From 5136aafcc2ed3d606dbec041713cc160002ec5d2 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Sep 2023 15:41:27 +0200 Subject: [PATCH 001/137] Add README.md --- src/tests/Interop/Swift/README.md | 176 ++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 src/tests/Interop/Swift/README.md diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md new file mode 100644 index 00000000000000..3e0443df13804d --- /dev/null +++ b/src/tests/Interop/Swift/README.md @@ -0,0 +1,176 @@ +# .NET Swift Interop + +Swift has a different ABI, runtime environment, and object model, making it non-trivial to call from the .NET runtime. Existing solutions like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet) rely on Swift /C# /C wrappers. + +This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. For a comprehensive .NET-Swift Interop, the Binding Tools for Swift contains valuable components that should either be reused or built upon. + +## Calling convention + +In Swift, functions parameters can be passed differently, either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. On a physical level, it's valuable to return common value types in registers instead of indirectly. The `self` parameter for both static and instance methods is always passed through a register since it's heavily used. Also, many methods call other methods on the same object, so it's best if the register storing `self` remains stable across different method signatures. Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Registers allocation: https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. + +Swift's default function types are `thick` meaning they have an optional context object implicitly passed when calling the function. It would be ideal to create a thick function from a thin one without introducing a thunk just to move parameters with the missing context parameter. + +## Name mangling + +Swift uses mangling for generating unique names. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. When calling in from .NET, it is necessary to mangle the name during the runtime or AOT compilation. + +## Memory management + +In Swift, memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). + +## Types and marshalling + +Interop should handle various types when calling from .NET, including blittable value types, non-blittable value types, tuples, classes/actors, existential containers, generic types, protocols with associated types, and closures. Enabling library evolution simplifies marshaling rules to some extent. For each entry point, the Swift compiler generates a thunk that is forward compatible. For instance, if you have an enum parameter that would typically fit into registers, the created thunk takes the value by reference rather than by value to account for potential changes in the enum's size. + +Reference: https://github.com/xamarin/binding-tools-for-swift/blob/main/docs/ValueTypeModeling.md + +## Flow for invoking a Swift function from .NET + +Here's the planned flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and demangled name: +1. A function name should be mangled during runtime or AOT compilation to resolve the entry point. This is necessary for Swift interop but not needed otherwise, as it may slow down the compiler. + - How to mangle name efficiently? + - How to detect the Swift Interop? +2. Function parameters should be automatically marshalled without any wrappers. + - Which types are not supported for automatic marshalling? +3. A thunk should be emitted to handle a different calling convention, especially for instance functions and for functions with error handling. + - Implement calling convention using thunks to handle errors, self, etc. +4. The result should be retrieved from the register or stack or indirectly. +5. Error registers should be checked and if set, an error should be thrown. +6. Cleanup may be required? + + +## Template + +Templates are used to define the definition of done (DoD) and contain of a set of unit tests that must be implemented. Each unit test is designed to cover a specific invocation type using different input types. The tests should be expanded with all Swift types. + +### Global/Static functions + +This is the simplest case that should be implemented. + +```swift +public static func add(_ a: Double, _ b: Double) -> Double { + return a + b +} + +public static func subtract(_ a: Double, _ b: Double) -> Double { + return a - b +} +``` + +### Function with default params + +Nice to have. When Swift compiles them it leaves the initialization expression behind for the compiler to consume later. It's effectively a weak macro that gets expanded later so that the compiler can potentially optimize it. + +```swift +public static func multiply(_ a: Double, _ b: Double = 1.0) -> Double { + return a * b +} +``` + +### Function with varargs + +Nice to have. The semantics for parameters being `f(name0: type0, name1: type1, name2: type2)`, Swift lets you do `f(a: Int..., b: Float..., c: String...)` which gets turned into `f(a: Int[], b: Float[], c: String[])` + +```swift +public static func average(numbers: Double...) -> Double { + let sum = numbers.reduce(0, +) + return sum / Double(numbers.count) +} +``` + +### Function with closures +```swift +public static func applyOperation(a: Double, b: Double, operation: (Double, Double) -> Double) -> Double { + return operation(a, b) +} +``` + +### Computed properties +```swift +public static var circleArea: (Double) -> Double = { radius in + return Double.pi * radius * radius +} +``` + +### Initializers/Deinitializers +```swift +public init(_internalValue: Int) { + self._internalValue = _internalValue + print("MathLibrary initialized.") +} + +deinit { + print("MathLibrary deinitialized.") +} +``` + +### Getters/Setters +```swift +private var _internalValue: Int = 0 + +public var value: Int { + get { + return _internalValue + } + set { + _internalValue = newValue + } +} +``` + +### Instance functions + +This case is important for handling self and errors via registers. + +```swift +public func factorial() -> Int { + guard _internalValue >= 0 else { + fatalError("Factorial is undefined for negative numbers") + } + return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() +} +``` + +### Delegates/Protocols +```swift +public protocol MathLibraryDelegate: AnyObject { + func mathLibraryDidInitialize() + func mathLibraryDidDeinitialize() +} +... +public weak var delegate: MathLibraryDelegate? + +public init(_internalValue: Int) { + self._internalValue = _internalValue + print("MathLibrary initialized.") + + // Notify the delegate that the library was initialized + delegate?.mathLibraryDidInitialize() +} + +deinit { + print("MathLibrary deinitialized.") + + // Notify the delegate that the library was deinitialized + delegate?.mathLibraryDidDeinitialize() +} +``` + +## Build steps + +Build the runtime: +```sh +./build.sh mono+libs +``` +Build the native library: +```sh +swiftc -emit-library ./src/tests/Interop/Swift/MathLibrary.swift -o ./src/tests/Interop/Swift/libMathLibrary.dylib +``` +Build the tests: +```sh +./src/tests/build.sh -mono osx arm64 Debug -test:Interop/Swift/SwiftInterop.csproj /p:LibrariesConfiguration=Debug +``` +Run the tests: +``` +sh +``` \ No newline at end of file From 9fc940272cf6bfafc19bbee359892c62f52cf504 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Sep 2023 17:12:28 +0200 Subject: [PATCH 002/137] Update build steps --- src/tests/Interop/Swift/README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 3e0443df13804d..c499357aaab1c1 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -34,6 +34,7 @@ Here's the planned flow for invoking a Swift function from .NET if a developer u - Which types are not supported for automatic marshalling? 3. A thunk should be emitted to handle a different calling convention, especially for instance functions and for functions with error handling. - Implement calling convention using thunks to handle errors, self, etc. + - Is it possible to test instance functions with P/Invoke or COM Interop is required? 4. The result should be retrieved from the register or stack or indirectly. 5. Error registers should be checked and if set, an error should be thrown. 6. Cleanup may be required? @@ -160,17 +161,21 @@ deinit { Build the runtime: ```sh -./build.sh mono+libs +./build.sh mono+libs+clr.hosts ``` -Build the native library: +Build the coreroot: ```sh -swiftc -emit-library ./src/tests/Interop/Swift/MathLibrary.swift -o ./src/tests/Interop/Swift/libMathLibrary.dylib +./src/tests/build.sh -mono debug generatelayoutonly /p:LibrariesConfiguration=Debug ``` Build the tests: ```sh -./src/tests/build.sh -mono osx arm64 Debug -test:Interop/Swift/SwiftInterop.csproj /p:LibrariesConfiguration=Debug +./src/tests/build.sh -mono Debug -test:Interop/Swift/SwiftInterop.csproj /p:LibrariesConfiguration=Debug +``` +Build the native library: +```sh +swiftc -emit-library ./src/tests/Interop/Swift/MathLibrary.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libMathLibrary.dylib ``` Run the tests: ``` -sh +bash $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/SwiftInterop.sh -coreroot=$PWD/artifacts/tests/coreclr/osx.arm64.Debug/Tests/Core_Root/ ``` \ No newline at end of file From d279a03132f14c750ff147458a6389523c5a39e2 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Sep 2023 17:12:47 +0200 Subject: [PATCH 003/137] Add experiment templates as unit tests --- src/tests/Interop/Swift/ClosureFunctions.cs | 27 +++++++ src/tests/Interop/Swift/DefaultParams.cs | 20 +++++ src/tests/Interop/Swift/GlobalFunctions.cs | 26 +++++++ src/tests/Interop/Swift/MathLibrary.swift | 81 +++++++++++++++++++++ src/tests/Interop/Swift/SwiftInterop.csproj | 14 ++++ src/tests/Interop/Swift/Varargs.cs | 21 ++++++ 6 files changed, 189 insertions(+) create mode 100644 src/tests/Interop/Swift/ClosureFunctions.cs create mode 100644 src/tests/Interop/Swift/DefaultParams.cs create mode 100644 src/tests/Interop/Swift/GlobalFunctions.cs create mode 100644 src/tests/Interop/Swift/MathLibrary.swift create mode 100644 src/tests/Interop/Swift/SwiftInterop.csproj create mode 100644 src/tests/Interop/Swift/Varargs.cs diff --git a/src/tests/Interop/Swift/ClosureFunctions.cs b/src/tests/Interop/Swift/ClosureFunctions.cs new file mode 100644 index 00000000000000..6ad7b64e7b3bb2 --- /dev/null +++ b/src/tests/Interop/Swift/ClosureFunctions.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +public class ClosureFunctionsTests +{ + public delegate double OperationDelegate(double a, double b); + + [DllImport("libMathLibrary.dylib", EntryPoint = "add")] + public static extern double add(double a, double b); + + [DllImport("libMathLibrary.dylib", EntryPoint = "applyOperation")] + public static extern double applyOperation(double a, double b, OperationDelegate operation); + + [Fact] + public static int TestEntryPoint() + { + OperationDelegate addDelegate = add; + + double result = 0.0; + result = applyOperation(5.0, 3.0, addDelegate); + Assert.Equal(8.0, result); + + return 100; + } +} diff --git a/src/tests/Interop/Swift/DefaultParams.cs b/src/tests/Interop/Swift/DefaultParams.cs new file mode 100644 index 00000000000000..4ec660abe59101 --- /dev/null +++ b/src/tests/Interop/Swift/DefaultParams.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +public class DefaultParamsTests +{ + [DllImport("libMathLibrary.dylib", EntryPoint = "multiply")] + public static extern double multiply(double a, double b = 1.0); + + [Fact] + public static int TestEntryPoint() + { + double result = 0.0; + result = multiply(5.0); + Assert.Equal(5.0, result); + + return 100; + } +} diff --git a/src/tests/Interop/Swift/GlobalFunctions.cs b/src/tests/Interop/Swift/GlobalFunctions.cs new file mode 100644 index 00000000000000..8ae52b3473f2d6 --- /dev/null +++ b/src/tests/Interop/Swift/GlobalFunctions.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +public class GlobalFunctionsTests +{ + [DllImport("libMathLibrary.dylib", EntryPoint = "add")] + public static extern double add(double a, double b); + + [DllImport("libMathLibrary.dylib", EntryPoint = "subtract")] + public static extern double subtract(double a, double b); + + [Fact] + public static int TestEntryPoint() + { + double result = 0.0; + result = add(5.0, 3.0); + Assert.Equal(8.0, result); + + result = subtract(5.0, 3.0); + Assert.Equal(2.0, result); + + return 100; + } +} diff --git a/src/tests/Interop/Swift/MathLibrary.swift b/src/tests/Interop/Swift/MathLibrary.swift new file mode 100644 index 00000000000000..52ba6466b3a383 --- /dev/null +++ b/src/tests/Interop/Swift/MathLibrary.swift @@ -0,0 +1,81 @@ +public protocol MathLibraryDelegate: AnyObject { + func mathLibraryDidInitialize() + func mathLibraryDidDeinitialize() +} + +public class MathLibrary { + // Global/Static functions + public static func add(_ a: Double, _ b: Double) -> Double { + return a + b + } + + public static func subtract(_ a: Double, _ b: Double) -> Double { + return a - b + } + + // Function with default params + public static func multiply(_ a: Double, _ b: Double = 1.0) -> Double { + return a * b + } + + // Function with varargs + public static func average(numbers: Double...) -> Double { + let sum = numbers.reduce(0, +) + return sum / Double(numbers.count) + } + + // Function with closures + public static func applyOperation(a: Double, b: Double, operation: (Double, Double) -> Double) -> Double { + return operation(a, b) + } + + // Computed property + public static var circleArea: (Double) -> Double = { radius in + return Double.pi * radius * radius + } + + public weak var delegate: MathLibraryDelegate? + + // Initializers/Deinitializers + public init(_internalValue: Int) { + self._internalValue = _internalValue + print("MathLibrary initialized.") + + // Notify the delegate that the library was initialized + delegate?.mathLibraryDidInitialize() + + } + + deinit { + print("MathLibrary deinitialized.") + + // Notify the delegate that the library was deinitialized + delegate?.mathLibraryDidDeinitialize() + } + + // Getters/Setters + private var _internalValue: Int = 0 + + public var value: Int { + get { + return _internalValue + } + set { + _internalValue = newValue + } + } + + public static let shared = MathLibrary() + + // Instance function + public func factorial() -> Int { + guard _internalValue >= 0 else { + fatalError("Factorial is undefined for negative numbers") + } + return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() + } + + public static func singleton () -> MathLibrary { + + } +} diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInterop.csproj new file mode 100644 index 00000000000000..7b381f9b920960 --- /dev/null +++ b/src/tests/Interop/Swift/SwiftInterop.csproj @@ -0,0 +1,14 @@ + + + Exe + true + + + + + + + + + + diff --git a/src/tests/Interop/Swift/Varargs.cs b/src/tests/Interop/Swift/Varargs.cs new file mode 100644 index 00000000000000..57613b4382adf6 --- /dev/null +++ b/src/tests/Interop/Swift/Varargs.cs @@ -0,0 +1,21 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +public class VarargsTests +{ + [DllImport("libMathLibrary.dylib", EntryPoint = "average")] + public static extern double average([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] numbers, int count); + + [Fact] + public static int TestEntryPoint() + { + double result = 0.0; + double[] numbers = { 1.0, 2.0, 3.0 }; + result = average(numbers, numbers.Length); + Assert.Equal(6.0, result); + + return 100; + } +} From de27030a23bc56efc1bec92c0578a1403b841191 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Sep 2023 17:16:00 +0200 Subject: [PATCH 004/137] Update README.md --- src/tests/Interop/Swift/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index c499357aaab1c1..d5a22bfe007cbe 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -42,7 +42,7 @@ Here's the planned flow for invoking a Swift function from .NET if a developer u ## Template -Templates are used to define the definition of done (DoD) and contain of a set of unit tests that must be implemented. Each unit test is designed to cover a specific invocation type using different input types. The tests should be expanded with all Swift types. +Templates are used to set the definition of done (DoD) and contain of a set of unit tests that must be implemented. Each unit test is designed to cover a specific invocation type using different input types. The tests should be expanded with all Swift types. ### Global/Static functions @@ -169,7 +169,7 @@ Build the coreroot: ``` Build the tests: ```sh -./src/tests/build.sh -mono Debug -test:Interop/Swift/SwiftInterop.csproj /p:LibrariesConfiguration=Debug +./src/tests/build.sh -mono debug -test:Interop/Swift/SwiftInterop.csproj /p:LibrariesConfiguration=Debug ``` Build the native library: ```sh From 476a605e90b3c2fbd23e1d7078ec838c598f2c82 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Sep 2023 17:22:08 +0200 Subject: [PATCH 005/137] Update README.md --- src/tests/Interop/Swift/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index d5a22bfe007cbe..4960c21750b2dd 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -42,7 +42,7 @@ Here's the planned flow for invoking a Swift function from .NET if a developer u ## Template -Templates are used to set the definition of done (DoD) and contain of a set of unit tests that must be implemented. Each unit test is designed to cover a specific invocation type using different input types. The tests should be expanded with all Swift types. +Template is used to set the definition of done (DoD) and contains of a set of unit tests that must be implemented. Each unit test is designed to cover a specific invocation type using different input types. The tests should be expanded with all Swift types. ### Global/Static functions From b1b69d3fdb21c565a21eafce498749b537b0cc27 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 14 Sep 2023 10:31:46 +0200 Subject: [PATCH 006/137] Update README.md --- src/tests/Interop/Swift/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 4960c21750b2dd..74964e1268e547 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -14,6 +14,8 @@ Swift's default function types are `thick` meaning they have an optional context Swift uses mangling for generating unique names. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. When calling in from .NET, it is necessary to mangle the name during the runtime or AOT compilation. +In order to simplify the testing we can use mangled name as the entry point. This provides a number of advantages, specifically for functions that have name overlap (i.e. functions with the same name that return different types) for which we cannot disambiguate from C#. The `Binding Tools for Swift` reads the dylib, pulls the public symbols and demangles them. + ## Memory management In Swift, memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). @@ -24,16 +26,15 @@ Interop should handle various types when calling from .NET, including blittable Reference: https://github.com/xamarin/binding-tools-for-swift/blob/main/docs/ValueTypeModeling.md +Initially, we should focus on blittable types. Later, we may introduce support for other non-blittable types. + ## Flow for invoking a Swift function from .NET Here's the planned flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and demangled name: -1. A function name should be mangled during runtime or AOT compilation to resolve the entry point. This is necessary for Swift interop but not needed otherwise, as it may slow down the compiler. - - How to mangle name efficiently? - - How to detect the Swift Interop? +1. A function name should be mangled using the `Binding Tools for Swift` due to limitations for functions that have name overlap. Alternative option is to mangle entry points during the runtime or AOT compilation. In this case, it may slow down the compiler for non-Swift interops and have limitations for functions that have name overlap. 2. Function parameters should be automatically marshalled without any wrappers. - - Which types are not supported for automatic marshalling? -3. A thunk should be emitted to handle a different calling convention, especially for instance functions and for functions with error handling. - - Implement calling convention using thunks to handle errors, self, etc. +3. A thunk should be emitted to handle the different calling convention, especially for instance functions and functions with error handling. + - Implement calling convention using thunks to handle self, errors, etc. - Is it possible to test instance functions with P/Invoke or COM Interop is required? 4. The result should be retrieved from the register or stack or indirectly. 5. Error registers should be checked and if set, an error should be thrown. From a95aca85d8c2fcf30d78430d6df1ba8335918a5b Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 14 Sep 2023 12:11:21 +0200 Subject: [PATCH 007/137] Update README.md --- src/tests/Interop/Swift/README.md | 40 +++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 74964e1268e547..4625c5b726d5e8 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -14,8 +14,6 @@ Swift's default function types are `thick` meaning they have an optional context Swift uses mangling for generating unique names. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. When calling in from .NET, it is necessary to mangle the name during the runtime or AOT compilation. -In order to simplify the testing we can use mangled name as the entry point. This provides a number of advantages, specifically for functions that have name overlap (i.e. functions with the same name that return different types) for which we cannot disambiguate from C#. The `Binding Tools for Swift` reads the dylib, pulls the public symbols and demangles them. - ## Memory management In Swift, memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). @@ -26,20 +24,36 @@ Interop should handle various types when calling from .NET, including blittable Reference: https://github.com/xamarin/binding-tools-for-swift/blob/main/docs/ValueTypeModeling.md -Initially, we should focus on blittable types. Later, we may introduce support for other non-blittable types. - -## Flow for invoking a Swift function from .NET +## An example of direct P/Invoke -Here's the planned flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and demangled name: -1. A function name should be mangled using the `Binding Tools for Swift` due to limitations for functions that have name overlap. Alternative option is to mangle entry points during the runtime or AOT compilation. In this case, it may slow down the compiler for non-Swift interops and have limitations for functions that have name overlap. +Here's the flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and demangled name: +1. An entry point name should be mangled using the `Binding Tools for Swift`. It creates function wrappers which could be invoked using demangled names. 2. Function parameters should be automatically marshalled without any wrappers. 3. A thunk should be emitted to handle the different calling convention, especially for instance functions and functions with error handling. - - Implement calling convention using thunks to handle self, errors, etc. - - Is it possible to test instance functions with P/Invoke or COM Interop is required? -4. The result should be retrieved from the register or stack or indirectly. -5. Error registers should be checked and if set, an error should be thrown. -6. Cleanup may be required? +4. The result should be retrieved from the register, stack, or indirectly. +5. An error should be thrown if an error register is set. +6. Cleanup may be required. + +## Tasks + +The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. Ideally, we want to eliminate extra wrappers. +Outcome of this experiment should be a document with limitations and list of tasks that needs to be done in order to officially support .NET Swift Interop. + +### Update Binding Tools for Swift to work with latest version of Mono runtime + +We should update the Binding Tools for Swift to be compatible with the latest version of the Mono runtime and Xcode. +### Name mangling + +In order to simplify the testing we can use mangled name as the entry point. This provides a number of advantages, specifically for functions that have name overlap (i.e. functions with the same name that return different types) for which we cannot disambiguate from C#. The `Binding Tools for Swift` reads the dylib, pulls the public symbols and demangles them. However, we should discover in which cases extra wrappers may not be required and possibility to perform entry point mangling within the runtime. In this case, it may slow down the compiler for non-Swift interops and have limitations for functions that have name overlap. + +### P/Invoke thunks + +The P/Invoke thunks should simplify register juggling by using predefined set of registers for `self` and `error` cases. We should explore possibilities and limitations of P/Invoke with instance functions. Additionally, we should consider using COM Interop for instance functions as well. + +## Type marshalling + +Type marshalling should ideally be automated, with an initial focus on supporting blittable types. Later, we can extend support to include non-blittable types. ## Template @@ -179,4 +193,4 @@ swiftc -emit-library ./src/tests/Interop/Swift/MathLibrary.swift -o $PWD/artifac Run the tests: ``` bash $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/SwiftInterop.sh -coreroot=$PWD/artifacts/tests/coreclr/osx.arm64.Debug/Tests/Core_Root/ -``` \ No newline at end of file +``` From 6c8e47743589003d260dedf6a2d7dc4a08129b9f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 14 Sep 2023 13:24:49 +0200 Subject: [PATCH 008/137] Update README.md --- src/tests/Interop/Swift/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 4625c5b726d5e8..baf00f4c1f51db 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -51,7 +51,7 @@ In order to simplify the testing we can use mangled name as the entry point. Thi The P/Invoke thunks should simplify register juggling by using predefined set of registers for `self` and `error` cases. We should explore possibilities and limitations of P/Invoke with instance functions. Additionally, we should consider using COM Interop for instance functions as well. -## Type marshalling +### Type marshalling Type marshalling should ideally be automated, with an initial focus on supporting blittable types. Later, we can extend support to include non-blittable types. From 7810e56c7270ebf59db057036fbab75d55c341b4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 19 Sep 2023 11:25:02 +0200 Subject: [PATCH 009/137] Fix the MathLibrary.swift --- src/tests/Interop/Swift/MathLibrary.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/tests/Interop/Swift/MathLibrary.swift b/src/tests/Interop/Swift/MathLibrary.swift index 52ba6466b3a383..e6c11d8ab0b39c 100644 --- a/src/tests/Interop/Swift/MathLibrary.swift +++ b/src/tests/Interop/Swift/MathLibrary.swift @@ -65,8 +65,6 @@ public class MathLibrary { } } - public static let shared = MathLibrary() - // Instance function public func factorial() -> Int { guard _internalValue >= 0 else { @@ -74,8 +72,4 @@ public class MathLibrary { } return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() } - - public static func singleton () -> MathLibrary { - - } } From 6d9d67f2be49d22e58a47612a13988219bb39c99 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 19 Sep 2023 15:34:21 +0200 Subject: [PATCH 010/137] Update README.md --- src/tests/Interop/Swift/README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index baf00f4c1f51db..fa813f733f831b 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -1,6 +1,6 @@ # .NET Swift Interop -Swift has a different ABI, runtime environment, and object model, making it non-trivial to call from the .NET runtime. Existing solutions like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet) rely on Swift /C# /C wrappers. +Swift has a different ABI, runtime environment, and object model, making it non-trivial to call from the .NET runtime. Existing solutions like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet) rely on Swift and C# binding wrappers. This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. For a comprehensive .NET-Swift Interop, the Binding Tools for Swift contains valuable components that should either be reused or built upon. @@ -24,6 +24,10 @@ Interop should handle various types when calling from .NET, including blittable Reference: https://github.com/xamarin/binding-tools-for-swift/blob/main/docs/ValueTypeModeling.md +## Interop on LLVM IR level + +The Swift compiler uses an LLVM backend, which can be linked with Mono LLVM bitcode files (.bc). + ## An example of direct P/Invoke Here's the flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and demangled name: @@ -45,11 +49,11 @@ We should update the Binding Tools for Swift to be compatible with the latest ve ### Name mangling -In order to simplify the testing we can use mangled name as the entry point. This provides a number of advantages, specifically for functions that have name overlap (i.e. functions with the same name that return different types) for which we cannot disambiguate from C#. The `Binding Tools for Swift` reads the dylib, pulls the public symbols and demangles them. However, we should discover in which cases extra wrappers may not be required and possibility to perform entry point mangling within the runtime. In this case, it may slow down the compiler for non-Swift interops and have limitations for functions that have name overlap. +In order to simplify the testing we can use mangled name as the entry point. This provides a number of advantages, specifically for functions that have name overlap (i.e. functions with the same name that return different types) for which we cannot disambiguate from C#. The `Binding Tools for Swift` reads the dylib, pulls the public symbols and demangles them. However, we should discover the possibility to perform entry point name mangling within the runtime. In this case, it may slow down the compiler for non-Swift interops and have limitations for functions that have name overlap. ### P/Invoke thunks -The P/Invoke thunks should simplify register juggling by using predefined set of registers for `self` and `error` cases. We should explore possibilities and limitations of P/Invoke with instance functions. Additionally, we should consider using COM Interop for instance functions as well. +The P/Invoke thunks should simplify register juggling by using predefined set of registers for `self` and `error` cases. We should explore possibilities and limitations of P/Invoke with instance functions. ### Type marshalling From 87adeed9e245026c783c2edd6562987ef247d6c9 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 20 Sep 2023 18:30:33 +0200 Subject: [PATCH 011/137] Update README.md --- src/tests/Interop/Swift/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index fa813f733f831b..381bf24da94ada 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -6,7 +6,7 @@ This project aims to explore the possibilities and limitations of direct P/Invok ## Calling convention -In Swift, functions parameters can be passed differently, either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. On a physical level, it's valuable to return common value types in registers instead of indirectly. The `self` parameter for both static and instance methods is always passed through a register since it's heavily used. Also, many methods call other methods on the same object, so it's best if the register storing `self` remains stable across different method signatures. Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Registers allocation: https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. +In Swift, functions parameters can be passed differently, either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. On a physical level, it's valuable to return common value types in registers instead of indirectly. The `self` parameter for instance methods is always passed through a register since it's heavily used. Also, many methods call other methods on the same object, so it's best if the register storing `self` remains stable across different method signatures. Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Registers allocation: https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. Swift's default function types are `thick` meaning they have an optional context object implicitly passed when calling the function. It would be ideal to create a thick function from a thin one without introducing a thunk just to move parameters with the missing context parameter. From 0716fda3d958f07d89607970821aaa3cad252d05 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 21 Sep 2023 15:16:00 +0200 Subject: [PATCH 012/137] Add Swift ABI details --- src/tests/Interop/Swift/README.md | 90 ++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index fa813f733f831b..972f668d0536ed 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -1,47 +1,87 @@ # .NET Swift Interop -Swift has a different ABI, runtime environment, and object model, making it non-trivial to call from the .NET runtime. Existing solutions like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet) rely on Swift and C# binding wrappers. +The Swift programming language has a different ABI, runtime environment, and object model, making it challenging to call from the .NET runtime. Existing solutions, like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet). -This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. For a comprehensive .NET-Swift Interop, the Binding Tools for Swift contains valuable components that should either be reused or built upon. +This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. For a comprehensive .NET Swift interop, the Binding Tools for Swift contains valuable components that could be reused or built upon. -## Calling convention +We want to focus on the runtime support for direct P/Invoke interop with Swift, which Xamarin bindings will consume to support running Maui apps with third-party Swift libraries. Ideally, we want to avoid generating extra wrappers and attempt to directly call all kinds of Swift functions. While external tools can be helpful, they may introduce additional complexity, and we intend to integrate them into the .NET toolchain ecosystem. -In Swift, functions parameters can be passed differently, either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. On a physical level, it's valuable to return common value types in registers instead of indirectly. The `self` parameter for both static and instance methods is always passed through a register since it's heavily used. Also, many methods call other methods on the same object, so it's best if the register storing `self` remains stable across different method signatures. Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Registers allocation: https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. +## Swift ABI in a nutshell -Swift's default function types are `thick` meaning they have an optional context object implicitly passed when calling the function. It would be ideal to create a thick function from a thin one without introducing a thunk just to move parameters with the missing context parameter. +The Swift ABI specifies how to call functions and how their data and metadata are represented in memory. Here are important components of the ABI that we need to consider. -## Name mangling +### Type layout -Swift uses mangling for generating unique names. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. When calling in from .NET, it is necessary to mangle the name during the runtime or AOT compilation. +The types we want to support are: blittable value types, non-blittable value types, tuples, classes/actors, existential containers, generics types, protocols with associated types, and closures. Objects of types are stored in registers or memory. A data member of an object is any value that requires layout within the object itself. Data members include an object's stored properties and associated values. A layout for static types is determined during the compilation, while the layout for opaque types is not determined until the runtime. For each type the alignment, size, and offset are calculated. -## Memory management -In Swift, memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). +Enabling library evolution simplifies marshaling rules to some extent. For each entry point, the Swift compiler generates a thunk that is forward compatible. For instance, if there is an enum parameter that would typically fit into registers, the created thunk takes the value by reference rather than by value to account for potential changes in the enum's size. Additionally, there are some edge cases where Swift compiler tries to optimize structs by allocating spare bits from the alignment. -## Types and marshalling +Memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). -Interop should handle various types when calling from .NET, including blittable value types, non-blittable value types, tuples, classes/actors, existential containers, generic types, protocols with associated types, and closures. Enabling library evolution simplifies marshaling rules to some extent. For each entry point, the Swift compiler generates a thunk that is forward compatible. For instance, if you have an enum parameter that would typically fit into registers, the created thunk takes the value by reference rather than by value to account for potential changes in the enum's size. +### Type metadata -Reference: https://github.com/xamarin/binding-tools-for-swift/blob/main/docs/ValueTypeModeling.md +The Swift runtime keeps a metadata record for every type used in a program, including every instantiation of generic types. They can be used for class methods, reflection and debugger tools. The metadata layout consists of common properties and type-specific metadata. Common properties are value witness table pointer and kind. The value witness table references a vtable of functions that implement the value semantics of the type (alloc, copy, destroy, move). Additionally, it contains size, alignment, and type. The value witness table pointer is at`offset -1` from the metadata pointer, that is, the pointer-sized word immediately before the pointer's referenced address. This field is at offset 0 from the metadata pointer. -## Interop on LLVM IR level +### Name mangling -The Swift compiler uses an LLVM backend, which can be linked with Mono LLVM bitcode files (.bc). +Swift uses mangling for generating unique names in a binary. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. -## An example of direct P/Invoke +Be aware of the edge cases that can't be mapped 1:1 in C#. Consider the following example in Swift: +```swift +public static func getValue() -> Double { + return 5.0 +} + +public static func getValue() -> Int { + return 5 +} +``` + +The Swift compiler generates the following mangled names for the functions: +``` +_$s11MathLibraryAAC8getValueSdyFZ ---> static MathLibrary.MathLibrary.getValue() -> Swift.Double +_$s11MathLibraryAAC8getValueSiyFZ ---> static MathLibrary.MathLibrary.getValue() -> Swift.Int +``` + +In such case, generating entry points automatically from the C# would be problematic because both methods have the same name and parameter list, but different return types. According to the C# documentation, a return type of a method is not part of the signature of the method for the purposes of method overloading. + +https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods#method-signatures + +The Binding Tools for Swift resolves that by reading the native library, extracting the public symbols, and demangling them. On the runtime level the user is supposed to provide the mangled name as the entry point. + +### Calling convention -Here's the flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and demangled name: -1. An entry point name should be mangled using the `Binding Tools for Swift`. It creates function wrappers which could be invoked using demangled names. -2. Function parameters should be automatically marshalled without any wrappers. -3. A thunk should be emitted to handle the different calling convention, especially for instance functions and functions with error handling. -4. The result should be retrieved from the register, stack, or indirectly. -5. An error should be thrown if an error register is set. -6. Cleanup may be required. +In Swift programming language, functions parameters can be passed either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. -## Tasks +According to the calling convention, the `self`` context has dedicated registers, and it is always passed through them since it's heavily used. Methods calling other methods on the same object can share the self context. + +Here are cases when `self` context is passed via register: + - Instance methods on class types: pointer to self + - Class methods: pointer to type metadata (which may be subclass metadata) + - Mutating method on value types: pointer to the value (i.e. value is passed indirectly) + - Non-mutating methods on value types: self may fit in one or more registers, else passed indirectly + - Thick closures, i.e. closures requiring a context: the closure context + +Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Similarly, the calling convention allows a function to return value types that are not opaque through a combination of registers if those values fit within the size and alignment constraints of the register. More details available at https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. + +## An example of direct P/Invoke -The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. Ideally, we want to eliminate extra wrappers. -Outcome of this experiment should be a document with limitations and list of tasks that needs to be done in order to officially support .NET Swift Interop. +Here's the flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and mangled names: +1. Function parameters should be automatically marshalled without any wrappers +2. A thunk should be emitted to handle the `self` and `error` registers +3. The result should be retrieved from the register, stack, or indirectly +4. An error should be thrown if the `error` register is set +5. Cleanup may be required + +## Goals + +The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. +The goals below are **outdated** and should be updated. Here is list of goals we want to focus on: + - Type marshalling + - Swift metadata marshalling + - Thunks for `self` context + - Thunks for `error` handling ### Update Binding Tools for Swift to work with latest version of Mono runtime From 675619f52ec470b5a97667d448b6c429ce7475a6 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 21 Sep 2023 15:18:33 +0200 Subject: [PATCH 013/137] Update README.md --- src/tests/Interop/Swift/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 972f668d0536ed..773c191a069a05 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -76,13 +76,14 @@ Here's the flow for invoking a Swift function from .NET if a developer uses a di ## Goals -The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. -The goals below are **outdated** and should be updated. Here is list of goals we want to focus on: +The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. Here is list of goals we want to focus on: - Type marshalling - Swift metadata marshalling - Thunks for `self` context - Thunks for `error` handling +## The goals below are outdated and should be updated + ### Update Binding Tools for Swift to work with latest version of Mono runtime We should update the Binding Tools for Swift to be compatible with the latest version of the Mono runtime and Xcode. From 24a8a01779763c57c98013e313fb7ce1ba1799f9 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 21 Sep 2023 18:09:30 +0200 Subject: [PATCH 014/137] Add tasks to the README.md --- src/tests/Interop/Swift/README.md | 105 ++++++++++++++---------------- 1 file changed, 49 insertions(+), 56 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 773c191a069a05..3abca24e5a9ae5 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -14,7 +14,6 @@ The Swift ABI specifies how to call functions and how their data and metadata ar The types we want to support are: blittable value types, non-blittable value types, tuples, classes/actors, existential containers, generics types, protocols with associated types, and closures. Objects of types are stored in registers or memory. A data member of an object is any value that requires layout within the object itself. Data members include an object's stored properties and associated values. A layout for static types is determined during the compilation, while the layout for opaque types is not determined until the runtime. For each type the alignment, size, and offset are calculated. - Enabling library evolution simplifies marshaling rules to some extent. For each entry point, the Swift compiler generates a thunk that is forward compatible. For instance, if there is an enum parameter that would typically fit into registers, the created thunk takes the value by reference rather than by value to account for potential changes in the enum's size. Additionally, there are some edge cases where Swift compiler tries to optimize structs by allocating spare bits from the alignment. Memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). @@ -23,6 +22,21 @@ Memory management is handled by [Automatic Reference Counting](https://docs.swif The Swift runtime keeps a metadata record for every type used in a program, including every instantiation of generic types. They can be used for class methods, reflection and debugger tools. The metadata layout consists of common properties and type-specific metadata. Common properties are value witness table pointer and kind. The value witness table references a vtable of functions that implement the value semantics of the type (alloc, copy, destroy, move). Additionally, it contains size, alignment, and type. The value witness table pointer is at`offset -1` from the metadata pointer, that is, the pointer-sized word immediately before the pointer's referenced address. This field is at offset 0 from the metadata pointer. +### Calling convention + +In Swift programming language, functions parameters can be passed either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. + +According to the calling convention, the `self`` context has dedicated registers, and it is always passed through them since it's heavily used. Methods calling other methods on the same object can share the self context. + +Here are cases when `self` context is passed via register: + - Instance methods on class types: pointer to self + - Class methods: pointer to type metadata (which may be subclass metadata) + - Mutating method on value types: pointer to the value (i.e. value is passed indirectly) + - Non-mutating methods on value types: self may fit in one or more registers, else passed indirectly + - Thick closures, i.e. closures requiring a context: the closure context + +Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Similarly, the calling convention allows a function to return value types that are not opaque through a combination of registers if those values fit within the size and alignment constraints of the register. More details available at https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. + ### Name mangling Swift uses mangling for generating unique names in a binary. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. @@ -50,22 +64,15 @@ https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-st The Binding Tools for Swift resolves that by reading the native library, extracting the public symbols, and demangling them. On the runtime level the user is supposed to provide the mangled name as the entry point. -### Calling convention - -In Swift programming language, functions parameters can be passed either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. +## Goals -According to the calling convention, the `self`` context has dedicated registers, and it is always passed through them since it's heavily used. Methods calling other methods on the same object can share the self context. +The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. In this phase of the experiment, we want to implement on marshalling of blittable types and handling `self` context and `error` handling on Mono AOT targeting MacCatalyst. -Here are cases when `self` context is passed via register: - - Instance methods on class types: pointer to self - - Class methods: pointer to type metadata (which may be subclass metadata) - - Mutating method on value types: pointer to the value (i.e. value is passed indirectly) - - Non-mutating methods on value types: self may fit in one or more registers, else passed indirectly - - Thick closures, i.e. closures requiring a context: the closure context +We can choose to first support Mono AOT either with or without LLVM according to the initial analysis. -Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Similarly, the calling convention allows a function to return value types that are not opaque through a combination of registers if those values fit within the size and alignment constraints of the register. More details available at https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. +## Tasks -## An example of direct P/Invoke +Templates are used to set the definition of done (DoD) and contains of a set of unit tests that will be be implemented. Each unit test is designed to cover a specific invocation type using different input types. In the first iteration of the experiment, we want to focus on blittable types targeting MacCatalyst only. Later, we plan to include support for non-blittable types and other Apple targets. Here's the flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and mangled names: 1. Function parameters should be automatically marshalled without any wrappers @@ -74,39 +81,15 @@ Here's the flow for invoking a Swift function from .NET if a developer uses a di 4. An error should be thrown if the `error` register is set 5. Cleanup may be required -## Goals - -The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. Here is list of goals we want to focus on: - - Type marshalling - - Swift metadata marshalling - - Thunks for `self` context - - Thunks for `error` handling - -## The goals below are outdated and should be updated - -### Update Binding Tools for Swift to work with latest version of Mono runtime - -We should update the Binding Tools for Swift to be compatible with the latest version of the Mono runtime and Xcode. - -### Name mangling - -In order to simplify the testing we can use mangled name as the entry point. This provides a number of advantages, specifically for functions that have name overlap (i.e. functions with the same name that return different types) for which we cannot disambiguate from C#. The `Binding Tools for Swift` reads the dylib, pulls the public symbols and demangles them. However, we should discover the possibility to perform entry point name mangling within the runtime. In this case, it may slow down the compiler for non-Swift interops and have limitations for functions that have name overlap. - -### P/Invoke thunks - -The P/Invoke thunks should simplify register juggling by using predefined set of registers for `self` and `error` cases. We should explore possibilities and limitations of P/Invoke with instance functions. - -### Type marshalling +### Type marshalling and metadata conversions -Type marshalling should ideally be automated, with an initial focus on supporting blittable types. Later, we can extend support to include non-blittable types. +Type marshalling should ideally be automated, with an initial focus on supporting blittable types. Later, we can extend support to include non-blittable types. Here are some tasks (not a full list): + - Create a mapping between C# and Swift types + - Investigate and determine which types lack marshalling support + - Investigate and determine how to generate types metadata -## Template -Template is used to set the definition of done (DoD) and contains of a set of unit tests that must be implemented. Each unit test is designed to cover a specific invocation type using different input types. The tests should be expanded with all Swift types. - -### Global/Static functions - -This is the simplest case that should be implemented. +This is the simplest case that should be implemented. It should be expanded with other types. ```swift public static func add(_ a: Double, _ b: Double) -> Double { @@ -118,6 +101,29 @@ public static func subtract(_ a: Double, _ b: Double) -> Double { } ``` +### Self context + +In order to support Swift calling convention, it is necessary to implement register handling by emitting thunks in the above-mentioned cases. + +```swift +public func factorial() -> Int { + guard _internalValue >= 0 else { + fatalError("Factorial is undefined for negative numbers") + } + return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() +} +``` + +### Error handling + +In order to support Swift calling convention, it is necessary to implement error handling by emitting thunks in the above-mentioned cases. + +### Update Binding Tools for Swift to work with latest version of Mono runtime + +We should update the Binding Tools for Swift to be compatible with the latest version of the Mono runtime and Xcode. + +## Other examples + ### Function with default params Nice to have. When Swift compiles them it leaves the initialization expression behind for the compiler to consume later. It's effectively a weak macro that gets expanded later so that the compiler can potentially optimize it. @@ -179,19 +185,6 @@ public var value: Int { } ``` -### Instance functions - -This case is important for handling self and errors via registers. - -```swift -public func factorial() -> Int { - guard _internalValue >= 0 else { - fatalError("Factorial is undefined for negative numbers") - } - return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() -} -``` - ### Delegates/Protocols ```swift public protocol MathLibraryDelegate: AnyObject { From 11d60ccd2f56465b7f70acbe4abcf87c3c776584 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 21 Sep 2023 18:09:56 +0200 Subject: [PATCH 015/137] Script that exports and demangles Swift symbols --- src/tests/Interop/Swift/demangle_symbols.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 src/tests/Interop/Swift/demangle_symbols.sh diff --git a/src/tests/Interop/Swift/demangle_symbols.sh b/src/tests/Interop/Swift/demangle_symbols.sh new file mode 100755 index 00000000000000..549c0c662fa9c8 --- /dev/null +++ b/src/tests/Interop/Swift/demangle_symbols.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Get symbols using nm +nm $1 > symbols.txt + +# Strip _$ and demangle +cat symbols.txt | awk '{print $3}' | sed 's/_$//g' | xargs -I {} xcrun swift-demangle {} > demangled_symbols.txt + +echo "Demangled symbols are exported to demangled_symbols.txt." \ No newline at end of file From e8169f0e898fd7c74e43d81f4abb3a0dea1098d3 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 21 Sep 2023 22:13:27 +0200 Subject: [PATCH 016/137] Update README.md --- src/tests/Interop/Swift/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 3abca24e5a9ae5..3adb77a3e8df93 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -66,7 +66,7 @@ The Binding Tools for Swift resolves that by reading the native library, extract ## Goals -The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. In this phase of the experiment, we want to implement on marshalling of blittable types and handling `self` context and `error` handling on Mono AOT targeting MacCatalyst. +The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. In the first iteration of the experiment, our focus will be on the self context and error handling calling conventions with blittable types targeting MacCatalyst. After that, we plan to expand support for non-blittable types using binding wrappers and to include other Apple targets. We can choose to first support Mono AOT either with or without LLVM according to the initial analysis. From 279a59441f8acce66b198abf3a68874e21ab413d Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 12 Oct 2023 10:28:08 +0200 Subject: [PATCH 017/137] Add custom attributes for Swift calling convention --- .../System.Private.CoreLib.Shared.projitems | 1 + .../CompilerServices/CallingConventions.cs | 4 ++++ .../SwiftErrorReturnAttribute.cs | 19 +++++++++++++++++++ .../InteropServices/CallingConvention.cs | 1 + .../System.Runtime/ref/System.Runtime.cs | 10 ++++++++++ .../Reflection/RuntimeMethodInfo.Mono.cs | 3 +++ src/mono/mono/metadata/loader.c | 3 +++ src/mono/mono/metadata/marshal.c | 4 ++++ src/mono/mono/metadata/metadata.c | 6 ++++++ src/mono/mono/metadata/tabledefs.h | 1 + 10 files changed, 52 insertions(+) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 2b774a2f4fd550..4d9f5a8adecbe6 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -841,6 +841,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs index e4870a1fcc4d64..88fe4693bf7f40 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs @@ -15,6 +15,10 @@ public class CallConvStdcall { public CallConvStdcall() { } } + public class CallConvSwift + { + public CallConvSwift() { } + } /// /// Indicates that a method should suppress the GC transition as part of the calling convention. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs new file mode 100644 index 00000000000000..6b81c249483712 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + /// + /// Indicates that the parameter contains Swift error handler. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] + public sealed class SwiftErrorReturnAttribute : Attribute + { + public SwiftErrorReturnAttribute() + { + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs index 88465296ced546..7244bebad7087f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs @@ -11,5 +11,6 @@ public enum CallingConvention StdCall = 3, ThisCall = 4, FastCall = 5, + SwiftCall = 6, } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 2c522cb01bdb5d..6e4a84ceff8cfa 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -12600,6 +12600,10 @@ public partial class CallConvThiscall { public CallConvThiscall() { } } + public partial class CallConvSwift + { + public CallConvSwift() { } + } [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple=false, Inherited=false)] public sealed partial class CallerArgumentExpressionAttribute : System.Attribute { @@ -12896,6 +12900,12 @@ public sealed partial class InlineArrayAttribute : System.Attribute public InlineArrayAttribute(int length) { } public int Length { get { throw null; } } } + [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false)] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed partial class SwiftErrorReturnAttribute : System.Attribute + { + public SwiftErrorReturnAttribute() { } + } [System.AttributeUsageAttribute(System.AttributeTargets.Struct)] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public sealed partial class IsByRefLikeAttribute : System.Attribute diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs index 7cbf84f2196f10..2c42fa802f9ceb 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs @@ -69,6 +69,7 @@ internal enum PInvokeAttributes CallConvStdcall = 0x0300, CallConvThiscall = 0x0400, CallConvFastcall = 0x0500, + CallConvSwift = 0x0600, MaxValue = 0xFFFF, } @@ -502,6 +503,7 @@ private DllImportAttribute GetDllImportAttribute() case PInvokeAttributes.CallConvStdcall: callingConvention = InteropServicesCallingConvention.StdCall; break; case PInvokeAttributes.CallConvThiscall: callingConvention = InteropServicesCallingConvention.ThisCall; break; case PInvokeAttributes.CallConvFastcall: callingConvention = InteropServicesCallingConvention.FastCall; break; + case PInvokeAttributes.CallConvSwift: callingConvention = InteropServicesCallingConvention.SwiftCall; break; // Invalid: default to CallingConvention.Cdecl default: break; @@ -579,6 +581,7 @@ private DllImportAttribute GetDllImportAttribute() PInvokeAttributes.CallConvStdcall => InteropServicesCallingConvention.StdCall, PInvokeAttributes.CallConvThiscall => InteropServicesCallingConvention.ThisCall, PInvokeAttributes.CallConvFastcall => InteropServicesCallingConvention.FastCall, + PInvokeAttributes.CallConvSwift => InteropServicesCallingConvention.SwiftCall, // Invalid: default to CallingConvention.Cdecl _ => InteropServicesCallingConvention.Cdecl, }; diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index 5f21d3371c3c1f..8433d6709a8ab6 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -1907,6 +1907,9 @@ mono_method_signature_checked_slow (MonoMethod *m, MonoError *error) case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL: conv = MONO_CALL_FASTCALL; break; + case PINVOKE_ATTRIBUTE_CALL_CONV_SWIFTCALL: + conv = MONO_CALL_SWIFTCALL; + break; case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC: case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST: default: { diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 02309b933f1607..9ef9b4e5b3c34f 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3232,6 +3232,8 @@ mono_marshal_set_callconv_for_type(MonoType *type, MonoMethodSignature *csig, gb csig->call_convention = MONO_CALL_FASTCALL; else if (!strcmp (class_name, "CallConvThiscall")) csig->call_convention = MONO_CALL_THISCALL; + else if (!strcmp (class_name, "CallConvSwift")) + csig->call_convention = MONO_CALL_SWIFTCALL; else if (!strcmp (class_name, "CallConvSuppressGCTransition") && skip_gc_trans != NULL) *skip_gc_trans = TRUE; } @@ -3356,6 +3358,8 @@ mono_marshal_set_signature_callconv_from_attribute(MonoMethodSignature *sig, Mon sig->call_convention = MONO_CALL_STDCALL; else if (!strcmp (name, "Thiscall")) sig->call_convention = MONO_CALL_THISCALL; + else if (!strcmp (name, "Swift")) + sig->call_convention = MONO_CALL_SWIFTCALL; else if (!strcmp (name, "Fastcall")) sig->call_convention = MONO_CALL_FASTCALL; else if (!strcmp (name, "SuppressGCTransition")) diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 9b64083fdfd794..3899d28fd148c9 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -2604,6 +2604,9 @@ metadata_signature_set_modopt_call_conv (MonoMethodSignature *sig, MonoType *cmo } else if (!strcmp (name, "Fastcall")) { base_callconv = MONO_CALL_FASTCALL; continue; + } else if (!strcmp (name, "Swift")) { + base_callconv = MONO_CALL_SWIFTCALL; + continue; } /* Check for known calling convention modifiers */ @@ -2676,6 +2679,7 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c case MONO_CALL_STDCALL: case MONO_CALL_THISCALL: case MONO_CALL_FASTCALL: + case MONO_CALL_SWIFTCALL: case MONO_CALL_UNMANAGED_MD: method->pinvoke = 1; break; @@ -5718,6 +5722,7 @@ mono_metadata_check_call_convention_category (unsigned int call_convention) case MONO_CALL_STDCALL: case MONO_CALL_THISCALL: case MONO_CALL_FASTCALL: + case MONO_CALL_SWIFTCALL: case MONO_CALL_UNMANAGED_MD: return 2; case MONO_CALL_VARARG: @@ -8129,6 +8134,7 @@ mono_guid_signature_append_method (GString *res, MonoMethodSignature *sig) case MONO_CALL_STDCALL: g_string_append (res, "unmanaged stdcall "); break; case MONO_CALL_THISCALL: g_string_append (res, "unmanaged thiscall "); break; case MONO_CALL_FASTCALL: g_string_append (res, "unmanaged fastcall "); break; + case MONO_CALL_SWIFTCALL: g_string_append (res, "unmanaged swiftcall "); break; case MONO_CALL_VARARG: g_string_append (res, "vararg "); break; default: break; } diff --git a/src/mono/mono/metadata/tabledefs.h b/src/mono/mono/metadata/tabledefs.h index 52521435fc3b55..1369fd0bfb5625 100644 --- a/src/mono/mono/metadata/tabledefs.h +++ b/src/mono/mono/metadata/tabledefs.h @@ -251,6 +251,7 @@ enum { #define PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL 0x0300 #define PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL 0x0400 #define PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL 0x0500 +#define PINVOKE_ATTRIBUTE_CALL_CONV_SWIFTCALL 0x0600 #define PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_ENABLED 0x1000 #define PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_DISABLED 0x2000 #define PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_MASK 0x3000 From acc15a08f00082bb427bddf8f30eae2cf074e4bf Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 12 Oct 2023 11:40:12 +0200 Subject: [PATCH 018/137] Add runtime support for Swift error handling --- src/mono/mono/mini/mini-amd64-gsharedvt.c | 1 + src/mono/mono/mini/mini-arm64.c | 23 +++++++++++++++++++ src/mono/mono/mini/mini-arm64.h | 2 ++ .../mono/metadata/details/metadata-types.h | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-amd64-gsharedvt.c b/src/mono/mono/mini/mini-amd64-gsharedvt.c index 0aa2f1559006b3..64956eb34864ec 100644 --- a/src/mono/mono/mini/mini-amd64-gsharedvt.c +++ b/src/mono/mono/mini/mini-amd64-gsharedvt.c @@ -49,6 +49,7 @@ storage_name (ArgStorage st) case ArgValuetypeAddrOnStack: return "ArgValuetypeAddrOnStack"; case ArgGSharedVtInReg: return "ArgGSharedVtInReg"; case ArgGSharedVtOnStack: return "ArgGSharedVtOnStack"; + case ArgSwiftError: return "ArgSwiftError"; case ArgNone: return "ArgNone"; default: return "unknown"; } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 2fac9738f61c25..c5bd8435616eb8 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1796,6 +1796,11 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) add_param (cinfo, &cinfo->sig_cookie, mono_get_int_type (), FALSE); } + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + // Assume that the first argument is SwiftError + cinfo->args[0].storage = ArgSwiftError; + } + cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT); return cinfo; @@ -2594,6 +2599,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: + case ArgSwiftError: cfg->ret->opcode = OP_REGVAR; cfg->ret->dreg = cinfo->ret.reg; break; @@ -2648,6 +2654,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: + case ArgSwiftError: // FIXME: Use nregs/size /* These will be copied to the stack in the prolog */ ins->inst_offset = offset; @@ -3071,6 +3078,14 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) MONO_ADD_INS (cfg->cbb, ins); break; } + case ArgSwiftError: { + // Create an extra variable and save call->args[0]->dreg + MonoInst *ins; + ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); + ins->backend.data = GUINT_TO_POINTER (call->args[0]->dreg); + cfg->arch.interop_var = ins; + break; + } default: g_assert_not_reached (); break; @@ -3586,6 +3601,13 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) g_assert_not_reached (); break; } + + // Move value from R21 to the arg dreg + if (call->signature->call_convention == MONO_CALL_SWIFTCALL) { + gint32 error_dreg = GPOINTER_TO_INT32 (cfg->arch.interop_var->backend.data); + arm_movx (code, error_dreg, ARMREG_R21); + } + return code; } @@ -5665,6 +5687,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) switch (ainfo->storage) { case ArgInIReg: + case ArgSwiftError: /* Stack slots for arguments have size 8 */ code = emit_strx (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); if (i == 0 && sig->hasthis) { diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index da21523af81ddf..f87bbf061c4117 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -119,6 +119,7 @@ typedef struct { MonoInst *seq_point_info_var; MonoInst *ss_tramp_var; MonoInst *bp_tramp_var; + MonoInst *interop_var; guint8 *thunks; int thunks_size; } MonoCompileArch; @@ -233,6 +234,7 @@ typedef enum { ArgVtypeByRefOnStack, ArgVtypeOnStack, ArgHFA, + ArgSwiftError, ArgNone } ArgStorage; diff --git a/src/native/public/mono/metadata/details/metadata-types.h b/src/native/public/mono/metadata/details/metadata-types.h index 7ae6ab2d3d95da..ed1d1ad0e3825c 100644 --- a/src/native/public/mono/metadata/details/metadata-types.h +++ b/src/native/public/mono/metadata/details/metadata-types.h @@ -29,7 +29,7 @@ typedef enum { MONO_CALL_THISCALL, MONO_CALL_FASTCALL, MONO_CALL_VARARG = 0x05, - /* unused, */ + MONO_CALL_SWIFTCALL = 0x06, /* unused, */ /* unused, */ MONO_CALL_UNMANAGED_MD = 0x09, /* default unmanaged calling convention, with additional attributed encoded in modopts */ From 5ea875550a6f758f298d1fdeab1b3bf053bb4fd4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 12 Oct 2023 11:40:41 +0200 Subject: [PATCH 019/137] Add sample test --- src/tests/Interop/Swift/ErrorHandling.cs | 25 +++++++++++++++++++++ src/tests/Interop/Swift/ErrorHandling.swift | 9 ++++++++ src/tests/Interop/Swift/README.md | 1 + src/tests/Interop/Swift/SwiftInterop.csproj | 6 ++--- 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 src/tests/Interop/Swift/ErrorHandling.cs create mode 100644 src/tests/Interop/Swift/ErrorHandling.swift diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/ErrorHandling.cs new file mode 100644 index 00000000000000..b200231bc52198 --- /dev/null +++ b/src/tests/Interop/Swift/ErrorHandling.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +public class GlobalFunctionsTests +{ + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrowSiyKF")] + public static extern nint SomeFuncThatMightThrow ([SwiftErrorReturn]ref IntPtr error); + + [Fact] + public static int TestEntryPoint() + { + IntPtr errorHandle = IntPtr.Zero; + nint result = SomeFuncThatMightThrow(ref errorHandle); + Console.WriteLine(result); + if (errorHandle != IntPtr.Zero) { + return 100; + } else { + Console.WriteLine(errorHandle); + return 101; + } + } +} diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift new file mode 100644 index 00000000000000..13e8549c82c9e3 --- /dev/null +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -0,0 +1,9 @@ +enum MyError: Error { + case runtimeError(String) +} + +public func someFuncThatMightThrow () throws -> Int { + print("Hello from Swift"); + throw MyError.runtimeError ("Catch me if you can"); + return 42; +} \ No newline at end of file diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 3adb77a3e8df93..560d49c9645660 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -227,6 +227,7 @@ Build the tests: Build the native library: ```sh swiftc -emit-library ./src/tests/Interop/Swift/MathLibrary.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libMathLibrary.dylib +swiftc -emit-library ./src/tests/Interop/Swift/ErrorHandling.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libErrorHandling.dylib ``` Run the tests: ``` diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInterop.csproj index 7b381f9b920960..5cbb62535e4e8a 100644 --- a/src/tests/Interop/Swift/SwiftInterop.csproj +++ b/src/tests/Interop/Swift/SwiftInterop.csproj @@ -4,10 +4,10 @@ true - - + + From 7a690773012ad9289aeb19364dc121a0062ea016 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Sun, 15 Oct 2023 07:53:59 +0200 Subject: [PATCH 020/137] Add Swift error handling on minijit arm64 --- src/mono/mono/mini/mini-arm64.c | 38 ++++++++++++++++++--- src/tests/Interop/Swift/ErrorHandling.cs | 15 ++++---- src/tests/Interop/Swift/ErrorHandling.swift | 25 ++++++++++---- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index c5bd8435616eb8..09e7f524684921 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2770,6 +2770,17 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->inst_offset = offset; offset += size; } + ins = cfg->arch.interop_var; + if (ins) { + size = 8; + align = 8; + offset += align - 1; + offset &= ~(align - 1); + ins->opcode = OP_REGOFFSET; + ins->inst_basereg = cfg->frame_reg; + ins->inst_offset = offset; + offset += size; + } /* Locals */ offsets = mono_allocate_stack_slots (cfg, FALSE, &locals_stack_size, &locals_stack_align); @@ -3079,10 +3090,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) break; } case ArgSwiftError: { - // Create an extra variable and save call->args[0]->dreg + // Create an extra variable and save arg MonoInst *ins; ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); - ins->backend.data = GUINT_TO_POINTER (call->args[0]->dreg); + ins->flags |= MONO_INST_VOLATILE; cfg->arch.interop_var = ins; break; } @@ -3604,8 +3615,16 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) // Move value from R21 to the arg dreg if (call->signature->call_convention == MONO_CALL_SWIFTCALL) { - gint32 error_dreg = GPOINTER_TO_INT32 (cfg->arch.interop_var->backend.data); - arm_movx (code, error_dreg, ARMREG_R21); + // code = emit_ldrx (code, ARMREG_IP0, cfg->args [0]->inst_basereg, cfg->args [0]->inst_offset); + // arm_strx (code, ARMREG_R21, ARMREG_IP0, 0); + + code = emit_ldrx (code, ARMREG_IP0, cfg->arch.interop_var->inst_basereg, cfg->arch.interop_var->inst_offset); + arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0); + // Don't change R21 register + arm_movx (code, ARMREG_IP1, ARMREG_R21); + // Fixed offset + arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 0x48); + arm_strx (code, ARMREG_IP1, ARMREG_IP0, 0); } return code; @@ -6075,6 +6094,17 @@ mono_arch_emit_prolog (MonoCompile *cfg) } } + /* Initialize interop_var */ + if (cfg->arch.interop_var) { + MonoInst *ins = cfg->arch.interop_var; + g_assert (ins->opcode == OP_REGOFFSET); + + // Reset R21 register + code = emit_imm (code, ARMREG_R21, 0); + code = emit_addx_imm (code, ARMREG_IP0, cfg->args[0]->inst_basereg, cfg->args[0]->inst_offset); + code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); + } + max_offset = 0; if (cfg->opt & MONO_OPT_BRANCH) { for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/ErrorHandling.cs index b200231bc52198..83bc563c6eaece 100644 --- a/src/tests/Interop/Swift/ErrorHandling.cs +++ b/src/tests/Interop/Swift/ErrorHandling.cs @@ -3,22 +3,25 @@ using System.Runtime.InteropServices; using Xunit; -public class GlobalFunctionsTests +public class ErrorHandlingTests { [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrowSiyKF")] - public static extern nint SomeFuncThatMightThrow ([SwiftErrorReturn]ref IntPtr error); + [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrow5dummy04willG0SiSV_SbtKF")] + public static extern nint SomeFuncThatMightThrow ([SwiftErrorReturn]ref IntPtr error, bool willThrow); + + [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling06handleA04fromySPyAA02MyA0OG_tF")] + public static extern void handleError (IntPtr handle); [Fact] public static int TestEntryPoint() { IntPtr errorHandle = IntPtr.Zero; - nint result = SomeFuncThatMightThrow(ref errorHandle); - Console.WriteLine(result); + SomeFuncThatMightThrow(ref errorHandle, true); if (errorHandle != IntPtr.Zero) { + Console.WriteLine($"Error instance from R21: 0x{errorHandle:X16}"); + handleError(errorHandle); return 100; } else { - Console.WriteLine(errorHandle); return 101; } } diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 13e8549c82c9e3..173d3bc9777400 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -1,9 +1,22 @@ -enum MyError: Error { +import Foundation + +public enum MyError: Error { case runtimeError(String) + case runtimeErrorTest(String) +} + +public func someFuncThatMightThrow (dummy: UnsafeRawPointer, willThrow: Bool) throws -> Int { + if willThrow { throw MyError.runtimeError ("Catch me if you can!"); } + else { return 42; } } -public func someFuncThatMightThrow () throws -> Int { - print("Hello from Swift"); - throw MyError.runtimeError ("Catch me if you can"); - return 42; -} \ No newline at end of file +public func handleError(from pointer: UnsafePointer) { + let errorInstance = pointer.pointee + + switch errorInstance { + case .runtimeError(let message): + print (message); + default: + print ("Unhandled error!") + } +} From ebe4116b87c91f9efdd625a660086bc19cc92a0d Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 16 Oct 2023 14:12:33 +0200 Subject: [PATCH 021/137] Update README.md --- src/tests/Interop/Swift/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 560d49c9645660..0d102cfeccc0e7 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -35,7 +35,7 @@ Here are cases when `self` context is passed via register: - Non-mutating methods on value types: self may fit in one or more registers, else passed indirectly - Thick closures, i.e. closures requiring a context: the closure context -Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Similarly, the calling convention allows a function to return value types that are not opaque through a combination of registers if those values fit within the size and alignment constraints of the register. More details available at https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. +Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Similarly, the async context is handled through a register which contains a pointer to an object with information about the current state of the asynchronous operation. More details available at https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. ### Name mangling @@ -118,6 +118,10 @@ public func factorial() -> Int { In order to support Swift calling convention, it is necessary to implement error handling by emitting thunks in the above-mentioned cases. +### Async context + +When an async function is invoked, its context is stored into a register which points to an object that contains information about the current state of the asynchronous operation. + ### Update Binding Tools for Swift to work with latest version of Mono runtime We should update the Binding Tools for Swift to be compatible with the latest version of the Mono runtime and Xcode. From 71d33f46184aa90d4cc89ee38c6376cddb6f29a5 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 27 Oct 2023 22:33:23 +0200 Subject: [PATCH 022/137] Add mini arm64 support for Swift self context --- .../System.Private.CoreLib.Shared.projitems | 2 +- .../SwiftErrorReturnAttribute.cs | 19 ----- .../Runtime/InteropServices/SwiftTypes.cs | 25 +++++++ .../System.Runtime/ref/System.Runtime.cs | 26 +++++-- src/mono/mono/mini/method-to-ir.c | 20 +++++ src/mono/mono/mini/mini-amd64-gsharedvt.c | 1 - src/mono/mono/mini/mini-arm64.c | 72 ++++++------------ src/mono/mono/mini/mini-arm64.h | 2 - src/tests/Interop/Swift/ClosureFunctions.cs | 27 ------- src/tests/Interop/Swift/DefaultParams.cs | 20 ----- src/tests/Interop/Swift/ErrorHandling.cs | 10 +-- src/tests/Interop/Swift/ErrorHandling.swift | 1 - src/tests/Interop/Swift/GlobalFunctions.cs | 26 ------- src/tests/Interop/Swift/MathLibrary.swift | 75 ------------------- src/tests/Interop/Swift/README.md | 2 +- src/tests/Interop/Swift/SelfContext.cs | 29 +++++++ src/tests/Interop/Swift/SelfContext.swift | 22 ++++++ src/tests/Interop/Swift/SwiftInterop.csproj | 7 +- src/tests/Interop/Swift/Varargs.cs | 21 ------ 19 files changed, 149 insertions(+), 258 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs delete mode 100644 src/tests/Interop/Swift/ClosureFunctions.cs delete mode 100644 src/tests/Interop/Swift/DefaultParams.cs delete mode 100644 src/tests/Interop/Swift/GlobalFunctions.cs delete mode 100644 src/tests/Interop/Swift/MathLibrary.swift create mode 100644 src/tests/Interop/Swift/SelfContext.cs create mode 100644 src/tests/Interop/Swift/SelfContext.swift delete mode 100644 src/tests/Interop/Swift/Varargs.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index ac70bb68f411d3..df5201c45205b5 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -844,7 +844,6 @@ - @@ -970,6 +969,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs deleted file mode 100644 index 6b81c249483712..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SwiftErrorReturnAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; - -namespace System.Runtime.CompilerServices -{ - /// - /// Indicates that the parameter contains Swift error handler. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] - public sealed class SwiftErrorReturnAttribute : Attribute - { - public SwiftErrorReturnAttribute() - { - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs new file mode 100644 index 00000000000000..f229761ab4cfae --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.InteropServices +{ + public struct SwiftSelf + { + public IntPtr Value { get; set; } + + public SwiftSelf() + { + Value = IntPtr.Zero; + } + } + + public readonly struct SwiftError + { + public IntPtr Value { get; } + + public SwiftError() + { + Value = IntPtr.Zero; + } + } +} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a19fc445f213cf..a5ab9e132b1739 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -12912,12 +12912,6 @@ public sealed partial class InlineArrayAttribute : System.Attribute public InlineArrayAttribute(int length) { } public int Length { get { throw null; } } } - [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false)] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public sealed partial class SwiftErrorReturnAttribute : System.Attribute - { - public SwiftErrorReturnAttribute() { } - } [System.AttributeUsageAttribute(System.AttributeTargets.Struct)] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public sealed partial class IsByRefLikeAttribute : System.Attribute @@ -13511,6 +13505,26 @@ public enum LayoutKind Explicit = 2, Auto = 3, } + + public struct SwiftSelf + { + public IntPtr Value { get; set; } + + public SwiftSelf(IntPtr value) + { + Value = value; + } + } + + public readonly struct SwiftError + { + public IntPtr Value { get; } + + public SwiftError(IntPtr value) + { + Value = value; + } + } public readonly partial struct OSPlatform : System.IEquatable { private readonly object _dummy; diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index fd8a31e1e4360e..0bcb568c5252a6 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -8494,6 +8494,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (ins_flag & MONO_INST_TAILCALL) mini_test_tailcall (cfg, tailcall); + if (method->signature->call_convention == MONO_CALL_SWIFTCALL) { + int swift_self_args = 0; + int swift_error_args = 0; + for (int i = 0; i < method->signature->param_count; i++) { + MonoType *arg_type = method->signature->params [i]; + if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftSelf")) { + swift_self_args++; + } + if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftError")) { + swift_error_args++; + } + } + if (swift_self_args > 1 || swift_error_args > 1) { + mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method signature contains multiple SwiftSelf/SwiftError arguments.")); + } + // Optimization ideas: + // - If Swift types not found, remove CallConvSwift attribute + // - Else, keep arg index + } + /* End of call, INS should contain the result of the call, if any */ if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) { diff --git a/src/mono/mono/mini/mini-amd64-gsharedvt.c b/src/mono/mono/mini/mini-amd64-gsharedvt.c index 64956eb34864ec..0aa2f1559006b3 100644 --- a/src/mono/mono/mini/mini-amd64-gsharedvt.c +++ b/src/mono/mono/mini/mini-amd64-gsharedvt.c @@ -49,7 +49,6 @@ storage_name (ArgStorage st) case ArgValuetypeAddrOnStack: return "ArgValuetypeAddrOnStack"; case ArgGSharedVtInReg: return "ArgGSharedVtInReg"; case ArgGSharedVtOnStack: return "ArgGSharedVtOnStack"; - case ArgSwiftError: return "ArgSwiftError"; case ArgNone: return "ArgNone"; default: return "unknown"; } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index d28227fbe03565..1dcf6565227d9b 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1866,11 +1866,6 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) add_param (cinfo, &cinfo->sig_cookie, mono_get_int_type (), FALSE); } - if (sig->call_convention == MONO_CALL_SWIFTCALL) { - // Assume that the first argument is SwiftError - cinfo->args[0].storage = ArgSwiftError; - } - cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT); return cinfo; @@ -2671,7 +2666,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: - case ArgSwiftError: cfg->ret->opcode = OP_REGVAR; cfg->ret->dreg = cinfo->ret.reg; break; @@ -2726,7 +2720,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: - case ArgSwiftError: // FIXME: Use nregs/size /* These will be copied to the stack in the prolog */ ins->inst_offset = offset; @@ -2842,17 +2835,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->inst_offset = offset; offset += size; } - ins = cfg->arch.interop_var; - if (ins) { - size = 8; - align = 8; - offset += align - 1; - offset &= ~(align - 1); - ins->opcode = OP_REGOFFSET; - ins->inst_basereg = cfg->frame_reg; - ins->inst_offset = offset; - offset += size; - } /* Locals */ offsets = mono_allocate_stack_slots (cfg, FALSE, &locals_stack_size, &locals_stack_align); @@ -3161,14 +3143,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) MONO_ADD_INS (cfg->cbb, ins); break; } - case ArgSwiftError: { - // Create an extra variable and save arg - MonoInst *ins; - ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); - ins->flags |= MONO_INST_VOLATILE; - cfg->arch.interop_var = ins; - break; - } default: g_assert_not_reached (); break; @@ -3687,16 +3661,18 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) // Move value from R21 to the arg dreg if (call->signature->call_convention == MONO_CALL_SWIFTCALL) { - // code = emit_ldrx (code, ARMREG_IP0, cfg->args [0]->inst_basereg, cfg->args [0]->inst_offset); - // arm_strx (code, ARMREG_R21, ARMREG_IP0, 0); - - code = emit_ldrx (code, ARMREG_IP0, cfg->arch.interop_var->inst_basereg, cfg->arch.interop_var->inst_offset); - arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0); - // Don't change R21 register - arm_movx (code, ARMREG_IP1, ARMREG_R21); - // Fixed offset - arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 0x48); - arm_strx (code, ARMREG_IP1, ARMREG_IP0, 0); + for (int i = 0; i < call->signature->param_count; i++) { + MonoType *arg_type = call->signature->params [i]; + if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftError")) { + code = emit_ldrx (code, ARMREG_IP0, cfg->args [i]->inst_basereg, cfg->args [i]->inst_offset); + // Don't change R21 register + arm_movx (code, ARMREG_IP1, ARMREG_R21); + // Fixed offset + arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 0x48); + arm_strx (code, ARMREG_IP1, ARMREG_IP0, 0); + break; + } + } } return code; @@ -5778,7 +5754,6 @@ emit_move_args (MonoCompile *cfg, guint8 *code) switch (ainfo->storage) { case ArgInIReg: - case ArgSwiftError: /* Stack slots for arguments have size 8 */ code = emit_strx (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); if (i == 0 && sig->hasthis) { @@ -5839,6 +5814,18 @@ emit_move_args (MonoCompile *cfg, guint8 *code) } } } + // TODO: Utilize ArgStorage enum + // Move self pointer to R20 + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + for (int i = 0; i < sig->param_count; i++) { + MonoType *arg_type = sig->params [i]; + if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftSelf")) { + code = emit_ldrx (code, ARMREG_IP0, cfg->args[i]->inst_basereg, cfg->args[i]->inst_offset); + arm_movx (code, ARMREG_R20, ARMREG_IP0); + break; + } + } + } return code; } @@ -6166,17 +6153,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) } } - /* Initialize interop_var */ - if (cfg->arch.interop_var) { - MonoInst *ins = cfg->arch.interop_var; - g_assert (ins->opcode == OP_REGOFFSET); - - // Reset R21 register - code = emit_imm (code, ARMREG_R21, 0); - code = emit_addx_imm (code, ARMREG_IP0, cfg->args[0]->inst_basereg, cfg->args[0]->inst_offset); - code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); - } - max_offset = 0; if (cfg->opt & MONO_OPT_BRANCH) { for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index f87bbf061c4117..da21523af81ddf 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -119,7 +119,6 @@ typedef struct { MonoInst *seq_point_info_var; MonoInst *ss_tramp_var; MonoInst *bp_tramp_var; - MonoInst *interop_var; guint8 *thunks; int thunks_size; } MonoCompileArch; @@ -234,7 +233,6 @@ typedef enum { ArgVtypeByRefOnStack, ArgVtypeOnStack, ArgHFA, - ArgSwiftError, ArgNone } ArgStorage; diff --git a/src/tests/Interop/Swift/ClosureFunctions.cs b/src/tests/Interop/Swift/ClosureFunctions.cs deleted file mode 100644 index 6ad7b64e7b3bb2..00000000000000 --- a/src/tests/Interop/Swift/ClosureFunctions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -public class ClosureFunctionsTests -{ - public delegate double OperationDelegate(double a, double b); - - [DllImport("libMathLibrary.dylib", EntryPoint = "add")] - public static extern double add(double a, double b); - - [DllImport("libMathLibrary.dylib", EntryPoint = "applyOperation")] - public static extern double applyOperation(double a, double b, OperationDelegate operation); - - [Fact] - public static int TestEntryPoint() - { - OperationDelegate addDelegate = add; - - double result = 0.0; - result = applyOperation(5.0, 3.0, addDelegate); - Assert.Equal(8.0, result); - - return 100; - } -} diff --git a/src/tests/Interop/Swift/DefaultParams.cs b/src/tests/Interop/Swift/DefaultParams.cs deleted file mode 100644 index 4ec660abe59101..00000000000000 --- a/src/tests/Interop/Swift/DefaultParams.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -public class DefaultParamsTests -{ - [DllImport("libMathLibrary.dylib", EntryPoint = "multiply")] - public static extern double multiply(double a, double b = 1.0); - - [Fact] - public static int TestEntryPoint() - { - double result = 0.0; - result = multiply(5.0); - Assert.Equal(5.0, result); - - return 100; - } -} diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/ErrorHandling.cs index 83bc563c6eaece..4891dc09a6606f 100644 --- a/src/tests/Interop/Swift/ErrorHandling.cs +++ b/src/tests/Interop/Swift/ErrorHandling.cs @@ -7,7 +7,7 @@ public class ErrorHandlingTests { [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrow5dummy04willG0SiSV_SbtKF")] - public static extern nint SomeFuncThatMightThrow ([SwiftErrorReturn]ref IntPtr error, bool willThrow); + public static extern nint SomeFuncThatMightThrow (ref SwiftError error, bool willThrow); [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling06handleA04fromySPyAA02MyA0OG_tF")] public static extern void handleError (IntPtr handle); @@ -15,11 +15,11 @@ public class ErrorHandlingTests [Fact] public static int TestEntryPoint() { - IntPtr errorHandle = IntPtr.Zero; + SwiftError errorHandle = new SwiftError(); SomeFuncThatMightThrow(ref errorHandle, true); - if (errorHandle != IntPtr.Zero) { - Console.WriteLine($"Error instance from R21: 0x{errorHandle:X16}"); - handleError(errorHandle); + if (errorHandle.Value != IntPtr.Zero) { + Console.WriteLine($"Error instance from R21: 0x{errorHandle.Value:X16}"); + handleError(errorHandle.Value); return 100; } else { return 101; diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 173d3bc9777400..4c83612a903360 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -2,7 +2,6 @@ import Foundation public enum MyError: Error { case runtimeError(String) - case runtimeErrorTest(String) } public func someFuncThatMightThrow (dummy: UnsafeRawPointer, willThrow: Bool) throws -> Int { diff --git a/src/tests/Interop/Swift/GlobalFunctions.cs b/src/tests/Interop/Swift/GlobalFunctions.cs deleted file mode 100644 index 8ae52b3473f2d6..00000000000000 --- a/src/tests/Interop/Swift/GlobalFunctions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -public class GlobalFunctionsTests -{ - [DllImport("libMathLibrary.dylib", EntryPoint = "add")] - public static extern double add(double a, double b); - - [DllImport("libMathLibrary.dylib", EntryPoint = "subtract")] - public static extern double subtract(double a, double b); - - [Fact] - public static int TestEntryPoint() - { - double result = 0.0; - result = add(5.0, 3.0); - Assert.Equal(8.0, result); - - result = subtract(5.0, 3.0); - Assert.Equal(2.0, result); - - return 100; - } -} diff --git a/src/tests/Interop/Swift/MathLibrary.swift b/src/tests/Interop/Swift/MathLibrary.swift deleted file mode 100644 index e6c11d8ab0b39c..00000000000000 --- a/src/tests/Interop/Swift/MathLibrary.swift +++ /dev/null @@ -1,75 +0,0 @@ -public protocol MathLibraryDelegate: AnyObject { - func mathLibraryDidInitialize() - func mathLibraryDidDeinitialize() -} - -public class MathLibrary { - // Global/Static functions - public static func add(_ a: Double, _ b: Double) -> Double { - return a + b - } - - public static func subtract(_ a: Double, _ b: Double) -> Double { - return a - b - } - - // Function with default params - public static func multiply(_ a: Double, _ b: Double = 1.0) -> Double { - return a * b - } - - // Function with varargs - public static func average(numbers: Double...) -> Double { - let sum = numbers.reduce(0, +) - return sum / Double(numbers.count) - } - - // Function with closures - public static func applyOperation(a: Double, b: Double, operation: (Double, Double) -> Double) -> Double { - return operation(a, b) - } - - // Computed property - public static var circleArea: (Double) -> Double = { radius in - return Double.pi * radius * radius - } - - public weak var delegate: MathLibraryDelegate? - - // Initializers/Deinitializers - public init(_internalValue: Int) { - self._internalValue = _internalValue - print("MathLibrary initialized.") - - // Notify the delegate that the library was initialized - delegate?.mathLibraryDidInitialize() - - } - - deinit { - print("MathLibrary deinitialized.") - - // Notify the delegate that the library was deinitialized - delegate?.mathLibraryDidDeinitialize() - } - - // Getters/Setters - private var _internalValue: Int = 0 - - public var value: Int { - get { - return _internalValue - } - set { - _internalValue = newValue - } - } - - // Instance function - public func factorial() -> Int { - guard _internalValue >= 0 else { - fatalError("Factorial is undefined for negative numbers") - } - return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() - } -} diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 0d102cfeccc0e7..693f3a5aaf8163 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -230,8 +230,8 @@ Build the tests: ``` Build the native library: ```sh -swiftc -emit-library ./src/tests/Interop/Swift/MathLibrary.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libMathLibrary.dylib swiftc -emit-library ./src/tests/Interop/Swift/ErrorHandling.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libErrorHandling.dylib +swiftc -emit-library ./src/tests/Interop/Swift/SelfContext.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libSelfContext.dylib ``` Run the tests: ``` diff --git a/src/tests/Interop/Swift/SelfContext.cs b/src/tests/Interop/Swift/SelfContext.cs new file mode 100644 index 00000000000000..0064bd104dcf21 --- /dev/null +++ b/src/tests/Interop/Swift/SelfContext.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +public class SelfContextTests +{ + [DllImport("libSelfContext.dylib", EntryPoint = "$s11SelfContext11MathLibraryC11getInstanceSvyFZ")] + public static extern IntPtr getInstance(); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport("libSelfContext.dylib", EntryPoint = "$s11SelfContext11MathLibraryC14getMagicNumber5dummyySV_tF")] + public static extern void getMagicNumber(SwiftSelf handle); + + [Fact] + public static int TestEntryPoint() + { + SwiftSelf selfHandle = new SwiftSelf(); + selfHandle.Value = getInstance(); + + if (selfHandle.Value != IntPtr.Zero) { + Console.WriteLine($"Self instance: 0x{selfHandle.Value:X16}"); + getMagicNumber (selfHandle); + return 100; + } else { + return 101; + } + } +} diff --git a/src/tests/Interop/Swift/SelfContext.swift b/src/tests/Interop/Swift/SelfContext.swift new file mode 100644 index 00000000000000..2facc1bd707437 --- /dev/null +++ b/src/tests/Interop/Swift/SelfContext.swift @@ -0,0 +1,22 @@ +public class MathLibrary { + public var a: Double + public var b: Double + + public static let shared = MathLibrary(a: 40.0, b: 2.0) + + private init(a: Double, b: Double) { + self.a = a + self.b = b + } + + public func getMagicNumber(dummy: UnsafeRawPointer) { + print(a + b) + } + + + public static func getInstance() -> UnsafeMutableRawPointer { + let unmanagedInstance = Unmanaged.passUnretained(shared) + let pointer = unmanagedInstance.toOpaque() + return pointer + } +} \ No newline at end of file diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInterop.csproj index 5cbb62535e4e8a..0fe5aaf3e02028 100644 --- a/src/tests/Interop/Swift/SwiftInterop.csproj +++ b/src/tests/Interop/Swift/SwiftInterop.csproj @@ -2,13 +2,10 @@ Exe true + true + - - - diff --git a/src/tests/Interop/Swift/Varargs.cs b/src/tests/Interop/Swift/Varargs.cs deleted file mode 100644 index 57613b4382adf6..00000000000000 --- a/src/tests/Interop/Swift/Varargs.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -public class VarargsTests -{ - [DllImport("libMathLibrary.dylib", EntryPoint = "average")] - public static extern double average([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] numbers, int count); - - [Fact] - public static int TestEntryPoint() - { - double result = 0.0; - double[] numbers = { 1.0, 2.0, 3.0 }; - result = average(numbers, numbers.Length); - Assert.Equal(6.0, result); - - return 100; - } -} From 7bcf61f381fb97edfdf493a4359af89cba8aa4f0 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 27 Oct 2023 22:40:46 +0200 Subject: [PATCH 023/137] Remove redundant movx instruction --- src/mono/mono/mini/mini-arm64.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 1dcf6565227d9b..a471c7b5992197 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -5820,8 +5820,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) for (int i = 0; i < sig->param_count; i++) { MonoType *arg_type = sig->params [i]; if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftSelf")) { - code = emit_ldrx (code, ARMREG_IP0, cfg->args[i]->inst_basereg, cfg->args[i]->inst_offset); - arm_movx (code, ARMREG_R20, ARMREG_IP0); + code = emit_ldrx (code, ARMREG_R20, cfg->args[i]->inst_basereg, cfg->args[i]->inst_offset); break; } } From 5973ff53eb5c6e6ad6ddc2f03cdac118ea52ffc7 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 31 Oct 2023 12:02:55 +0100 Subject: [PATCH 024/137] Update Swift types according to the design document --- .../System.Private.CoreLib.Shared.projitems | 2 +- .../InteropServices/Swift/SwiftType.cs | 29 ++++++++++++++ .../Runtime/InteropServices/SwiftTypes.cs | 25 ------------ .../System.Runtime/ref/System.Runtime.cs | 38 +++++++++---------- src/tests/Interop/Swift/ErrorHandling.cs | 9 +++-- src/tests/Interop/Swift/ErrorHandling.swift | 24 +++++++----- src/tests/Interop/Swift/README.md | 2 +- src/tests/Interop/Swift/SelfContext.cs | 5 ++- 8 files changed, 72 insertions(+), 62 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index ced48e724fda74..f28187dfc10f35 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -970,7 +970,7 @@ - + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs new file mode 100644 index 00000000000000..c5256603f82032 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.InteropServices.Swift +{ + public readonly struct SwiftSelf + { + public SwiftSelf(IntPtr value) { + Value = value; + } + public IntPtr Value { get; } + } + + public readonly struct SwiftError + { + public SwiftError(IntPtr value) { + Value = value; + } + public IntPtr Value { get; } + } + + public readonly struct SwiftAsyncContext + { + public SwiftAsyncContext(IntPtr value) { + Value = value; + } + public IntPtr Value { get; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs deleted file mode 100644 index f229761ab4cfae..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SwiftTypes.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.InteropServices -{ - public struct SwiftSelf - { - public IntPtr Value { get; set; } - - public SwiftSelf() - { - Value = IntPtr.Zero; - } - } - - public readonly struct SwiftError - { - public IntPtr Value { get; } - - public SwiftError() - { - Value = IntPtr.Zero; - } - } -} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a5ab9e132b1739..a07c0938944d1c 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13505,26 +13505,6 @@ public enum LayoutKind Explicit = 2, Auto = 3, } - - public struct SwiftSelf - { - public IntPtr Value { get; set; } - - public SwiftSelf(IntPtr value) - { - Value = value; - } - } - - public readonly struct SwiftError - { - public IntPtr Value { get; } - - public SwiftError(IntPtr value) - { - Value = value; - } - } public readonly partial struct OSPlatform : System.IEquatable { private readonly object _dummy; @@ -13826,6 +13806,24 @@ public void Free() { } } } } +namespace System.Runtime.InteropServices.Swift +{ + public readonly struct SwiftSelf + { + public SwiftSelf(IntPtr value) { } + public IntPtr Value { get; } + } + public readonly struct SwiftError + { + public SwiftError(IntPtr value) { } + public IntPtr Value { get; } + } + public readonly struct SwiftAsyncContext + { + public SwiftAsyncContext(IntPtr value) { } + public IntPtr Value { get; } + } +} namespace System.Runtime.Remoting { public partial class ObjectHandle : System.MarshalByRefObject diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/ErrorHandling.cs index 4891dc09a6606f..552888179c8e2b 100644 --- a/src/tests/Interop/Swift/ErrorHandling.cs +++ b/src/tests/Interop/Swift/ErrorHandling.cs @@ -1,22 +1,23 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Swift; using Xunit; public class ErrorHandlingTests { [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrow5dummy04willG0SiSV_SbtKF")] - public static extern nint SomeFuncThatMightThrow (ref SwiftError error, bool willThrow); + [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrow04willG05dummySiSb_SVtKF")] + public unsafe static extern nint SomeFuncThatMightThrow (bool willThrow, SwiftError* error); [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling06handleA04fromySPyAA02MyA0OG_tF")] public static extern void handleError (IntPtr handle); [Fact] - public static int TestEntryPoint() + public unsafe static int TestEntryPoint() { SwiftError errorHandle = new SwiftError(); - SomeFuncThatMightThrow(ref errorHandle, true); + SomeFuncThatMightThrow(true, &errorHandle); if (errorHandle.Value != IntPtr.Zero) { Console.WriteLine($"Error instance from R21: 0x{errorHandle.Value:X16}"); handleError(errorHandle.Value); diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 4c83612a903360..aebb7fe09b57cf 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -1,21 +1,27 @@ import Foundation public enum MyError: Error { - case runtimeError(String) + case runtimeError(message: String, info: String) } -public func someFuncThatMightThrow (dummy: UnsafeRawPointer, willThrow: Bool) throws -> Int { - if willThrow { throw MyError.runtimeError ("Catch me if you can!"); } +public func someFuncThatMightThrow (willThrow: Bool, dummy: UnsafeRawPointer) throws -> Int { + if willThrow { throw MyError.runtimeError (message: "Catch me if you can!", info: "abcd abcd"); } else { return 42; } } public func handleError(from pointer: UnsafePointer) { - let errorInstance = pointer.pointee + let pointerValue = UInt(bitPattern: pointer) + let offsetPointerValue = pointerValue + 0x48 + let offsetPointer = UnsafeRawPointer(bitPattern: offsetPointerValue) - switch errorInstance { - case .runtimeError(let message): - print (message); - default: - print ("Unhandled error!") + if let offsetErrorPointer = offsetPointer?.assumingMemoryBound(to: MyError.self) { + let errorInstance = offsetErrorPointer.pointee + switch errorInstance { + case .runtimeError(let message, _): + print(message) + } + } else { + print("Pointer does not point to MyError.") } + } diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 693f3a5aaf8163..d3a278a928760e 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -218,7 +218,7 @@ deinit { Build the runtime: ```sh -./build.sh mono+libs+clr.hosts +./build.sh mono+libs+clr.hosts /p:ApiCompatGenerateSuppressionFile=true /p:KeepNativeSymbols=true ``` Build the coreroot: ```sh diff --git a/src/tests/Interop/Swift/SelfContext.cs b/src/tests/Interop/Swift/SelfContext.cs index 0064bd104dcf21..4f880d37daa827 100644 --- a/src/tests/Interop/Swift/SelfContext.cs +++ b/src/tests/Interop/Swift/SelfContext.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Swift; using Xunit; public class SelfContextTests @@ -15,8 +16,8 @@ public class SelfContextTests [Fact] public static int TestEntryPoint() { - SwiftSelf selfHandle = new SwiftSelf(); - selfHandle.Value = getInstance(); + IntPtr handle = getInstance(); + SwiftSelf selfHandle = new SwiftSelf(handle); if (selfHandle.Value != IntPtr.Zero) { Console.WriteLine($"Self instance: 0x{selfHandle.Value:X16}"); From ffc173a9ac0b72068725e486f067b6272fe00e5f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 31 Oct 2023 12:04:36 +0100 Subject: [PATCH 025/137] Add mini arm64 support for Swift self and error registers --- src/mono/mono/mini/method-to-ir.c | 44 ++++++++++--------- src/mono/mono/mini/mini-arm64.c | 73 +++++++++++++++++++------------ src/mono/mono/mini/mini-arm64.h | 2 + 3 files changed, 70 insertions(+), 49 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 0bcb568c5252a6..d3e7293372a935 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7631,6 +7631,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b goto calli_end; } } + + if (method->signature->call_convention == MONO_CALL_SWIFTCALL) { + int swift_error_args = 0; + int swift_self_args = 0; + for (int i = 0; i < method->signature->param_count; ++i) { + MonoType *arg_type = method->signature->params [i]; + if (arg_type && arg_type->data.klass) { + const char *name_space = m_class_get_name_space(arg_type->data.klass); + const char *class_name = m_class_get_name(arg_type->data.klass); + + if (name_space && class_name && !strcmp(name_space, "System.Runtime.InteropServices.Swift")) { + if (!strcmp(class_name, "SwiftError")) { + swift_error_args++; + } else if (!strcmp(class_name, "SwiftSelf")) { + swift_self_args++; + } + } + } + } + if (swift_self_args > 1 || swift_error_args > 1) { + mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method signature contains multiple SwiftSelf/SwiftError arguments.")); + } + } + /* Some wrappers use calli with ftndesc-es */ if (cfg->llvm_only && !(cfg->method->wrapper_type && cfg->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && @@ -8494,26 +8518,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (ins_flag & MONO_INST_TAILCALL) mini_test_tailcall (cfg, tailcall); - if (method->signature->call_convention == MONO_CALL_SWIFTCALL) { - int swift_self_args = 0; - int swift_error_args = 0; - for (int i = 0; i < method->signature->param_count; i++) { - MonoType *arg_type = method->signature->params [i]; - if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftSelf")) { - swift_self_args++; - } - if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftError")) { - swift_error_args++; - } - } - if (swift_self_args > 1 || swift_error_args > 1) { - mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method signature contains multiple SwiftSelf/SwiftError arguments.")); - } - // Optimization ideas: - // - If Swift types not found, remove CallConvSwift attribute - // - Else, keep arg index - } - /* End of call, INS should contain the result of the call, if any */ if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) { diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index eb6c65a2e21182..dd51ce4bb8e067 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1869,6 +1869,22 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->gr ++; } } + + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + MonoType *arg_type = sig->params[pindex]->data.type; + if (arg_type && arg_type->data.klass) { + const char *name_space = m_class_get_name_space(arg_type->data.klass); + const char *class_name = m_class_get_name(arg_type->data.klass); + + if (name_space && class_name && !strcmp(name_space, "System.Runtime.InteropServices.Swift")) { + if (!strcmp(class_name, "SwiftError")) { + ainfo->storage = ArgSwiftError; + } else if (!strcmp(class_name, "SwiftSelf")) { + ainfo->storage = ArgSwiftSelf; + } + } + } + } } /* Handle the case where there are no implicit arguments */ @@ -2735,6 +2751,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: + case ArgSwiftError: // FIXME: Use nregs/size /* These will be copied to the stack in the prolog */ ins->inst_offset = offset; @@ -2752,6 +2769,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgVtypeInIRegs: case ArgHFA: case ArgInSIMDReg: + case ArgSwiftSelf: ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; /* These arguments are saved to the stack in the prolog */ @@ -2995,6 +3013,7 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int re switch (storage) { case ArgInIReg: + case ArgSwiftError: MONO_INST_NEW (cfg, ins, OP_MOVE); ins->dreg = mono_alloc_ireg_copy (cfg, arg->dreg); ins->sreg1 = arg->dreg; @@ -3109,6 +3128,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: + case ArgSwiftError: add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, arg); break; case ArgOnStack: @@ -3141,7 +3161,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgVtypeByRefOnStack: case ArgVtypeOnStack: case ArgInSIMDReg: - case ArgHFA: { + case ArgHFA: + case ArgSwiftSelf: { MonoInst *ins; guint32 align; guint32 size; @@ -3185,6 +3206,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) switch (ainfo->storage) { case ArgVtypeInIRegs: + case ArgSwiftSelf: for (i = 0; i < ainfo->nregs; ++i) { // FIXME: Smaller sizes MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE); @@ -3674,22 +3696,6 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) break; } - // Move value from R21 to the arg dreg - if (call->signature->call_convention == MONO_CALL_SWIFTCALL) { - for (int i = 0; i < call->signature->param_count; i++) { - MonoType *arg_type = call->signature->params [i]; - if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftError")) { - code = emit_ldrx (code, ARMREG_IP0, cfg->args [i]->inst_basereg, cfg->args [i]->inst_offset); - // Don't change R21 register - arm_movx (code, ARMREG_IP1, ARMREG_R21); - // Fixed offset - arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 0x48); - arm_strx (code, ARMREG_IP1, ARMREG_IP0, 0); - break; - } - } - } - return code; } @@ -5769,6 +5775,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) switch (ainfo->storage) { case ArgInIReg: + case ArgSwiftError: /* Stack slots for arguments have size 8 */ code = emit_strx (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); if (i == 0 && sig->hasthis) { @@ -5802,6 +5809,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) break; } case ArgVtypeInIRegs: + case ArgSwiftSelf: for (part = 0; part < ainfo->nregs; part ++) { int offs = GTMREG_TO_INT (ins->inst_offset + (part * 8)); if (part + 1 < ainfo->nregs && IS_VALID_STPX_OFFSET (offs)) { @@ -5810,6 +5818,10 @@ emit_move_args (MonoCompile *cfg, guint8 *code) continue; } code = emit_strx (code, ainfo->reg + part, ins->inst_basereg, offs); + + if (ainfo->storage == ArgSwiftSelf) { + code = emit_ldrx (code, ARMREG_R20, ins->inst_basereg, ins->inst_offset); + } } break; case ArgHFA: @@ -5829,17 +5841,6 @@ emit_move_args (MonoCompile *cfg, guint8 *code) } } } - // TODO: Utilize ArgStorage enum - // Move self pointer to R20 - if (sig->call_convention == MONO_CALL_SWIFTCALL) { - for (int i = 0; i < sig->param_count; i++) { - MonoType *arg_type = sig->params [i]; - if (arg_type->data.klass && !strcmp (m_class_get_name (arg_type->data.klass), "SwiftSelf")) { - code = emit_ldrx (code, ARMREG_R20, cfg->args[i]->inst_basereg, cfg->args[i]->inst_offset); - break; - } - } - } return code; } @@ -6195,6 +6196,21 @@ mono_arch_emit_epilog (MonoCompile *cfg) max_epilog_size = 16 + 20*4; code = realloc_code (cfg, max_epilog_size); + cinfo = cfg->arch.cinfo; + for (i = 0; i < cinfo->nargs; ++i) { + ArgInfo* ainfo = cinfo->args + i; + MonoInst* arg = cfg->args [i]; + + switch (ainfo->storage) { + case ArgSwiftError: + code = emit_ldrx (code, ARMREG_IP0, arg->inst_basereg, arg->inst_offset); + arm_strx (code, ARMREG_R21, ARMREG_IP0, 0); + break; + default: + break; + } + } + if (cfg->method->save_lmf) { code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, GTMREG_TO_INT (cfg->lmf_var->inst_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs) - (MONO_ARCH_FIRST_LMF_REG * 8))); } else { @@ -6203,7 +6219,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) } /* Load returned vtypes into registers if needed */ - cinfo = cfg->arch.cinfo; switch (cinfo->ret.storage) { case ArgVtypeInIRegs: { MonoInst *ins = cfg->ret; diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index da21523af81ddf..a169d7d6993ce3 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -233,6 +233,8 @@ typedef enum { ArgVtypeByRefOnStack, ArgVtypeOnStack, ArgHFA, + ArgSwiftError, + ArgSwiftSelf, ArgNone } ArgStorage; From 907c69ad4498ff9b9d7a0fcba9f7f1be7f19c87f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 2 Nov 2023 13:46:54 +0100 Subject: [PATCH 026/137] [interp] Add interpreter support for Swift calling convention It introduces support for the Swift calling convention when invoking Swift functions from managed code using P/Invoke on arm64. The CallContext is expanded with context registers that get preserved in a generic trampoline. Before and after the function call, the interpreter stores the self context argument into a CallContext context register, which is copied into the appropriate register before the native function call. Similarly, after the call, the interpreter indirectly stores the error context register value from the CallContext context register onto the stack at SwiftError* argument. --- src/mono/mono/metadata/object-offsets.h | 1 + src/mono/mono/mini/aot-compiler.c | 2 +- src/mono/mono/mini/ee.h | 1 + src/mono/mono/mini/interp-stubs.c | 6 +++++ src/mono/mono/mini/interp/interp.c | 30 ++++++++++++++++----- src/mono/mono/mini/interp/transform.c | 2 ++ src/mono/mono/mini/mini-arm64.c | 36 ++++++++++++++++++++++--- src/mono/mono/mini/mini-arm64.h | 4 +++ src/mono/mono/mini/mini.h | 4 ++- src/mono/mono/mini/tramp-arm64.c | 14 +++++++++- 10 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/mono/mono/metadata/object-offsets.h b/src/mono/mono/metadata/object-offsets.h index a1ab49ff43a091..3d851753b8995e 100644 --- a/src/mono/mono/metadata/object-offsets.h +++ b/src/mono/mono/metadata/object-offsets.h @@ -305,6 +305,7 @@ DECL_OFFSET(SeqPointInfo, bp_addrs) DECL_OFFSET(CallContext, gregs) DECL_OFFSET(CallContext, fregs) +DECL_OFFSET(CallContext, cregs) DECL_OFFSET(CallContext, stack_size) DECL_OFFSET(CallContext, stack) #endif diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 2cd2dbc234f21d..5fcbae5997405c 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -8387,7 +8387,7 @@ emit_trampolines (MonoAotCompile *acfg) } if (mono_aot_mode_is_interp (&acfg->aot_opts) && mono_is_corlib_image (acfg->image->assembly->image)) { - mono_arch_get_interp_to_native_trampoline (&info); + mono_arch_get_interp_to_native_trampoline (NULL, &info); emit_trampoline (acfg, info); #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE diff --git a/src/mono/mono/mini/ee.h b/src/mono/mono/mini/ee.h index 1e88e9aaaa9d81..c6f986403a449d 100644 --- a/src/mono/mono/mini/ee.h +++ b/src/mono/mono/mini/ee.h @@ -51,6 +51,7 @@ typedef gpointer MonoInterpFrameHandle; MONO_EE_CALLBACK (gpointer, frame_get_this, (MonoInterpFrameHandle frame)) \ MONO_EE_CALLBACK (void, frame_arg_to_data, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)) \ MONO_EE_CALLBACK (void, data_to_frame_arg, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)) \ + MONO_EE_CALLBACK (void, data_to_frame_arg_indirect, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)) \ MONO_EE_CALLBACK (gpointer, frame_arg_to_storage, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)) \ MONO_EE_CALLBACK (MonoInterpFrameHandle, frame_get_parent, (MonoInterpFrameHandle frame)) \ MONO_EE_CALLBACK (void, start_single_stepping, (void)) \ diff --git a/src/mono/mono/mini/interp-stubs.c b/src/mono/mono/mini/interp-stubs.c index 0ade0c95e0440d..58122081c43565 100644 --- a/src/mono/mono/mini/interp-stubs.c +++ b/src/mono/mono/mini/interp-stubs.c @@ -203,6 +203,12 @@ stub_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, i g_assert_not_reached (); } +static void +stub_data_to_frame_arg_indirect (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data) +{ + g_assert_not_reached (); +} + static gpointer stub_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index) { diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 213ef829cdf0a5..655a1a1cc03a19 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1577,6 +1577,17 @@ interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, stackval_from_data (sig->params [index - sig->hasthis], STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)), data, sig->pinvoke && !sig->marshalling_disabled); } +static void +interp_data_to_frame_arg_indirect (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data) +{ + InterpFrame *iframe = (InterpFrame*)frame; + InterpMethod *imethod = iframe->imethod; + + // Perform an indirect store at index stack location + stackval *result = (stackval*) STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)); + *(gpointer*)result->data.p = *(gpointer*)data; +} + static gpointer interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index) { @@ -1590,16 +1601,16 @@ interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *s } static MonoPIFunc -get_interp_to_native_trampoline (void) +get_interp_to_native_trampoline (MonoMethodSignature *sig) { static MonoPIFunc trampoline = NULL; - if (!trampoline) { + if (!trampoline || sig) { if (mono_ee_features.use_aot_trampolines) { trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline"); } else { MonoTrampInfo *info; - trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info); + trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (sig, &info); mono_tramp_info_register (info, NULL); } mono_memory_barrier (); @@ -1610,7 +1621,7 @@ get_interp_to_native_trampoline (void) static void interp_to_native_trampoline (gpointer addr, gpointer ccontext) { - get_interp_to_native_trampoline () (addr, ccontext); + get_interp_to_native_trampoline (NULL) (addr, ccontext); } /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */ @@ -1654,15 +1665,19 @@ ves_pinvoke_method ( *cache = entry_func; } #else + // The generic trampoline is cached in the static variable 'entry_func'. If a different calling convention is used, + // retrieve the generic trampoline again, as it may contain handling of context registers. static MonoPIFunc entry_func = NULL; - if (!entry_func) { + unsigned int call_conv = 0; + if (!entry_func || sig->call_convention != call_conv) { + call_conv = sig->call_convention; MONO_ENTER_GC_UNSAFE; #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX ERROR_DECL (error); entry_func = (MonoPIFunc) mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper ("mono_interp_to_native_trampoline", (gpointer) mono_interp_to_native_trampoline), error); mono_error_assert_ok (error); #else - entry_func = get_interp_to_native_trampoline (); + entry_func = get_interp_to_native_trampoline (sig); #endif mono_memory_barrier (); MONO_EXIT_GC_UNSAFE; @@ -1705,6 +1720,9 @@ ves_pinvoke_method ( interp_pop_lmf (&ext); #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + mono_arch_get_native_call_context_error (&ccontext, &frame, sig, call_info); + } if (!context->has_resume_state) { mono_arch_get_native_call_context_ret (&ccontext, &frame, sig, call_info); } diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index d0ee55f987165e..685cdbda7229b2 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3817,6 +3817,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target default_cconv = csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C; #endif #endif + // When using the Swift calling convention, emit MINT_CALLI_NAT opcode to manage context registers. + default_cconv = default_cconv && csignature->call_convention != MONO_CALL_SWIFTCALL; // FIXME calli receives both the args offset and sometimes another arg for the frame pointer, // therefore some args are in the param area, while the fp is not. We should differentiate for diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index dd51ce4bb8e067..7d4fcba6124c51 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1917,10 +1917,14 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgVtypeInIRegs: case ArgInIReg: return &ccontext->gregs [ainfo->reg]; + case ArgSwiftSelf: + return &ccontext->cregs [ARMREG_R20 - CTX_REGS_OFFSET]; + case ArgSwiftError: + return &ccontext->cregs [ARMREG_R21 - CTX_REGS_OFFSET]; case ArgInFReg: case ArgInFRegR4: case ArgHFA: - return &ccontext->fregs [ainfo->reg]; + return &ccontext->fregs [ainfo->reg]; case ArgOnStack: case ArgOnStackR4: case ArgOnStackR8: @@ -1930,8 +1934,8 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) return *(gpointer*)(ccontext->stack + ainfo->offset); case ArgVtypeByRef: return (gpointer) ccontext->gregs [ainfo->reg]; - default: - g_error ("Arg storage type not yet supported"); + default: + g_error ("Arg storage type not yet supported"); } } @@ -2123,6 +2127,32 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +/** + * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. + * + * The function searches for an argument with the storage type `ArgSwiftError`. If found, + * it retrieves the value from `ccontext` and indirectly stores it onto the stack of the current frame. + */ +void +mono_arch_get_native_call_context_error (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info) +{ + const MonoEECallbacks *interp_cb; + CallInfo *cinfo = (CallInfo*)call_info; + ArgInfo *ainfo; + gpointer storage; + + interp_cb = mini_get_interp_callbacks (); + + for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { + ainfo = &cinfo->args [i]; + if (ainfo->storage == ArgSwiftError) { + storage = arg_get_storage (ccontext, ainfo); + interp_cb->data_to_frame_arg_indirect ((MonoInterpFrameHandle)frame, sig, i, storage); + break; + } + } +} + typedef struct { MonoMethodSignature *sig; CallInfo *cinfo; diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index a169d7d6993ce3..c96a33bc78594a 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -98,6 +98,8 @@ struct SeqPointInfo { #define PARAM_REGS 8 #define FP_PARAM_REGS 8 +#define CTX_REGS 2 +#define CTX_REGS_OFFSET 20 typedef struct { host_mgreg_t res, res2; @@ -271,6 +273,8 @@ struct CallInfo { typedef struct { /* General registers + ARMREG_R8 for indirect returns */ host_mgreg_t gregs [PARAM_REGS + 1]; + /* Context registers in */ + host_mgreg_t cregs [CTX_REGS]; /* Floating registers */ double fregs [FP_PARAM_REGS]; /* Stack usage, used for passing params on stack */ diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 4924a0be9d4899..1592e238d9d310 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2544,7 +2544,7 @@ void mono_arch_notify_pending_exc (MonoThreadInfo *info); guint8* mono_arch_get_call_target (guint8 *code); guint32 mono_arch_get_plt_info_offset (guint8 *plt_entry, host_mgreg_t *regs, guint8 *code); GSList *mono_arch_get_trampolines (gboolean aot); -gpointer mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info); +gpointer mono_arch_get_interp_to_native_trampoline (MonoMethodSignature *sig, MonoTrampInfo **info); gpointer mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info); #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP @@ -2559,6 +2559,8 @@ void mono_arch_set_native_call_context_ret (CallContext *ccontext, gpointer gpointer mono_arch_get_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); // After the pinvoke call is done, this moves return value from the ccontext to the InterpFrame. void mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); +// After the pinvoke call is done, this stores an error context value from the ccontext to the InterpFrame. +void mono_arch_get_native_call_context_error (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); /* Free the structure returned by mono_arch_get_interp_native_call_info (NULL, sig) */ void mono_arch_free_interp_native_call_info (gpointer call_info); #endif diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index d26e16b2bbd322..728401e9873d43 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -653,7 +653,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo * See tramp-amd64.c for documentation. */ gpointer -mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) +mono_arch_get_interp_to_native_trampoline (MonoMethodSignature *sig, MonoTrampInfo **info) { #ifndef DISABLE_INTERPRETER guint8 *start = NULL, *code; @@ -718,6 +718,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < PARAM_REGS + 1; i++) arm_ldrx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + i * sizeof (host_mgreg_t)); + /* set all context registers from CallContext */ + if (sig && sig->call_convention == MONO_CALL_SWIFTCALL) { + for (i = 0; i < CTX_REGS; i++) + arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); + } + /* set all floating registers from CallContext */ for (i = 0; i < FP_PARAM_REGS; i++) arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); @@ -735,6 +741,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < PARAM_REGS; i++) arm_strx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + i * sizeof (host_mgreg_t)); + /* set all context registers to CallContext */ + if (sig && sig->call_convention == MONO_CALL_SWIFTCALL) { + for (i = 0; i < CTX_REGS; i++) + arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); + } + /* set all floating registers to CallContext */ for (i = 0; i < FP_PARAM_REGS; i++) arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); From 42680b1d3a4eda47984c44752551f5c6201cbd08 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 2 Nov 2023 21:37:32 +0100 Subject: [PATCH 027/137] [inter] Simplify Swift calling convention support Resolve commit comments. Remove a callback for stack indirect store and. Remove Swift-specific trampoline. --- src/mono/mono/mini/aot-compiler.c | 2 +- src/mono/mono/mini/ee.h | 1 - src/mono/mono/mini/interp-stubs.c | 6 ----- src/mono/mono/mini/interp/interp.c | 36 ++++++++++++------------------ src/mono/mono/mini/mini-arm64.c | 25 +++++++++------------ src/mono/mono/mini/mini-arm64.h | 4 ++-- src/mono/mono/mini/mini.h | 6 ++--- src/mono/mono/mini/tramp-arm64.c | 26 ++++++++++----------- 8 files changed, 44 insertions(+), 62 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 5fcbae5997405c..2cd2dbc234f21d 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -8387,7 +8387,7 @@ emit_trampolines (MonoAotCompile *acfg) } if (mono_aot_mode_is_interp (&acfg->aot_opts) && mono_is_corlib_image (acfg->image->assembly->image)) { - mono_arch_get_interp_to_native_trampoline (NULL, &info); + mono_arch_get_interp_to_native_trampoline (&info); emit_trampoline (acfg, info); #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE diff --git a/src/mono/mono/mini/ee.h b/src/mono/mono/mini/ee.h index c6f986403a449d..1e88e9aaaa9d81 100644 --- a/src/mono/mono/mini/ee.h +++ b/src/mono/mono/mini/ee.h @@ -51,7 +51,6 @@ typedef gpointer MonoInterpFrameHandle; MONO_EE_CALLBACK (gpointer, frame_get_this, (MonoInterpFrameHandle frame)) \ MONO_EE_CALLBACK (void, frame_arg_to_data, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)) \ MONO_EE_CALLBACK (void, data_to_frame_arg, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)) \ - MONO_EE_CALLBACK (void, data_to_frame_arg_indirect, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)) \ MONO_EE_CALLBACK (gpointer, frame_arg_to_storage, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)) \ MONO_EE_CALLBACK (MonoInterpFrameHandle, frame_get_parent, (MonoInterpFrameHandle frame)) \ MONO_EE_CALLBACK (void, start_single_stepping, (void)) \ diff --git a/src/mono/mono/mini/interp-stubs.c b/src/mono/mono/mini/interp-stubs.c index 58122081c43565..0ade0c95e0440d 100644 --- a/src/mono/mono/mini/interp-stubs.c +++ b/src/mono/mono/mini/interp-stubs.c @@ -203,12 +203,6 @@ stub_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, i g_assert_not_reached (); } -static void -stub_data_to_frame_arg_indirect (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data) -{ - g_assert_not_reached (); -} - static gpointer stub_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index) { diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 655a1a1cc03a19..0940176b144157 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1577,17 +1577,6 @@ interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, stackval_from_data (sig->params [index - sig->hasthis], STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)), data, sig->pinvoke && !sig->marshalling_disabled); } -static void -interp_data_to_frame_arg_indirect (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data) -{ - InterpFrame *iframe = (InterpFrame*)frame; - InterpMethod *imethod = iframe->imethod; - - // Perform an indirect store at index stack location - stackval *result = (stackval*) STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)); - *(gpointer*)result->data.p = *(gpointer*)data; -} - static gpointer interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index) { @@ -1601,16 +1590,16 @@ interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *s } static MonoPIFunc -get_interp_to_native_trampoline (MonoMethodSignature *sig) +get_interp_to_native_trampoline (void) { static MonoPIFunc trampoline = NULL; - if (!trampoline || sig) { + if (!trampoline) { if (mono_ee_features.use_aot_trampolines) { trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline"); } else { MonoTrampInfo *info; - trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (sig, &info); + trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info); mono_tramp_info_register (info, NULL); } mono_memory_barrier (); @@ -1621,7 +1610,7 @@ get_interp_to_native_trampoline (MonoMethodSignature *sig) static void interp_to_native_trampoline (gpointer addr, gpointer ccontext) { - get_interp_to_native_trampoline (NULL) (addr, ccontext); + get_interp_to_native_trampoline () (addr, ccontext); } /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */ @@ -1665,19 +1654,15 @@ ves_pinvoke_method ( *cache = entry_func; } #else - // The generic trampoline is cached in the static variable 'entry_func'. If a different calling convention is used, - // retrieve the generic trampoline again, as it may contain handling of context registers. static MonoPIFunc entry_func = NULL; - unsigned int call_conv = 0; - if (!entry_func || sig->call_convention != call_conv) { - call_conv = sig->call_convention; + if (!entry_func) { MONO_ENTER_GC_UNSAFE; #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX ERROR_DECL (error); entry_func = (MonoPIFunc) mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper ("mono_interp_to_native_trampoline", (gpointer) mono_interp_to_native_trampoline), error); mono_error_assert_ok (error); #else - entry_func = get_interp_to_native_trampoline (sig); + entry_func = get_interp_to_native_trampoline (); #endif mono_memory_barrier (); MONO_EXIT_GC_UNSAFE; @@ -1721,7 +1706,14 @@ ves_pinvoke_method ( #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP if (sig->call_convention == MONO_CALL_SWIFTCALL) { - mono_arch_get_native_call_context_error (&ccontext, &frame, sig, call_info); + int arg_index; + gpointer data = mono_arch_get_swift_error (&ccontext, sig, call_info, &arg_index); + + // Perform an indirect store at arg_index stack location + if (data != NULL) { + stackval *result = (stackval*) STACK_ADD_BYTES (frame.stack, get_arg_offset (frame.imethod, sig, arg_index)); + *(gpointer*)result->data.p = *(gpointer*)data; + } } if (!context->has_resume_state) { mono_arch_get_native_call_context_ret (&ccontext, &frame, sig, call_info); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 7d4fcba6124c51..52c9c4f19fb26b 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1924,7 +1924,7 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgInFReg: case ArgInFRegR4: case ArgHFA: - return &ccontext->fregs [ainfo->reg]; + return &ccontext->fregs [ainfo->reg]; case ArgOnStack: case ArgOnStackR4: case ArgOnStackR8: @@ -1934,8 +1934,8 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) return *(gpointer*)(ccontext->stack + ainfo->offset); case ArgVtypeByRef: return (gpointer) ccontext->gregs [ainfo->reg]; - default: - g_error ("Arg storage type not yet supported"); + default: + g_error ("Arg storage type not yet supported"); } } @@ -2130,27 +2130,24 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo /** * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. * - * The function searches for an argument with the storage type `ArgSwiftError`. If found, - * it retrieves the value from `ccontext` and indirectly stores it onto the stack of the current frame. + * The function searches for an argument with the storage type `ArgSwiftError`. + * If found, it retrieves the value from `ccontext`. */ -void -mono_arch_get_native_call_context_error (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info) +gpointer +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) { - const MonoEECallbacks *interp_cb; CallInfo *cinfo = (CallInfo*)call_info; ArgInfo *ainfo; - gpointer storage; - - interp_cb = mini_get_interp_callbacks (); for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { ainfo = &cinfo->args [i]; if (ainfo->storage == ArgSwiftError) { - storage = arg_get_storage (ccontext, ainfo); - interp_cb->data_to_frame_arg_indirect ((MonoInterpFrameHandle)frame, sig, i, storage); - break; + *arg_index = i; + return arg_get_storage (ccontext, ainfo); } } + + return NULL; } typedef struct { diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index c96a33bc78594a..8084de36b32ecc 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -273,10 +273,10 @@ struct CallInfo { typedef struct { /* General registers + ARMREG_R8 for indirect returns */ host_mgreg_t gregs [PARAM_REGS + 1]; - /* Context registers in */ - host_mgreg_t cregs [CTX_REGS]; /* Floating registers */ double fregs [FP_PARAM_REGS]; + /* Context registers */ + host_mgreg_t cregs [CTX_REGS]; /* Stack usage, used for passing params on stack */ guint32 stack_size; guint8* stack; diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 1592e238d9d310..656f21f303ea9b 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2544,7 +2544,7 @@ void mono_arch_notify_pending_exc (MonoThreadInfo *info); guint8* mono_arch_get_call_target (guint8 *code); guint32 mono_arch_get_plt_info_offset (guint8 *plt_entry, host_mgreg_t *regs, guint8 *code); GSList *mono_arch_get_trampolines (gboolean aot); -gpointer mono_arch_get_interp_to_native_trampoline (MonoMethodSignature *sig, MonoTrampInfo **info); +gpointer mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info); gpointer mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info); #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP @@ -2559,8 +2559,8 @@ void mono_arch_set_native_call_context_ret (CallContext *ccontext, gpointer gpointer mono_arch_get_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); // After the pinvoke call is done, this moves return value from the ccontext to the InterpFrame. void mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); -// After the pinvoke call is done, this stores an error context value from the ccontext to the InterpFrame. -void mono_arch_get_native_call_context_error (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); +// After the pinvoke call is done, this return an error context value from the ccontext. +gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index); /* Free the structure returned by mono_arch_get_interp_native_call_info (NULL, sig) */ void mono_arch_free_interp_native_call_info (gpointer call_info); #endif diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index 728401e9873d43..9487399cb00f32 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -653,7 +653,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo * See tramp-amd64.c for documentation. */ gpointer -mono_arch_get_interp_to_native_trampoline (MonoMethodSignature *sig, MonoTrampInfo **info) +mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) { #ifndef DISABLE_INTERPRETER guint8 *start = NULL, *code; @@ -718,16 +718,16 @@ mono_arch_get_interp_to_native_trampoline (MonoMethodSignature *sig, MonoTrampIn for (i = 0; i < PARAM_REGS + 1; i++) arm_ldrx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + i * sizeof (host_mgreg_t)); - /* set all context registers from CallContext */ - if (sig && sig->call_convention == MONO_CALL_SWIFTCALL) { - for (i = 0; i < CTX_REGS; i++) - arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); - } - /* set all floating registers from CallContext */ for (i = 0; i < FP_PARAM_REGS; i++) arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); +#ifdef CTX_REGS + /* set all context registers from CallContext */ + for (i = 0; i < CTX_REGS; i++) + arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); +#endif + /* load target addr */ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_targetaddr); @@ -741,16 +741,16 @@ mono_arch_get_interp_to_native_trampoline (MonoMethodSignature *sig, MonoTrampIn for (i = 0; i < PARAM_REGS; i++) arm_strx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + i * sizeof (host_mgreg_t)); - /* set all context registers to CallContext */ - if (sig && sig->call_convention == MONO_CALL_SWIFTCALL) { - for (i = 0; i < CTX_REGS; i++) - arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); - } - /* set all floating registers to CallContext */ for (i = 0; i < FP_PARAM_REGS; i++) arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); +#ifdef CTX_REGS + /* set all context registers to CallContext */ + for (i = 0; i < CTX_REGS; i++) + arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); +#endif + arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); arm_addx_imm (code, ARMREG_SP, ARMREG_SP, framesize); From 2cce70fdb1120b004f806cb54b7bcddca5ea43fe Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 2 Nov 2023 22:31:30 +0100 Subject: [PATCH 028/137] [mono] Add mini and interpreter support for swift calling convention on amd64 Update the mini x64 backend to handle swift context registers. Update interpreter managed to native trampoline to preserve context registers --- src/mono/mono/mini/mini-amd64.c | 78 ++++++++++++++++++++++++++++++-- src/mono/mono/mini/mini-amd64.h | 6 +++ src/mono/mono/mini/tramp-amd64.c | 12 +++++ 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 6278ae4b9aea7a..aab4f88a936f6e 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1077,6 +1077,22 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) default: g_assert_not_reached (); } + + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + MonoType *arg_type = sig->params[i]->data.type; + if (arg_type && arg_type->data.klass) { + const char *name_space = m_class_get_name_space(arg_type->data.klass); + const char *class_name = m_class_get_name(arg_type->data.klass); + + if (name_space && class_name && !strcmp(name_space, "System.Runtime.InteropServices.Swift")) { + if (!strcmp(class_name, "SwiftError")) { + ainfo->storage = ArgSwiftError; + } else if (!strcmp(class_name, "SwiftSelf")) { + ainfo->storage = ArgSwiftSelf; + } + } + } + } } if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) { @@ -1108,6 +1124,10 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) switch (ainfo->storage) { case ArgInIReg: return &ccontext->gregs [ainfo->reg]; + case ArgSwiftSelf: + return &ccontext->cregs [AMD64_R13 - CTX_REGS_OFFSET]; + case ArgSwiftError: + return &ccontext->cregs [AMD64_R12 - CTX_REGS_OFFSET]; case ArgInFloatSSEReg: case ArgInDoubleSSEReg: return &ccontext->fregs [ainfo->reg]; @@ -1360,6 +1380,29 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +/** + * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. + * + * The function searches for an argument with the storage type `ArgSwiftError`. + * If found, it retrieves the value from `ccontext`. + */ +gpointer +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) +{ + CallInfo *cinfo = (CallInfo*)call_info; + ArgInfo *ainfo; + + for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { + ainfo = &cinfo->args [i]; + if (ainfo->storage == ArgSwiftError) { + *arg_index = i; + return arg_get_storage (ccontext, ainfo); + } + } + + return NULL; +} + /* * mono_arch_get_argument_info: * @csig: a method signature @@ -1877,7 +1920,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) * are volatile across calls. * FIXME: Optimize this. */ - if ((ainfo->storage == ArgInIReg) || (ainfo->storage == ArgInFloatSSEReg) || (ainfo->storage == ArgInDoubleSSEReg) || (ainfo->storage == ArgValuetypeInReg) || (ainfo->storage == ArgGSharedVtInReg)) + if ((ainfo->storage == ArgInIReg) || (ainfo->storage == ArgInFloatSSEReg) || (ainfo->storage == ArgInDoubleSSEReg) || (ainfo->storage == ArgValuetypeInReg) || (ainfo->storage == ArgGSharedVtInReg) || (ainfo->storage == ArgSwiftError)) inreg = FALSE; ins->opcode = OP_REGOFFSET; @@ -1887,6 +1930,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInFloatSSEReg: case ArgInDoubleSSEReg: case ArgGSharedVtInReg: + case ArgSwiftError: if (inreg) { ins->opcode = OP_REGVAR; ins->dreg = ainfo->reg; @@ -1900,6 +1944,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->inst_offset = ainfo->offset + ARGS_OFFSET; break; case ArgValuetypeInReg: + case ArgSwiftSelf: break; case ArgValuetypeAddrInIReg: case ArgValuetypeAddrOnStack: { @@ -2006,6 +2051,7 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int re switch (storage) { case ArgInIReg: + case ArgSwiftError: MONO_INST_NEW (cfg, ins, OP_MOVE); ins->dreg = mono_alloc_ireg_copy (cfg, tree->dreg); ins->sreg1 = tree->dreg; @@ -2295,7 +2341,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) in = call->args [i]; - if (ainfo->storage == ArgInIReg) + if (ainfo->storage == ArgInIReg || ainfo->storage == ArgSwiftError) add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, in); } @@ -2314,6 +2360,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) switch (ainfo->storage) { case ArgInIReg: + case ArgSwiftError: /* Already done */ break; case ArgInFloatSSEReg: @@ -2325,7 +2372,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgValuetypeAddrInIReg: case ArgValuetypeAddrOnStack: case ArgGSharedVtInReg: - case ArgGSharedVtOnStack: { + case ArgGSharedVtOnStack: + case ArgSwiftSelf: { if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t)) /* Already emitted above */ break; @@ -8061,7 +8109,8 @@ MONO_RESTORE_WARNING /* Save volatile arguments to the stack */ if (ins->opcode != OP_REGVAR) { switch (ainfo->storage) { - case ArgInIReg: { + case ArgInIReg: + case ArgSwiftError: { guint32 size = 8; /* FIXME: I1 etc */ @@ -8095,6 +8144,7 @@ MONO_RESTORE_WARNING amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset, ainfo->reg); break; case ArgValuetypeInReg: + case ArgSwiftSelf: for (quad = 0; quad < 2; quad ++) { switch (ainfo->pair_storage [quad]) { case ArgInIReg: @@ -8112,6 +8162,10 @@ MONO_RESTORE_WARNING g_assert_not_reached (); } } + + if (ainfo->storage == ArgSwiftSelf) { + amd64_mov_reg_membase (code, AMD64_R13, ins->inst_basereg, ins->inst_offset, sizeof(gpointer)); + } break; case ArgValuetypeAddrInIReg: if (ainfo->pair_storage [0] == ArgInIReg) @@ -8129,6 +8183,7 @@ MONO_RESTORE_WARNING /* Argument allocated to (non-volatile) register */ switch (ainfo->storage) { case ArgInIReg: + case ArgSwiftError: amd64_mov_reg_reg (code, ins->dreg, ainfo->reg, 8); break; case ArgOnStack: @@ -8275,6 +8330,20 @@ mono_arch_emit_epilog (MonoCompile *cfg) code = realloc_code (cfg, max_epilog_size); + cinfo = cfg->arch.cinfo; + for (int i = 0; i < cinfo->nargs; ++i) { + ArgInfo* ainfo = cinfo->args + i; + MonoInst* arg = cfg->args [i]; + + switch (ainfo->storage) { + case ArgSwiftError: + amd64_mov_membase_reg (code, arg->dreg, 0, AMD64_R12, 8); + break; + default: + break; + } + } + cfg->has_unwind_info_for_epilog = TRUE; /* Mark the start of the epilog */ @@ -8311,7 +8380,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) } /* Load returned vtypes into registers if needed */ - cinfo = cfg->arch.cinfo; if (cinfo->ret.storage == ArgValuetypeInReg) { ArgInfo *ainfo = &cinfo->ret; MonoInst *inst = cfg->ret; diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 2c775c1585545b..b405f98c031750 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -236,6 +236,8 @@ static const AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 }; #define FLOAT_PARAM_REGS 8 #define RETURN_REGS 2 #define FLOAT_RETURN_REGS 2 +#define CTX_REGS 2 +#define CTX_REGS_OFFSET 12 static const AMD64_Reg_No param_regs [] = {AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9}; @@ -297,6 +299,8 @@ typedef enum { ArgGSharedVtOnStack, /* Variable sized gsharedvt argument passed/returned by addr */ ArgGsharedvtVariableInReg, + ArgSwiftError, + ArgSwiftSelf, ArgNone /* only in pair_storage */ } ArgStorage; @@ -338,6 +342,8 @@ typedef struct { host_mgreg_t gregs [AMD64_NREG]; /* Floating registers */ double fregs [AMD64_XMM_NREG]; + /* Context registers */ + host_mgreg_t cregs [CTX_REGS]; /* Stack usage, used for passing params on stack */ guint32 stack_size; guint8 *stack; diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 7d6282bd3e19d0..d8a18f86bd65f7 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1097,6 +1097,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_PARAM_REGS; ++i) amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); +#ifdef CTX_REGS + /* set all context registers from CallContext */ + for (i = 0; i < CTX_REGS; i++) + amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); +#endif + /* load target addr */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (target_mgreg_t)); @@ -1112,6 +1118,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_RETURN_REGS; i++) amd64_sse_movsd_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double), i); +#ifdef CTX_REGS + /* set all context registers to CallContext */ + for (i = 0; i < CTX_REGS; i++) + amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); +#endif + #if TARGET_WIN32 amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0); #else From a702f0d17c93d3b83418d53faf6d837664877d40 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 2 Nov 2023 22:32:24 +0100 Subject: [PATCH 029/137] [mono] Update Swift interop smoke test --- src/tests/Interop/Swift/ErrorHandling.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index aebb7fe09b57cf..9452683be9b5a8 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -1,11 +1,11 @@ import Foundation public enum MyError: Error { - case runtimeError(message: String, info: String) + case runtimeError(message: String) } public func someFuncThatMightThrow (willThrow: Bool, dummy: UnsafeRawPointer) throws -> Int { - if willThrow { throw MyError.runtimeError (message: "Catch me if you can!", info: "abcd abcd"); } + if willThrow { throw MyError.runtimeError (message: "Catch me if you can!"); } else { return 42; } } @@ -17,7 +17,7 @@ public func handleError(from pointer: UnsafePointer) { if let offsetErrorPointer = offsetPointer?.assumingMemoryBound(to: MyError.self) { let errorInstance = offsetErrorPointer.pointee switch errorInstance { - case .runtimeError(let message, _): + case .runtimeError(let message): print(message) } } else { From 5bc2693d6f154d5be642543438d53ea582046a9a Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 2 Nov 2023 22:38:52 +0100 Subject: [PATCH 030/137] [mono] Update Swift interop smoke test --- src/tests/Interop/Swift/ErrorHandling.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 9452683be9b5a8..345deee7e58de7 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -11,7 +11,7 @@ public func someFuncThatMightThrow (willThrow: Bool, dummy: UnsafeRawPointer) th public func handleError(from pointer: UnsafePointer) { let pointerValue = UInt(bitPattern: pointer) - let offsetPointerValue = pointerValue + 0x48 + let offsetPointerValue = pointerValue + 0x48 // 0x20 on amd64 let offsetPointer = UnsafeRawPointer(bitPattern: offsetPointerValue) if let offsetErrorPointer = offsetPointer?.assumingMemoryBound(to: MyError.self) { From 78b974ab2a0a688d35780ff666993165309733aa Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 3 Nov 2023 11:10:30 +0100 Subject: [PATCH 031/137] [mono] Add ArgSwiftError in emit_move_args --- src/mono/mono/mini/mini-arm64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 52c9c4f19fb26b..5fc737af9dd4f7 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -5761,6 +5761,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) if (ins->opcode == OP_REGVAR) { switch (ainfo->storage) { case ArgInIReg: + case ArgSwiftError: arm_movx (code, ins->dreg, ainfo->reg); if (i == 0 && sig->hasthis) { mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, GPTRDIFF_TO_INT (code - cfg->native_code)); From ece53c2bd2063b803c3cce8d2b4fc43691e2e40c Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 6 Nov 2023 12:17:40 +0100 Subject: [PATCH 032/137] Force ArgSwiftError to be allocated on stack --- src/mono/mono/mini/mini-arm64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 5fc737af9dd4f7..23295937c20d65 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2768,7 +2768,8 @@ mono_arch_allocate_vars (MonoCompile *cfg) ainfo = cinfo->args + i; ins = cfg->args [i]; - if (ins->opcode == OP_REGVAR) + /* We force the ArgSwiftError to be allocated to the stack slot because we need to retrieve it after the call */ + if (ins->opcode == OP_REGVAR && ainfo->storage != ArgSwiftError) continue; ins->opcode = OP_REGOFFSET; From a86248588b6c436d0ba94ea87f88e64e7d619da7 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 6 Nov 2023 12:43:32 +0100 Subject: [PATCH 033/137] Revert "[mono] Add ArgSwiftError in emit_move_args" This reverts commit 78b974ab2a0a688d35780ff666993165309733aa. --- src/mono/mono/mini/mini-arm64.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 23295937c20d65..8093d78e9f72ce 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -5762,7 +5762,6 @@ emit_move_args (MonoCompile *cfg, guint8 *code) if (ins->opcode == OP_REGVAR) { switch (ainfo->storage) { case ArgInIReg: - case ArgSwiftError: arm_movx (code, ins->dreg, ainfo->reg); if (i == 0 && sig->hasthis) { mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, GPTRDIFF_TO_INT (code - cfg->native_code)); From 6a5dda275c1802a79a4a40a651688111898c5359 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 6 Nov 2023 14:43:02 +0100 Subject: [PATCH 034/137] [mono] Add helper functions for checking for Swift context classes --- src/mono/mono/mini/method-to-ir.c | 22 +++++++++++----------- src/mono/mono/mini/mini-amd64.c | 26 +++++++++++++------------- src/mono/mono/mini/mini-arm64.c | 22 +++++++++++----------- src/mono/mono/mini/mini.h | 3 +++ src/mono/mono/mini/tramp-amd64.c | 4 ---- src/mono/mono/mini/tramp-arm64.c | 4 ---- 6 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index d3e7293372a935..ed093cf91be166 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7636,17 +7636,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b int swift_error_args = 0; int swift_self_args = 0; for (int i = 0; i < method->signature->param_count; ++i) { - MonoType *arg_type = method->signature->params [i]; - if (arg_type && arg_type->data.klass) { - const char *name_space = m_class_get_name_space(arg_type->data.klass); - const char *class_name = m_class_get_name(arg_type->data.klass); - - if (name_space && class_name && !strcmp(name_space, "System.Runtime.InteropServices.Swift")) { - if (!strcmp(class_name, "SwiftError")) { - swift_error_args++; - } else if (!strcmp(class_name, "SwiftSelf")) { - swift_self_args++; - } + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, + // allowing the trailing '*' character to be ignored. + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + if (swift_error && + !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && + !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + swift_error_args++; + } else if (klass == mono_class_try_get_swift_self_class ()) { + swift_self_args++; } } } diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index aab4f88a936f6e..2dd0de4d75c109 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1079,17 +1079,17 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (sig->call_convention == MONO_CALL_SWIFTCALL) { - MonoType *arg_type = sig->params[i]->data.type; - if (arg_type && arg_type->data.klass) { - const char *name_space = m_class_get_name_space(arg_type->data.klass); - const char *class_name = m_class_get_name(arg_type->data.klass); - - if (name_space && class_name && !strcmp(name_space, "System.Runtime.InteropServices.Swift")) { - if (!strcmp(class_name, "SwiftError")) { - ainfo->storage = ArgSwiftError; - } else if (!strcmp(class_name, "SwiftSelf")) { - ainfo->storage = ArgSwiftSelf; - } + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, + // allowing the trailing '*' character to be ignored. + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + if (swift_error && + !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && + !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + ainfo->storage = ArgSwiftError; + } else if (klass == mono_class_try_get_swift_self_class ()) { + ainfo->storage = ArgSwiftSelf; } } } @@ -1125,9 +1125,9 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgInIReg: return &ccontext->gregs [ainfo->reg]; case ArgSwiftSelf: - return &ccontext->cregs [AMD64_R13 - CTX_REGS_OFFSET]; + return &ccontext->cregs [ctx_regs [AMD64_R13]]; case ArgSwiftError: - return &ccontext->cregs [AMD64_R12 - CTX_REGS_OFFSET]; + return &ccontext->cregs [ctx_regs [AMD64_R12]]; case ArgInFloatSSEReg: case ArgInDoubleSSEReg: return &ccontext->fregs [ainfo->reg]; diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 8093d78e9f72ce..c410cbda84cb5d 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1871,17 +1871,17 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (sig->call_convention == MONO_CALL_SWIFTCALL) { - MonoType *arg_type = sig->params[pindex]->data.type; - if (arg_type && arg_type->data.klass) { - const char *name_space = m_class_get_name_space(arg_type->data.klass); - const char *class_name = m_class_get_name(arg_type->data.klass); - - if (name_space && class_name && !strcmp(name_space, "System.Runtime.InteropServices.Swift")) { - if (!strcmp(class_name, "SwiftError")) { - ainfo->storage = ArgSwiftError; - } else if (!strcmp(class_name, "SwiftSelf")) { - ainfo->storage = ArgSwiftSelf; - } + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); + if (klass) { + // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, + // allowing the trailing '*' character to be ignored. + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + if (swift_error && + !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && + !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + ainfo->storage = ArgSwiftError; + } else if (klass == mono_class_try_get_swift_self_class ()) { + ainfo->storage = ArgSwiftSelf; } } } diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 656f21f303ea9b..2dfcfb9a45769f 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2565,6 +2565,9 @@ gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignatu void mono_arch_free_interp_native_call_info (gpointer call_info); #endif +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + /*New interruption machinery */ void mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data); diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index d8a18f86bd65f7..5aba1edab58726 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1097,11 +1097,9 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_PARAM_REGS; ++i) amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); -#ifdef CTX_REGS /* set all context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); -#endif /* load target addr */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (target_mgreg_t)); @@ -1118,11 +1116,9 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_RETURN_REGS; i++) amd64_sse_movsd_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double), i); -#ifdef CTX_REGS /* set all context registers to CallContext */ for (i = 0; i < CTX_REGS; i++) amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); -#endif #if TARGET_WIN32 amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0); diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index 9487399cb00f32..58483b9842e985 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -722,11 +722,9 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); -#ifdef CTX_REGS /* set all context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); -#endif /* load target addr */ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_targetaddr); @@ -745,11 +743,9 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); -#ifdef CTX_REGS /* set all context registers to CallContext */ for (i = 0; i < CTX_REGS; i++) arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); -#endif arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); From e2b6fe9cb86f87a6f75c89b0419ece4391e70079 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 6 Nov 2023 14:45:17 +0100 Subject: [PATCH 035/137] [mono] Fix ArgSwift registers index --- src/mono/mono/mini/mini-amd64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 2dd0de4d75c109..96937cbab0d8e8 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1125,9 +1125,9 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgInIReg: return &ccontext->gregs [ainfo->reg]; case ArgSwiftSelf: - return &ccontext->cregs [ctx_regs [AMD64_R13]]; + return &ccontext->cregs [AMD64_R13 - CTX_REGS_OFFSET]; case ArgSwiftError: - return &ccontext->cregs [ctx_regs [AMD64_R12]]; + return &ccontext->cregs [AMD64_R12 - CTX_REGS_OFFSET]; case ArgInFloatSSEReg: case ArgInDoubleSSEReg: return &ccontext->fregs [ainfo->reg]; From b3cb4cb93f5ac7d9bb8ceeb8f1fa4cb789682e9a Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 13:08:28 +0100 Subject: [PATCH 036/137] [mono] Avoid allocating context registers on arm64 --- src/mono/mono/mini/interp/transform.c | 29 +++++++++++++++++++++++++++ src/mono/mono/mini/method-to-ir.c | 17 ++++++++++------ src/mono/mono/mini/mini-arm64.c | 21 +++++++++++++++++-- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 75eae66996c6a3..a9fbae835ab05f 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3726,6 +3726,35 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int *call_args = create_call_args (td, num_args); + if (csignature->call_convention == MONO_CALL_SWIFTCALL) { + MonoClass *swift_error = mono_class_try_get_swift_error_class(); + MonoClass *swift_self = mono_class_try_get_swift_self_class(); + int swift_error_args = 0, swift_self_args = 0; + for (int i = 0; i < csignature->param_count; ++i) { + MonoClass *klass = mono_class_from_mono_type_internal (csignature->params [i]); + if (klass) { + // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, + // allowing the trailing '*' character to be ignored. + if (swift_error && + !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && + !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + if (strcmp (m_class_get_name (klass), "SwiftError*")) { + swift_error_args = swift_self_args = 0; + mono_error_set_invalid_program (error, "SwiftError argument must be a reference."); + return FALSE; + } + swift_error_args++; + } else if (klass == swift_self) { + swift_self_args++; + } + } + } + if (swift_self_args > 1 || swift_error_args > 1) { + mono_error_set_invalid_program (error, "Method signature contains multiple SwiftSelf/SwiftError arguments."); + return FALSE; + } + } + // We overwrite it with the return local, save it for future use if (csignature->param_count || csignature->hasthis) first_sreg = td->sp [0].local; diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index ed093cf91be166..6d62538f526790 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7632,20 +7632,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } } - if (method->signature->call_convention == MONO_CALL_SWIFTCALL) { - int swift_error_args = 0; - int swift_self_args = 0; - for (int i = 0; i < method->signature->param_count; ++i) { + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + MonoClass *swift_error = mono_class_try_get_swift_error_class(); + MonoClass *swift_self = mono_class_try_get_swift_self_class(); + int swift_error_args = 0, swift_self_args = 0; + for (int i = 0; i < sig->param_count; ++i) { MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass) { // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, // allowing the trailing '*' character to be ignored. - MonoClass *swift_error = mono_class_try_get_swift_error_class (); if (swift_error && !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + if (strcmp (m_class_get_name (klass), "SwiftError*")) { + swift_error_args = swift_self_args = 0; + mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("SwiftError argument must be a reference.")); + break; + } swift_error_args++; - } else if (klass == mono_class_try_get_swift_self_class ()) { + } else if (klass == swift_self) { swift_self_args++; } } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index c410cbda84cb5d..5f2dbbd067cc23 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2020,6 +2020,10 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M storage = ccontext->stack + ainfo->offset; *(gpointer*)storage = interp_cb->frame_arg_to_storage (frame, sig, i); continue; + } else if (ainfo->storage == ArgSwiftError) { + storage = arg_get_storage (ccontext, ainfo); + *(gpointer*)storage = 0; + continue; } int temp_size = arg_need_temp (ainfo); @@ -2601,8 +2605,10 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* r28 is reserved for cfg->arch.args_reg */ /* r27 is reserved for the imt argument */ - for (i = ARMREG_R19; i <= ARMREG_R26; ++i) - regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); + for (i = ARMREG_R19; i <= ARMREG_R26; ++i) { + if (!(cfg->method->signature->call_convention == MONO_CALL_SWIFTCALL && (i == ARMREG_R20 || i == ARMREG_R21))) + regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); + } return regs; } @@ -2707,6 +2713,13 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->used_int_regs |= 1 << ARMREG_R28; } + if (sig->call_convention == MONO_CALL_SWIFTCALL) { + g_assert (!(cfg->used_int_regs & (1 << ARMREG_R20))); + cfg->used_int_regs |= 1 << ARMREG_R20; + g_assert (!(cfg->used_int_regs & (1 << ARMREG_R21))); + cfg->used_int_regs |= 1 << ARMREG_R21; + } + if (cfg->method->save_lmf) { /* The LMF var is allocated normally */ } else { @@ -5810,6 +5823,10 @@ emit_move_args (MonoCompile *cfg, guint8 *code) mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, GPTRDIFF_TO_INT (code - cfg->native_code)); mono_add_var_location (cfg, ins, FALSE, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset), GPTRDIFF_TO_INT (code - cfg->native_code), 0); } + + if (ainfo->storage == ArgSwiftError) { + code = emit_imm (code, ARMREG_R21, 0); + } break; case ArgInFReg: code = emit_strfpx (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); From 68ad76d2e408b02f272887bb6524f5f04172cb36 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 13:09:55 +0100 Subject: [PATCH 037/137] [mono] Add smoke tests for Swift calling convention --- src/tests/Interop/Swift/Dummy.swift | 1 + src/tests/Interop/Swift/ErrorHandling.cs | 53 +++++++++++++++---- src/tests/Interop/Swift/ErrorHandling.swift | 36 ++++++++++--- src/tests/Interop/Swift/InvalidCallingConv.cs | 51 ++++++++++++++++++ src/tests/Interop/Swift/SelfContext.cs | 22 ++++---- src/tests/Interop/Swift/SelfContext.swift | 18 +++---- src/tests/Interop/Swift/SwiftInterop.csproj | 1 + 7 files changed, 142 insertions(+), 40 deletions(-) create mode 100644 src/tests/Interop/Swift/Dummy.swift create mode 100644 src/tests/Interop/Swift/InvalidCallingConv.cs diff --git a/src/tests/Interop/Swift/Dummy.swift b/src/tests/Interop/Swift/Dummy.swift new file mode 100644 index 00000000000000..d2326a105fe9af --- /dev/null +++ b/src/tests/Interop/Swift/Dummy.swift @@ -0,0 +1 @@ +public func dummyFunc() { } \ No newline at end of file diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/ErrorHandling.cs index 552888179c8e2b..17051d52403dcc 100644 --- a/src/tests/Interop/Swift/ErrorHandling.cs +++ b/src/tests/Interop/Swift/ErrorHandling.cs @@ -2,28 +2,59 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Swift; +using System.Text; using Xunit; public class ErrorHandlingTests { + private const string SwiftLib = "libErrorHandling.dylib"; + + [DllImport(SwiftLib, EntryPoint = "$s13ErrorHandling05setMyA7Message5bytes6lengthySPys5UInt8VG_SitF")] + public static extern void SetErrorMessage(byte[] strBytes, int length); + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling22someFuncThatMightThrow04willG05dummySiSb_SVtKF")] - public unsafe static extern nint SomeFuncThatMightThrow (bool willThrow, SwiftError* error); + [DllImport(SwiftLib, EntryPoint = "$s13ErrorHandling018conditionallyThrowA004willD0SiSb_tKF")] + public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); - [DllImport("libErrorHandling.dylib", EntryPoint = "$s13ErrorHandling06handleA04fromySPyAA02MyA0OG_tF")] - public static extern void handleError (IntPtr handle); + [DllImport(SwiftLib, EntryPoint = "$s13ErrorHandling05getMyA7Message4fromSPys5UInt8VGSgSPyAA0dA0OG_tF")] + public static extern IntPtr GetErrorMessage(IntPtr handle); [Fact] public unsafe static int TestEntryPoint() { - SwiftError errorHandle = new SwiftError(); - SomeFuncThatMightThrow(true, &errorHandle); - if (errorHandle.Value != IntPtr.Zero) { - Console.WriteLine($"Error instance from R21: 0x{errorHandle.Value:X16}"); - handleError(errorHandle.Value); - return 100; - } else { + const string expectedErrorMessage = "Catch me if you can!"; + SetErrorMessageForSwift(expectedErrorMessage); + + SwiftError error; + + // This will throw an error + conditionallyThrowError(true, &error); + if (error.Value == IntPtr.Zero) { return 101; } + string errorMessage = GetErrorMessageFromSwift(error, expectedErrorMessage.Length); + Assert.Equal(expectedErrorMessage, errorMessage); + + // This will not throw an error + int result = (int) conditionallyThrowError(false, &error); + if (error.Value != IntPtr.Zero) { + return 102; + } + Assert.Equal(42, result); + return 100; + } + + private static void SetErrorMessageForSwift(string message) + { + var messageBytes = Encoding.UTF8.GetBytes(message); + SetErrorMessage(messageBytes, messageBytes.Length); + } + + private static string GetErrorMessageFromSwift(SwiftError error, int length) + { + IntPtr pointer = GetErrorMessage(error.Value); + byte[] byteArray = new byte[length]; + Marshal.Copy(pointer, byteArray, 0, length); + return Encoding.UTF8.GetString(byteArray); } } diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 345deee7e58de7..808ae506103cc6 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -4,24 +4,44 @@ public enum MyError: Error { case runtimeError(message: String) } -public func someFuncThatMightThrow (willThrow: Bool, dummy: UnsafeRawPointer) throws -> Int { - if willThrow { throw MyError.runtimeError (message: "Catch me if you can!"); } - else { return 42; } +var errorMessage: String = "" + +public func setMyErrorMessage(bytes: UnsafePointer, length: Int) { + let data = Data(bytes: bytes, count: length) + errorMessage = String(data: data, encoding: .utf8)! +} + +public func conditionallyThrowError(willThrow: Bool) throws -> Int { + if willThrow { + throw MyError.runtimeError(message: errorMessage) + } else { + return 42 + } } -public func handleError(from pointer: UnsafePointer) { +public func getMyErrorMessage(from pointer: UnsafePointer) -> UnsafePointer? { let pointerValue = UInt(bitPattern: pointer) - let offsetPointerValue = pointerValue + 0x48 // 0x20 on amd64 + var offsetValue: UInt +#if arch(arm64) + offsetValue = 0x48 +#elseif (x86_64) + offsetValue = 0x20 +#else + fatalError("Unsupported architecture") +#endif + let offsetPointerValue = pointerValue + offsetValue let offsetPointer = UnsafeRawPointer(bitPattern: offsetPointerValue) if let offsetErrorPointer = offsetPointer?.assumingMemoryBound(to: MyError.self) { let errorInstance = offsetErrorPointer.pointee switch errorInstance { case .runtimeError(let message): - print(message) + let messageBytes: [UInt8] = Array(message.utf8) + let buffer = UnsafeMutableBufferPointer.allocate(capacity: messageBytes.count) + _ = buffer.initialize(from: messageBytes) + return UnsafePointer(buffer.baseAddress!) } } else { - print("Pointer does not point to MyError.") + return nil } - } diff --git a/src/tests/Interop/Swift/InvalidCallingConv.cs b/src/tests/Interop/Swift/InvalidCallingConv.cs new file mode 100644 index 00000000000000..e83d8ff9c15067 --- /dev/null +++ b/src/tests/Interop/Swift/InvalidCallingConv.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Swift; +using Xunit; + +public class InvalidCallingConvTests +{ + private const string SwiftLib = "dummy.dylib"; + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] + public static extern nint DummyFunc1(SwiftSelf self1, SwiftSelf self2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] + public unsafe static extern nint DummyFunc2(SwiftError* error1, SwiftError* error2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] + public unsafe static extern nint DummyFunc3(SwiftSelf self1, SwiftSelf self2, SwiftError* error1, SwiftError* error2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] + public static extern nint DummyFunc4(SwiftError error1); + + [Fact] + public unsafe static int TestEntryPoint() + { + SwiftSelf self = new SwiftSelf(IntPtr.Zero); + SwiftError error = new SwiftError(IntPtr.Zero); + + try { + DummyFunc1(self, self); + return 101; + } catch (InvalidProgramException e) { } + try { + DummyFunc2(&error, &error); + return 102; + } catch (InvalidProgramException e) { } + try { + DummyFunc3(self, self, &error, &error); + return 103; + } catch (InvalidProgramException e) { } + try { + DummyFunc4(error); + return 104; + } catch (InvalidProgramException e) { } + return 100; + } +} diff --git a/src/tests/Interop/Swift/SelfContext.cs b/src/tests/Interop/Swift/SelfContext.cs index 4f880d37daa827..184a71afad199b 100644 --- a/src/tests/Interop/Swift/SelfContext.cs +++ b/src/tests/Interop/Swift/SelfContext.cs @@ -6,25 +6,27 @@ public class SelfContextTests { - [DllImport("libSelfContext.dylib", EntryPoint = "$s11SelfContext11MathLibraryC11getInstanceSvyFZ")] + private const string SwiftLib = "libSelfContext.dylib"; + + [DllImport(SwiftLib, EntryPoint = "$s11SelfContext0A7LibraryC11getInstanceSvyFZ")] public static extern IntPtr getInstance(); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport("libSelfContext.dylib", EntryPoint = "$s11SelfContext11MathLibraryC14getMagicNumber5dummyySV_tF")] - public static extern void getMagicNumber(SwiftSelf handle); + [DllImport(SwiftLib, EntryPoint = "$s11SelfContext0A7LibraryC14getMagicNumberSiyF")] + public static extern nint getMagicNumber(SwiftSelf self); [Fact] public static int TestEntryPoint() { - IntPtr handle = getInstance(); - SwiftSelf selfHandle = new SwiftSelf(handle); + IntPtr pointer = getInstance(); + SwiftSelf self = new SwiftSelf(pointer); - if (selfHandle.Value != IntPtr.Zero) { - Console.WriteLine($"Self instance: 0x{selfHandle.Value:X16}"); - getMagicNumber (selfHandle); - return 100; - } else { + if (self.Value == IntPtr.Zero) { return 101; } + + int result = (int) getMagicNumber(self); + Assert.Equal(42, result); + return 100; } } diff --git a/src/tests/Interop/Swift/SelfContext.swift b/src/tests/Interop/Swift/SelfContext.swift index 2facc1bd707437..b6e21b2de97d6c 100644 --- a/src/tests/Interop/Swift/SelfContext.swift +++ b/src/tests/Interop/Swift/SelfContext.swift @@ -1,19 +1,15 @@ -public class MathLibrary { - public var a: Double - public var b: Double +public class SelfLibrary { + public var number: Int + public static let shared = SelfLibrary(number: 42) - public static let shared = MathLibrary(a: 40.0, b: 2.0) - - private init(a: Double, b: Double) { - self.a = a - self.b = b + private init(number: Int) { + self.number = number } - public func getMagicNumber(dummy: UnsafeRawPointer) { - print(a + b) + public func getMagicNumber() -> Int { + return self.number } - public static func getInstance() -> UnsafeMutableRawPointer { let unmanagedInstance = Unmanaged.passUnretained(shared) let pointer = unmanagedInstance.toOpaque() diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInterop.csproj index 0fe5aaf3e02028..063041e1675e8e 100644 --- a/src/tests/Interop/Swift/SwiftInterop.csproj +++ b/src/tests/Interop/Swift/SwiftInterop.csproj @@ -7,5 +7,6 @@ + From 1efac9d929d9ed0f79e56ecbffe1d969c207c22c Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 14:53:55 +0100 Subject: [PATCH 038/137] [mono] Avoid allocating context registers on x64 --- src/mono/mono/mini/mini-amd64.c | 20 ++++++++++++++++---- src/tests/Interop/Swift/ErrorHandling.swift | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 96937cbab0d8e8..8cf17dc5307649 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1260,6 +1260,10 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M storage = arg_get_storage (ccontext, ainfo); *(gpointer *)storage = interp_cb->frame_arg_to_storage (frame, sig, i); continue; + } else if (ainfo->storage == ArgSwiftError) { + storage = arg_get_storage (ccontext, ainfo); + *(gpointer*)storage = 0; + continue; } int temp_size = arg_need_temp (ainfo); @@ -1666,8 +1670,10 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* We use the callee saved registers for global allocation */ regs = g_list_prepend (regs, (gpointer)AMD64_RBX); - regs = g_list_prepend (regs, (gpointer)AMD64_R12); - regs = g_list_prepend (regs, (gpointer)AMD64_R13); + if (cfg->method->signature->call_convention != MONO_CALL_SWIFTCALL) { + regs = g_list_prepend (regs, (gpointer)AMD64_R12); + regs = g_list_prepend (regs, (gpointer)AMD64_R13); + } regs = g_list_prepend (regs, (gpointer)AMD64_R14); regs = g_list_prepend (regs, (gpointer)AMD64_R15); #ifdef TARGET_WIN32 @@ -1907,7 +1913,8 @@ mono_arch_allocate_vars (MonoCompile *cfg) for (guint i = 0; i < sig->param_count + sig->hasthis; ++i) { ins = cfg->args [i]; - if (ins->opcode != OP_REGVAR) { + /* We force the ArgSwiftError to be allocated to the stack slot because we need to retrieve it after the call */ + if (ins->opcode != OP_REGVAR || cinfo->args [i].storage == ArgSwiftError) { ArgInfo *ainfo = &cinfo->args [i]; gboolean inreg = TRUE; @@ -8135,6 +8142,10 @@ MONO_RESTORE_WARNING mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, GPTRDIFF_TO_INT (code - cfg->native_code)); mono_add_var_location (cfg, ins, FALSE, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset), GPTRDIFF_TO_INT (code - cfg->native_code), 0); } + + if (ainfo->storage == ArgSwiftError) { + amd64_mov_reg_imm (code, AMD64_R12, 0); + } break; } case ArgInFloatSSEReg: @@ -8337,7 +8348,8 @@ mono_arch_emit_epilog (MonoCompile *cfg) switch (ainfo->storage) { case ArgSwiftError: - amd64_mov_membase_reg (code, arg->dreg, 0, AMD64_R12, 8); + amd64_mov_reg_membase (code, AMD64_R11, arg->inst_basereg, arg->inst_offset, 8); + amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, 8); break; default: break; diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 808ae506103cc6..4c45ff6276d9c1 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -24,7 +24,7 @@ public func getMyErrorMessage(from pointer: UnsafePointer) -> UnsafePoi var offsetValue: UInt #if arch(arm64) offsetValue = 0x48 -#elseif (x86_64) +#elseif arch(x86_64) offsetValue = 0x20 #else fatalError("Unsupported architecture") From 74dc8c95bca497e2dc722ea2b029672d7fa79be8 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 16:06:06 +0100 Subject: [PATCH 039/137] [mono] Simplify interp support for amd64 --- src/mono/mono/mini/mini-amd64.c | 4 ++-- src/mono/mono/mini/mini-amd64.h | 5 ++--- src/mono/mono/mini/tramp-amd64.c | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 8cf17dc5307649..d0b306c6c36e07 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1125,9 +1125,9 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgInIReg: return &ccontext->gregs [ainfo->reg]; case ArgSwiftSelf: - return &ccontext->cregs [AMD64_R13 - CTX_REGS_OFFSET]; + return &ccontext->gregs [AMD64_R13]; case ArgSwiftError: - return &ccontext->cregs [AMD64_R12 - CTX_REGS_OFFSET]; + return &ccontext->gregs [AMD64_R12]; case ArgInFloatSSEReg: case ArgInDoubleSSEReg: return &ccontext->fregs [ainfo->reg]; diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index b405f98c031750..2a2aeeaaa2ee3a 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -237,7 +237,6 @@ static const AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 }; #define RETURN_REGS 2 #define FLOAT_RETURN_REGS 2 #define CTX_REGS 2 -#define CTX_REGS_OFFSET 12 static const AMD64_Reg_No param_regs [] = {AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9}; @@ -247,6 +246,8 @@ static const AMD64_XMM_Reg_No float_param_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD6 AMD64_XMM6, AMD64_XMM7}; static const AMD64_Reg_No return_regs [] = {AMD64_RAX, AMD64_RDX}; + +static const AMD64_Reg_No ctx_regs [] = {AMD64_R12, AMD64_R13}; #endif typedef struct { @@ -342,8 +343,6 @@ typedef struct { host_mgreg_t gregs [AMD64_NREG]; /* Floating registers */ double fregs [AMD64_XMM_NREG]; - /* Context registers */ - host_mgreg_t cregs [CTX_REGS]; /* Stack usage, used for passing params on stack */ guint32 stack_size; guint8 *stack; diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 5aba1edab58726..26babb6aa8c87e 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1099,7 +1099,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* set all context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) - amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); + amd64_mov_reg_membase (code, ctx_regs [i], AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + ctx_regs [i] * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); /* load target addr */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (target_mgreg_t)); @@ -1118,7 +1118,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* set all context registers to CallContext */ for (i = 0; i < CTX_REGS; i++) - amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + ctx_regs [i] * sizeof (target_mgreg_t), ctx_regs [i], sizeof (target_mgreg_t)); #if TARGET_WIN32 amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0); From fd1b036dc6d444dc5bbfb0148a8fd606b99a2203 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 16:33:01 +0100 Subject: [PATCH 040/137] Exclude coreclr runtime flavor --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 45e23266330ba6..d0ea9efc9de817 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -75,6 +75,9 @@ https://github.com/dotnet/runtime/issues/88586 + + https://github.com/dotnet/runtime/issues/93631 + From 458c1e42bbf860ad066f73c606395bc90278618a Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 16:36:58 +0100 Subject: [PATCH 041/137] Update README.md --- src/tests/Interop/Swift/README.md | 145 +----------------------------- 1 file changed, 3 insertions(+), 142 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index d3a278a928760e..f7f85decfc4708 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -72,149 +72,9 @@ We can choose to first support Mono AOT either with or without LLVM according to ## Tasks -Templates are used to set the definition of done (DoD) and contains of a set of unit tests that will be be implemented. Each unit test is designed to cover a specific invocation type using different input types. In the first iteration of the experiment, we want to focus on blittable types targeting MacCatalyst only. Later, we plan to include support for non-blittable types and other Apple targets. +Progress on the implementation can be tracked at https://github.com/dotnet/runtime/issues/93631. -Here's the flow for invoking a Swift function from .NET if a developer uses a direct P/Invoke and mangled names: -1. Function parameters should be automatically marshalled without any wrappers -2. A thunk should be emitted to handle the `self` and `error` registers -3. The result should be retrieved from the register, stack, or indirectly -4. An error should be thrown if the `error` register is set -5. Cleanup may be required - -### Type marshalling and metadata conversions - -Type marshalling should ideally be automated, with an initial focus on supporting blittable types. Later, we can extend support to include non-blittable types. Here are some tasks (not a full list): - - Create a mapping between C# and Swift types - - Investigate and determine which types lack marshalling support - - Investigate and determine how to generate types metadata - - -This is the simplest case that should be implemented. It should be expanded with other types. - -```swift -public static func add(_ a: Double, _ b: Double) -> Double { - return a + b -} - -public static func subtract(_ a: Double, _ b: Double) -> Double { - return a - b -} -``` - -### Self context - -In order to support Swift calling convention, it is necessary to implement register handling by emitting thunks in the above-mentioned cases. - -```swift -public func factorial() -> Int { - guard _internalValue >= 0 else { - fatalError("Factorial is undefined for negative numbers") - } - return _internalValue == 0 ? 1 : _internalValue * MathLibrary(_internalValue: _internalValue - 1).factorial() -} -``` - -### Error handling - -In order to support Swift calling convention, it is necessary to implement error handling by emitting thunks in the above-mentioned cases. - -### Async context - -When an async function is invoked, its context is stored into a register which points to an object that contains information about the current state of the asynchronous operation. - -### Update Binding Tools for Swift to work with latest version of Mono runtime - -We should update the Binding Tools for Swift to be compatible with the latest version of the Mono runtime and Xcode. - -## Other examples - -### Function with default params - -Nice to have. When Swift compiles them it leaves the initialization expression behind for the compiler to consume later. It's effectively a weak macro that gets expanded later so that the compiler can potentially optimize it. - -```swift -public static func multiply(_ a: Double, _ b: Double = 1.0) -> Double { - return a * b -} -``` - -### Function with varargs - -Nice to have. The semantics for parameters being `f(name0: type0, name1: type1, name2: type2)`, Swift lets you do `f(a: Int..., b: Float..., c: String...)` which gets turned into `f(a: Int[], b: Float[], c: String[])` - -```swift -public static func average(numbers: Double...) -> Double { - let sum = numbers.reduce(0, +) - return sum / Double(numbers.count) -} -``` - -### Function with closures -```swift -public static func applyOperation(a: Double, b: Double, operation: (Double, Double) -> Double) -> Double { - return operation(a, b) -} -``` - -### Computed properties -```swift -public static var circleArea: (Double) -> Double = { radius in - return Double.pi * radius * radius -} -``` - -### Initializers/Deinitializers -```swift -public init(_internalValue: Int) { - self._internalValue = _internalValue - print("MathLibrary initialized.") -} - -deinit { - print("MathLibrary deinitialized.") -} -``` - -### Getters/Setters -```swift -private var _internalValue: Int = 0 - -public var value: Int { - get { - return _internalValue - } - set { - _internalValue = newValue - } -} -``` - -### Delegates/Protocols -```swift -public protocol MathLibraryDelegate: AnyObject { - func mathLibraryDidInitialize() - func mathLibraryDidDeinitialize() -} -... -public weak var delegate: MathLibraryDelegate? - -public init(_internalValue: Int) { - self._internalValue = _internalValue - print("MathLibrary initialized.") - - // Notify the delegate that the library was initialized - delegate?.mathLibraryDidInitialize() -} - -deinit { - print("MathLibrary deinitialized.") - - // Notify the delegate that the library was deinitialized - delegate?.mathLibraryDidDeinitialize() -} -``` - -## Build steps +## Local build and testing Build the runtime: ```sh @@ -232,6 +92,7 @@ Build the native library: ```sh swiftc -emit-library ./src/tests/Interop/Swift/ErrorHandling.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libErrorHandling.dylib swiftc -emit-library ./src/tests/Interop/Swift/SelfContext.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libSelfContext.dylib +swiftc -emit-library ./src/tests/Interop/Swift/Dummy.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libDummy.dylib ``` Run the tests: ``` From 29399966a9fc8a693e8492a180b69df049ffe855 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 16:38:11 +0100 Subject: [PATCH 042/137] Remove helper script --- src/tests/Interop/Swift/demangle_symbols.sh | 9 --------- 1 file changed, 9 deletions(-) delete mode 100755 src/tests/Interop/Swift/demangle_symbols.sh diff --git a/src/tests/Interop/Swift/demangle_symbols.sh b/src/tests/Interop/Swift/demangle_symbols.sh deleted file mode 100755 index 549c0c662fa9c8..00000000000000 --- a/src/tests/Interop/Swift/demangle_symbols.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Get symbols using nm -nm $1 > symbols.txt - -# Strip _$ and demangle -cat symbols.txt | awk '{print $3}' | sed 's/_$//g' | xargs -I {} xcrun swift-demangle {} > demangled_symbols.txt - -echo "Demangled symbols are exported to demangled_symbols.txt." \ No newline at end of file From 8298058d2e411ff620fee7c2c83e61b19b0aecbe Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 7 Nov 2023 22:43:51 +0100 Subject: [PATCH 043/137] [mono] Simplify arguments check with helper macros --- src/mono/mono/metadata/class-internals.h | 19 +++++++++++++++++++ src/mono/mono/mini/interp/transform.c | 22 +++++++++------------- src/mono/mono/mini/method-to-ir.c | 22 +++++++++------------- src/mono/mono/mini/mini-amd64.c | 11 ++++------- src/mono/mono/mini/mini-arm64.c | 11 ++++------- src/mono/mono/mini/mini.h | 1 + 6 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index f9647d12aec216..967ecd425e5f98 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -978,6 +978,25 @@ mono_class_try_get_##shortname##_class (void) \ return klass; \ } + +#define GENERATE_TRY_GET_CLASS_REF_WITH_CACHE(shortname,name_space,name) \ +MonoClass* \ +mono_class_try_get_##shortname##_class (void) \ +{ \ + static volatile MonoClass *tmp_class; \ + static volatile gboolean inited; \ + MonoClass *klass = (MonoClass *)tmp_class; \ + mono_memory_barrier (); \ + if (!inited) { \ + klass = mono_class_try_load_from_name (mono_class_generate_get_corlib_impl (), name_space, name); \ + klass = mono_class_create_ptr (m_class_get_byval_arg (klass)); \ + tmp_class = klass; \ + mono_memory_barrier (); \ + inited = TRUE; \ + } \ + return klass; \ +} + GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (safehandle) #ifndef DISABLE_COM diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index a9fbae835ab05f..038d20a01893af 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3727,23 +3727,19 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int *call_args = create_call_args (td, num_args); if (csignature->call_convention == MONO_CALL_SWIFTCALL) { - MonoClass *swift_error = mono_class_try_get_swift_error_class(); - MonoClass *swift_self = mono_class_try_get_swift_self_class(); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; for (int i = 0; i < csignature->param_count; ++i) { MonoClass *klass = mono_class_from_mono_type_internal (csignature->params [i]); if (klass) { - // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, - // allowing the trailing '*' character to be ignored. - if (swift_error && - !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && - !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { - if (strcmp (m_class_get_name (klass), "SwiftError*")) { - swift_error_args = swift_self_args = 0; - mono_error_set_invalid_program (error, "SwiftError argument must be a reference."); - return FALSE; - } - swift_error_args++; + if (klass == swift_error) { + swift_error_args = swift_self_args = 0; + mono_error_set_invalid_program (error, "SwiftError argument must be a reference."); + return FALSE; + } else if (klass == swift_error_ptr) { + swift_self_args++; } else if (klass == swift_self) { swift_self_args++; } diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 6d62538f526790..f101190c645ec7 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7633,23 +7633,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } if (sig->call_convention == MONO_CALL_SWIFTCALL) { - MonoClass *swift_error = mono_class_try_get_swift_error_class(); - MonoClass *swift_self = mono_class_try_get_swift_self_class(); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; for (int i = 0; i < sig->param_count; ++i) { MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass) { - // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, - // allowing the trailing '*' character to be ignored. - if (swift_error && - !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && - !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { - if (strcmp (m_class_get_name (klass), "SwiftError*")) { - swift_error_args = swift_self_args = 0; - mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("SwiftError argument must be a reference.")); - break; - } - swift_error_args++; + if (klass == swift_error) { + swift_error_args = swift_self_args = 0; + mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("SwiftError argument must be a reference.")); + break; + } else if (klass == swift_error_ptr) { + swift_self_args++; } else if (klass == swift_self) { swift_self_args++; } diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index d0b306c6c36e07..c346055d35dde3 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1079,16 +1079,13 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (sig->call_convention == MONO_CALL_SWIFTCALL) { + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass) { - // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, - // allowing the trailing '*' character to be ignored. - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - if (swift_error && - !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && - !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + if (klass == swift_error_ptr) { ainfo->storage = ArgSwiftError; - } else if (klass == mono_class_try_get_swift_self_class ()) { + } else if (klass == swift_self) { ainfo->storage = ArgSwiftSelf; } } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 5f2dbbd067cc23..530253d5aca9f0 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1871,16 +1871,13 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (sig->call_convention == MONO_CALL_SWIFTCALL) { + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); if (klass) { - // References cannot be retrieved directly. For SwiftError*, use strncmp since its length is predefined, - // allowing the trailing '*' character to be ignored. - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - if (swift_error && - !strcmp (m_class_get_name_space (klass), m_class_get_name_space (swift_error)) && - !strncmp (m_class_get_name (klass), m_class_get_name (swift_error), 10)) { + if (klass == swift_error_ptr) { ainfo->storage = ArgSwiftError; - } else if (klass == mono_class_try_get_swift_self_class ()) { + } else if (klass == swift_self) { ainfo->storage = ArgSwiftSelf; } } diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 2dfcfb9a45769f..6e03d274853ab8 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2566,6 +2566,7 @@ void mono_arch_free_interp_native_call_info (gpointer call_info); #endif static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") /*New interruption machinery */ From 5447ccdc93f60a6ccf536ad9436c8857f2f36a06 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 9 Nov 2023 12:14:17 +0100 Subject: [PATCH 044/137] Add build script for native libs --- src/tests/Interop/Swift/CMakeLists.txt | 25 +++++++++++++++++++ src/tests/Interop/Swift/InvalidCallingConv.cs | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/tests/Interop/Swift/CMakeLists.txt diff --git a/src/tests/Interop/Swift/CMakeLists.txt b/src/tests/Interop/Swift/CMakeLists.txt new file mode 100644 index 00000000000000..42de151bfd3318 --- /dev/null +++ b/src/tests/Interop/Swift/CMakeLists.txt @@ -0,0 +1,25 @@ +project(SwiftInteropLibraries) +# include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") + +if(NOT CMAKE_Swift_COMPILER) + set(CMAKE_Swift_COMPILER swiftc) +endif() + +enable_language(Swift) + +set(SOURCE_FILES_DUMMY Dummy.swift) +set(SOURCE_FILES_ERROR_HANDLING ErrorHandling.swift) +set(SOURCE_FILES_SELF_CONTEXT SelfContext.swift) + +add_library(Dummy SHARED ${SOURCE_FILES_DUMMY}) +add_library(ErrorHandling SHARED ${SOURCE_FILES_ERROR_HANDLING}) +add_library(SelfContext SHARED ${SOURCE_FILES_SELF_CONTEXT}) + +# Set the output name for the libraries +set_target_properties(Dummy PROPERTIES OUTPUT_NAME "Dummy") +set_target_properties(ErrorHandling PROPERTIES OUTPUT_NAME "ErrorHandling") +set_target_properties(SelfContext PROPERTIES OUTPUT_NAME "SelfContext") + +install(TARGETS Dummy ErrorHandling SelfContext + LIBRARY DESTINATION bin +) \ No newline at end of file diff --git a/src/tests/Interop/Swift/InvalidCallingConv.cs b/src/tests/Interop/Swift/InvalidCallingConv.cs index e83d8ff9c15067..9c98e1eef5fe79 100644 --- a/src/tests/Interop/Swift/InvalidCallingConv.cs +++ b/src/tests/Interop/Swift/InvalidCallingConv.cs @@ -6,7 +6,7 @@ public class InvalidCallingConvTests { - private const string SwiftLib = "dummy.dylib"; + private const string SwiftLib = "libDummy.dylib"; [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] From 64157c51da3fe86183a8516c61e8d80ce2032eeb Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Fri, 10 Nov 2023 15:03:09 +0100 Subject: [PATCH 045/137] Build native Swift libraries after test build --- src/tests/Interop/Swift/SwiftInterop.csproj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInterop.csproj index 063041e1675e8e..37c06a86232cc3 100644 --- a/src/tests/Interop/Swift/SwiftInterop.csproj +++ b/src/tests/Interop/Swift/SwiftInterop.csproj @@ -9,4 +9,21 @@ + + + + + + + + + + + From 6b3a52f077421cacdab4fd1e95ebdff393c36f68 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 14 Nov 2023 10:50:16 +0100 Subject: [PATCH 046/137] Revert "Build native Swift libraries after test build" This reverts commit 64157c51da3fe86183a8516c61e8d80ce2032eeb. --- src/tests/Interop/Swift/SwiftInterop.csproj | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInterop.csproj index 37c06a86232cc3..063041e1675e8e 100644 --- a/src/tests/Interop/Swift/SwiftInterop.csproj +++ b/src/tests/Interop/Swift/SwiftInterop.csproj @@ -9,21 +9,4 @@ - - - - - - - - - - - From 6077b22b2274fae7ded04e5ab6441f9695262214 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 14 Nov 2023 15:10:30 +0100 Subject: [PATCH 047/137] [mono] Add params check for Swift calling convention in mini runtime --- src/mono/mono/mini/method-to-ir.c | 54 +++++++++++++++++-------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index f101190c645ec7..7f278920957ca6 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7632,30 +7632,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } } - if (sig->call_convention == MONO_CALL_SWIFTCALL) { - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - int swift_error_args = 0, swift_self_args = 0; - for (int i = 0; i < sig->param_count; ++i) { - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_error) { - swift_error_args = swift_self_args = 0; - mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("SwiftError argument must be a reference.")); - break; - } else if (klass == swift_error_ptr) { - swift_self_args++; - } else if (klass == swift_self) { - swift_self_args++; - } - } - } - if (swift_self_args > 1 || swift_error_args > 1) { - mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method signature contains multiple SwiftSelf/SwiftError arguments.")); - } - } - /* Some wrappers use calli with ftndesc-es */ if (cfg->llvm_only && !(cfg->method->wrapper_type && cfg->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && @@ -11171,6 +11147,36 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b const MonoJitICallId jit_icall_id = (MonoJitICallId)token; MonoJitICallInfo * const jit_icall_info = mono_find_jit_icall_info (jit_icall_id); + if (method->wrapper_type == MONO_CALL_SWIFTCALL) { + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + int swift_error_args = 0, swift_self_args = 0; + ERROR_DECL (swiftcall_error); + for (int i = 0; i < method->signature->param_count; ++i) { + MonoClass *klass = mono_class_from_mono_type_internal (method->signature->params [i]); + if (klass) { + if (klass == swift_error) { + swift_error_args = swift_self_args = 0; + mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("SwiftError argument must be a reference."), mono_method_full_name (method, TRUE)); + break; + } else if (klass == swift_error_ptr) { + swift_self_args++; + } else if (klass == swift_self) { + swift_self_args++; + } + } + } + if (swift_self_args > 1 || swift_error_args > 1) { + mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("Method signature contains multiple SwiftSelf/SwiftError arguments."), mono_method_full_name (method, TRUE)); + } + + if (!is_ok (swiftcall_error)) { + emit_invalid_program_with_msg (cfg, swiftcall_error, method, cmethod); + mono_error_cleanup (swiftcall_error); + } + } + CHECK_STACK (jit_icall_info->sig->param_count); sp -= jit_icall_info->sig->param_count; From af416ebe876ee39aef75a1d66be12ed16e5665fe Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 14 Nov 2023 21:49:56 +0100 Subject: [PATCH 048/137] [mono] Add basic runtime tests for the Swift calling convention --- src/tests/Interop/CMakeLists.txt | 1 + src/tests/Interop/Swift/CMakeLists.txt | 38 ++++++++----------- src/tests/Interop/Swift/README.md | 14 +------ .../Interop/Swift/SwiftErrorHandling.csproj | 14 +++++++ ....csproj => SwiftInvalidCallingConv.csproj} | 6 ++- .../Interop/Swift/SwiftSelfContext.csproj | 14 +++++++ 6 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 src/tests/Interop/Swift/SwiftErrorHandling.csproj rename src/tests/Interop/Swift/{SwiftInterop.csproj => SwiftInvalidCallingConv.csproj} (66%) create mode 100644 src/tests/Interop/Swift/SwiftSelfContext.csproj diff --git a/src/tests/Interop/CMakeLists.txt b/src/tests/Interop/CMakeLists.txt index 21e83b1f9f370f..7eb6cf79ba32ae 100644 --- a/src/tests/Interop/CMakeLists.txt +++ b/src/tests/Interop/CMakeLists.txt @@ -103,4 +103,5 @@ endif(CLR_CMAKE_TARGET_UNIX) if(CLR_CMAKE_TARGET_APPLE) add_subdirectory(ObjectiveC/AutoReleaseTest) add_subdirectory(ObjectiveC/ObjectiveCMarshalAPI) + add_subdirectory(Swift) endif() diff --git a/src/tests/Interop/Swift/CMakeLists.txt b/src/tests/Interop/Swift/CMakeLists.txt index 42de151bfd3318..5bfcac97b8f458 100644 --- a/src/tests/Interop/Swift/CMakeLists.txt +++ b/src/tests/Interop/Swift/CMakeLists.txt @@ -1,25 +1,19 @@ project(SwiftInteropLibraries) -# include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") -if(NOT CMAKE_Swift_COMPILER) - set(CMAKE_Swift_COMPILER swiftc) -endif() +set(SWIFT_SOURCES + Dummy + ErrorHandling + SelfContext +) -enable_language(Swift) - -set(SOURCE_FILES_DUMMY Dummy.swift) -set(SOURCE_FILES_ERROR_HANDLING ErrorHandling.swift) -set(SOURCE_FILES_SELF_CONTEXT SelfContext.swift) - -add_library(Dummy SHARED ${SOURCE_FILES_DUMMY}) -add_library(ErrorHandling SHARED ${SOURCE_FILES_ERROR_HANDLING}) -add_library(SelfContext SHARED ${SOURCE_FILES_SELF_CONTEXT}) - -# Set the output name for the libraries -set_target_properties(Dummy PROPERTIES OUTPUT_NAME "Dummy") -set_target_properties(ErrorHandling PROPERTIES OUTPUT_NAME "ErrorHandling") -set_target_properties(SelfContext PROPERTIES OUTPUT_NAME "SelfContext") - -install(TARGETS Dummy ErrorHandling SelfContext - LIBRARY DESTINATION bin -) \ No newline at end of file +foreach(SOURCE ${SWIFT_SOURCES}) + add_custom_target(${SOURCE}SwiftLibrary ALL + COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift + COMMENT "Generating ${SOURCE} library" + ) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DESTINATION bin + ) +endforeach() \ No newline at end of file diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index f7f85decfc4708..8ed0f1946f3392 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -86,15 +86,5 @@ Build the coreroot: ``` Build the tests: ```sh -./src/tests/build.sh -mono debug -test:Interop/Swift/SwiftInterop.csproj /p:LibrariesConfiguration=Debug -``` -Build the native library: -```sh -swiftc -emit-library ./src/tests/Interop/Swift/ErrorHandling.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libErrorHandling.dylib -swiftc -emit-library ./src/tests/Interop/Swift/SelfContext.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libSelfContext.dylib -swiftc -emit-library ./src/tests/Interop/Swift/Dummy.swift -o $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/libDummy.dylib -``` -Run the tests: -``` -bash $PWD/artifacts/tests/coreclr/osx.arm64.Debug/Interop/Swift/SwiftInterop/SwiftInterop.sh -coreroot=$PWD/artifacts/tests/coreclr/osx.arm64.Debug/Tests/Core_Root/ -``` +./src/tests/build.sh -mono debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug +``` \ No newline at end of file diff --git a/src/tests/Interop/Swift/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling.csproj new file mode 100644 index 00000000000000..b02b0d39f47d84 --- /dev/null +++ b/src/tests/Interop/Swift/SwiftErrorHandling.csproj @@ -0,0 +1,14 @@ + + + Exe + true + true + + + + + + + + + diff --git a/src/tests/Interop/Swift/SwiftInterop.csproj b/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj similarity index 66% rename from src/tests/Interop/Swift/SwiftInterop.csproj rename to src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj index 063041e1675e8e..0c846653c86a88 100644 --- a/src/tests/Interop/Swift/SwiftInterop.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj @@ -5,8 +5,10 @@ true - - + + + + diff --git a/src/tests/Interop/Swift/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext.csproj new file mode 100644 index 00000000000000..aaa9e840148582 --- /dev/null +++ b/src/tests/Interop/Swift/SwiftSelfContext.csproj @@ -0,0 +1,14 @@ + + + Exe + true + true + + + + + + + + + From cc9c619b2cb8cb72ced9fa73fd6097c17d5f09a9 Mon Sep 17 00:00:00 2001 From: Matous Kozak <55735845+matouskozak@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:26:41 +0100 Subject: [PATCH 049/137] Update README.md Add full AOT runtime test instructions --- src/tests/Interop/Swift/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 8ed0f1946f3392..a3946668c9a96d 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -87,4 +87,11 @@ Build the coreroot: Build the tests: ```sh ./src/tests/build.sh -mono debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug -``` \ No newline at end of file +``` +--- +Build tests in full AOT mode: +```sh +./src/tests/build.sh -log:MonoAot -mono_fullaot debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug /p:RuntimeVariant=llvmfullaot +``` +Run tests in full AOT mode: +- set `MONO_ENV_OPTIONS=--full-aot` and run as usual From 89f46b81cba765d86f5fc3a2713ed52bb85e7fe8 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 09:41:36 +0100 Subject: [PATCH 050/137] Fix README.md formatting --- src/tests/Interop/Swift/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index a3946668c9a96d..79d1c6ce56f856 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -88,8 +88,7 @@ Build the tests: ```sh ./src/tests/build.sh -mono debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug ``` ---- -Build tests in full AOT mode: +Build the tests in full AOT mode: ```sh ./src/tests/build.sh -log:MonoAot -mono_fullaot debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug /p:RuntimeVariant=llvmfullaot ``` From 20eb7a64029842fd0c16c774afee9679d36ddbd9 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 11:51:15 +0100 Subject: [PATCH 051/137] Add comments for the Swift types --- .../Runtime/InteropServices/Swift/SwiftType.cs | 18 ++++++++++++++++++ .../ref/System.Runtime.InteropServices.cs | 1 + 2 files changed, 19 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs index c5256603f82032..cc0eb66d2508e1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs @@ -3,27 +3,45 @@ namespace System.Runtime.InteropServices.Swift { + /// + /// Indicates that the argument is the self context. + /// public readonly struct SwiftSelf { + /// Creates a new instance of the SwiftSelf struct with the specified pointer value. + /// The pointer value of the self context public SwiftSelf(IntPtr value) { Value = value; } + /// Gets the pointer of the self context. public IntPtr Value { get; } } + /// + /// Indicates that the argument is the error context. + /// public readonly struct SwiftError { + /// Creates a new instance of the SwiftError struct with the specified pointer value. + /// The pointer value of the error context public SwiftError(IntPtr value) { Value = value; } + /// Gets the pointer of the error context. public IntPtr Value { get; } } + /// + /// Indicates that the argument is the async context. + /// public readonly struct SwiftAsyncContext { + /// Creates a new instance of the SwiftAsyncContext struct with the specified pointer value. + /// The pointer value of the async context public SwiftAsyncContext(IntPtr value) { Value = value; } + /// Gets the pointer of the async context. public IntPtr Value { get; } } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index b973972873c91e..c0df7bd89db587 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -638,6 +638,7 @@ public enum CallingConvention StdCall = 3, ThisCall = 4, FastCall = 5, + SwiftCall = 6, } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class, Inherited=false)] public sealed partial class ClassInterfaceAttribute : System.Attribute From ae08445b49546fdca158d0bded222a3b9defb7b5 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 11:54:27 +0100 Subject: [PATCH 052/137] Fix lint; remove trailing spaces --- src/tests/Interop/Swift/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 79d1c6ce56f856..6546787f1d8d9f 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -2,9 +2,9 @@ The Swift programming language has a different ABI, runtime environment, and object model, making it challenging to call from the .NET runtime. Existing solutions, like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet). -This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. For a comprehensive .NET Swift interop, the Binding Tools for Swift contains valuable components that could be reused or built upon. +This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. For a comprehensive .NET Swift interop, the Binding Tools for Swift contains valuable components that could be reused or built upon. -We want to focus on the runtime support for direct P/Invoke interop with Swift, which Xamarin bindings will consume to support running Maui apps with third-party Swift libraries. Ideally, we want to avoid generating extra wrappers and attempt to directly call all kinds of Swift functions. While external tools can be helpful, they may introduce additional complexity, and we intend to integrate them into the .NET toolchain ecosystem. +We want to focus on the runtime support for direct P/Invoke interop with Swift, which Xamarin bindings will consume to support running Maui apps with third-party Swift libraries. Ideally, we want to avoid generating extra wrappers and attempt to directly call all kinds of Swift functions. While external tools can be helpful, they may introduce additional complexity, and we intend to integrate them into the .NET toolchain ecosystem. ## Swift ABI in a nutshell @@ -24,9 +24,9 @@ The Swift runtime keeps a metadata record for every type used in a program, incl ### Calling convention -In Swift programming language, functions parameters can be passed either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. +In Swift programming language, functions parameters can be passed either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. -According to the calling convention, the `self`` context has dedicated registers, and it is always passed through them since it's heavily used. Methods calling other methods on the same object can share the self context. +According to the calling convention, the `self`` context has dedicated registers, and it is always passed through them since it's heavily used. Methods calling other methods on the same object can share the self context. Here are cases when `self` context is passed via register: - Instance methods on class types: pointer to self From 5a225b5dc070559adff6f1ca0bc54761fc7963ea Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 13:08:40 +0100 Subject: [PATCH 053/137] Resolve CI failures --- src/mono/mono/mini/method-to-ir.c | 10 +++++----- src/mono/mono/mini/mini-arm.c | 7 +++++++ src/mono/mono/mini/mini-riscv.c | 7 +++++++ src/mono/mono/mini/mini-x86.c | 7 +++++++ src/tests/Interop/Swift/CMakeLists.txt | 2 +- src/tests/Interop/Swift/Dummy.swift | 2 +- src/tests/Interop/Swift/SelfContext.swift | 2 +- src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj | 1 + 8 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 7f278920957ca6..9b62d759a6dd7c 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -11154,15 +11154,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b int swift_error_args = 0, swift_self_args = 0; ERROR_DECL (swiftcall_error); for (int i = 0; i < method->signature->param_count; ++i) { - MonoClass *klass = mono_class_from_mono_type_internal (method->signature->params [i]); - if (klass) { - if (klass == swift_error) { + MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); + if (param_klass) { + if (param_klass == swift_error) { swift_error_args = swift_self_args = 0; mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("SwiftError argument must be a reference."), mono_method_full_name (method, TRUE)); break; - } else if (klass == swift_error_ptr) { + } else if (param_klass == swift_error_ptr) { swift_self_args++; - } else if (klass == swift_self) { + } else if (param_klass == swift_self) { swift_self_args++; } } diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index 29546e1c231991..fedb369ff3211d 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -1818,6 +1818,13 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +gpointer +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) +{ + NOT_IMPLEMENTED; + return NULL; +} + #ifndef DISABLE_JIT gboolean diff --git a/src/mono/mono/mini/mini-riscv.c b/src/mono/mono/mini/mini-riscv.c index fe169c316e7ca6..17665ded542d7f 100644 --- a/src/mono/mono/mini/mini-riscv.c +++ b/src/mono/mono/mini/mini-riscv.c @@ -1199,6 +1199,13 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +gpointer +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) +{ + NOT_IMPLEMENTED; + return NULL; +} + #ifndef DISABLE_JIT #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index 80116fb5497f32..9912aa699c4e60 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -691,6 +691,13 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +gpointer +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) +{ + NOT_IMPLEMENTED; + return NULL; +} + /* * mono_arch_get_argument_info: * @csig: a method signature diff --git a/src/tests/Interop/Swift/CMakeLists.txt b/src/tests/Interop/Swift/CMakeLists.txt index 5bfcac97b8f458..b771e7330d92cb 100644 --- a/src/tests/Interop/Swift/CMakeLists.txt +++ b/src/tests/Interop/Swift/CMakeLists.txt @@ -16,4 +16,4 @@ foreach(SOURCE ${SWIFT_SOURCES}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib DESTINATION bin ) -endforeach() \ No newline at end of file +endforeach() diff --git a/src/tests/Interop/Swift/Dummy.swift b/src/tests/Interop/Swift/Dummy.swift index d2326a105fe9af..b8aae426015550 100644 --- a/src/tests/Interop/Swift/Dummy.swift +++ b/src/tests/Interop/Swift/Dummy.swift @@ -1 +1 @@ -public func dummyFunc() { } \ No newline at end of file +public func dummyFunc() { } diff --git a/src/tests/Interop/Swift/SelfContext.swift b/src/tests/Interop/Swift/SelfContext.swift index b6e21b2de97d6c..bb6ce271de1ad7 100644 --- a/src/tests/Interop/Swift/SelfContext.swift +++ b/src/tests/Interop/Swift/SelfContext.swift @@ -15,4 +15,4 @@ public class SelfLibrary { let pointer = unmanagedInstance.toOpaque() return pointer } -} \ No newline at end of file +} diff --git a/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj index 0c846653c86a88..f4fc8109bc2070 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj @@ -3,6 +3,7 @@ Exe true true + true From ac7f5652ab6467e2fc16f30e9137ca4060e8b3f3 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 13:38:28 +0100 Subject: [PATCH 054/137] Remove static functions from mini.h file --- src/mono/mono/mini/interp/transform.c | 3 +++ src/mono/mono/mini/method-to-ir.c | 4 ++++ src/mono/mono/mini/mini-amd64.c | 3 +++ src/mono/mono/mini/mini-amd64.h | 3 +++ src/mono/mono/mini/mini-arm64.c | 4 ++++ src/mono/mono/mini/mini.h | 4 ---- 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 76cc4e0136832a..48a815ff5686a3 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -61,6 +61,9 @@ static int stack_type [] = { static GENERATE_TRY_GET_CLASS_WITH_CACHE (intrinsic_klass, "System.Runtime.CompilerServices", "IntrinsicAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (doesnotreturn_klass, "System.Diagnostics.CodeAnalysis", "DoesNotReturnAttribute") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 9b62d759a6dd7c..8643489e44dd80 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -226,6 +226,10 @@ const gint8 mini_ins_sreg_counts[] = { #undef MINI_OP #undef MINI_OP3 +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + guint32 mono_alloc_ireg (MonoCompile *cfg) { diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index c346055d35dde3..f6be9458105bbc 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -53,6 +53,9 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") #define IS_IMM32(val) ((((guint64)val) >> 32) == 0) diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 2a2aeeaaa2ee3a..c4e7a410009e90 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -226,10 +226,13 @@ static const AMD64_Reg_No return_regs [] = { AMD64_RAX }; static const AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 }; +static const AMD64_Reg_No ctx_regs [] = { AMD64_R12, AMD64_R13 }; + #define PARAM_REGS G_N_ELEMENTS(param_regs) #define FLOAT_PARAM_REGS G_N_ELEMENTS(float_param_regs) #define RETURN_REGS G_N_ELEMENTS(return_regs) #define FLOAT_RETURN_REGS G_N_ELEMENTS(float_return_regs) +#define CTX_REGS G_N_ELEMENTS(ctx_regs) #else #define PARAM_REGS 6 diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 530253d5aca9f0..46e36638a199eb 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -125,6 +125,10 @@ static WARN_UNUSED_RESULT guint8* emit_load_regset (guint8 *code, guint64 regs, static guint8* emit_brx (guint8 *code, int reg); static guint8* emit_blrx (guint8 *code, int reg); +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + const char* mono_arch_regname (int reg) { diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 6e03d274853ab8..656f21f303ea9b 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2565,10 +2565,6 @@ gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignatu void mono_arch_free_interp_native_call_info (gpointer call_info); #endif -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - /*New interruption machinery */ void mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data); From b945d4daa7f35a76076f427c9e2eb7b4bc6a9b5b Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 18:17:52 +0100 Subject: [PATCH 055/137] Fix CI failures --- src/mono/mono/mini/mini-arm64.c | 4 ++-- src/tests/Interop/Swift/SwiftErrorHandling.csproj | 2 ++ src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj | 1 + src/tests/Interop/Swift/SwiftSelfContext.csproj | 2 ++ src/tests/issues.targets | 9 +++++++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 46e36638a199eb..0bb7bef007b6a5 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -5866,7 +5866,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) code = emit_strx (code, ainfo->reg + part, ins->inst_basereg, offs); if (ainfo->storage == ArgSwiftSelf) { - code = emit_ldrx (code, ARMREG_R20, ins->inst_basereg, ins->inst_offset); + code = emit_ldrx (code, ARMREG_R20, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); } } break; @@ -6249,7 +6249,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) switch (ainfo->storage) { case ArgSwiftError: - code = emit_ldrx (code, ARMREG_IP0, arg->inst_basereg, arg->inst_offset); + code = emit_ldrx (code, ARMREG_IP0, arg->inst_basereg, GTMREG_TO_INT (arg->inst_offset)); arm_strx (code, ARMREG_R21, ARMREG_IP0, 0); break; default: diff --git a/src/tests/Interop/Swift/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling.csproj index b02b0d39f47d84..47e8d5d25a0cdb 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling.csproj @@ -3,6 +3,8 @@ Exe true true + + true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj index f4fc8109bc2070..57995b528b07c5 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj @@ -3,6 +3,7 @@ Exe true true + true diff --git a/src/tests/Interop/Swift/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext.csproj index aaa9e840148582..c13b06e9e79f4e 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext.csproj @@ -3,6 +3,8 @@ Exe true true + + true diff --git a/src/tests/issues.targets b/src/tests/issues.targets index d0ea9efc9de817..7b029c8ffa8407 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -3277,6 +3277,9 @@ needs native libraries + + Not supported + @@ -3723,6 +3726,12 @@ + + + Not supported + + + Date: Wed, 15 Nov 2023 18:59:15 +0100 Subject: [PATCH 056/137] Revert API changes --- .../src/System/Runtime/InteropServices/CallingConvention.cs | 1 - .../ref/System.Runtime.InteropServices.cs | 1 - .../src/System/Reflection/RuntimeMethodInfo.Mono.cs | 2 -- src/mono/mono/metadata/loader.c | 3 --- src/mono/mono/metadata/tabledefs.h | 1 - 5 files changed, 8 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs index 7244bebad7087f..88465296ced546 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs @@ -11,6 +11,5 @@ public enum CallingConvention StdCall = 3, ThisCall = 4, FastCall = 5, - SwiftCall = 6, } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index e50429f2b55d02..9483b414b5ef25 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -638,7 +638,6 @@ public enum CallingConvention StdCall = 3, ThisCall = 4, FastCall = 5, - SwiftCall = 6, } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class, Inherited=false)] public sealed partial class ClassInterfaceAttribute : System.Attribute diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs index c2daeaff24e058..c6db75764929b1 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs @@ -503,7 +503,6 @@ private DllImportAttribute GetDllImportAttribute() case PInvokeAttributes.CallConvStdcall: callingConvention = InteropServicesCallingConvention.StdCall; break; case PInvokeAttributes.CallConvThiscall: callingConvention = InteropServicesCallingConvention.ThisCall; break; case PInvokeAttributes.CallConvFastcall: callingConvention = InteropServicesCallingConvention.FastCall; break; - case PInvokeAttributes.CallConvSwift: callingConvention = InteropServicesCallingConvention.SwiftCall; break; // Invalid: default to CallingConvention.Cdecl default: break; @@ -581,7 +580,6 @@ private DllImportAttribute GetDllImportAttribute() PInvokeAttributes.CallConvStdcall => InteropServicesCallingConvention.StdCall, PInvokeAttributes.CallConvThiscall => InteropServicesCallingConvention.ThisCall, PInvokeAttributes.CallConvFastcall => InteropServicesCallingConvention.FastCall, - PInvokeAttributes.CallConvSwift => InteropServicesCallingConvention.SwiftCall, // Invalid: default to CallingConvention.Cdecl _ => InteropServicesCallingConvention.Cdecl, }; diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index 8433d6709a8ab6..5f21d3371c3c1f 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -1907,9 +1907,6 @@ mono_method_signature_checked_slow (MonoMethod *m, MonoError *error) case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL: conv = MONO_CALL_FASTCALL; break; - case PINVOKE_ATTRIBUTE_CALL_CONV_SWIFTCALL: - conv = MONO_CALL_SWIFTCALL; - break; case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC: case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST: default: { diff --git a/src/mono/mono/metadata/tabledefs.h b/src/mono/mono/metadata/tabledefs.h index 1369fd0bfb5625..52521435fc3b55 100644 --- a/src/mono/mono/metadata/tabledefs.h +++ b/src/mono/mono/metadata/tabledefs.h @@ -251,7 +251,6 @@ enum { #define PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL 0x0300 #define PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL 0x0400 #define PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL 0x0500 -#define PINVOKE_ATTRIBUTE_CALL_CONV_SWIFTCALL 0x0600 #define PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_ENABLED 0x1000 #define PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_DISABLED 0x2000 #define PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_MASK 0x3000 From 0587a55593158c8532f7854e8fdb9171384fc1e2 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 15 Nov 2023 18:59:32 +0100 Subject: [PATCH 057/137] Update README.md --- src/tests/Interop/Swift/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md index 6546787f1d8d9f..b8ca714bd46140 100644 --- a/src/tests/Interop/Swift/README.md +++ b/src/tests/Interop/Swift/README.md @@ -78,7 +78,7 @@ Progress on the implementation can be tracked at https://github.com/dotnet/runti Build the runtime: ```sh -./build.sh mono+libs+clr.hosts /p:ApiCompatGenerateSuppressionFile=true /p:KeepNativeSymbols=true +./build.sh mono+libs+clr.hosts /p:KeepNativeSymbols=true ``` Build the coreroot: ```sh From 56bcb1bb5438422a3906e6a95d9f88262270e693 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 16 Nov 2023 17:00:47 +0100 Subject: [PATCH 058/137] [interp] Simplify register allocation in CallContext --- src/mono/mono/metadata/class-internals.h | 4 ++-- src/mono/mono/metadata/object-offsets.h | 1 - src/mono/mono/mini/interp/transform.c | 4 ++-- src/mono/mono/mini/method-to-ir.c | 10 +++++----- src/mono/mono/mini/mini-amd64.c | 4 ++-- src/mono/mono/mini/mini-amd64.h | 7 +++---- src/mono/mono/mini/mini-arm64.c | 8 ++++---- src/mono/mono/mini/mini-arm64.h | 8 +++----- src/mono/mono/mini/tramp-amd64.c | 4 ++-- src/mono/mono/mini/tramp-arm64.c | 4 ++-- 10 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 967ecd425e5f98..b135e830b46da2 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -979,9 +979,9 @@ mono_class_try_get_##shortname##_class (void) \ } -#define GENERATE_TRY_GET_CLASS_REF_WITH_CACHE(shortname,name_space,name) \ +#define GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE(shortname,name_space,name) \ MonoClass* \ -mono_class_try_get_##shortname##_class (void) \ +mono_class_try_get_##shortname##_ptr_class (void) \ { \ static volatile MonoClass *tmp_class; \ static volatile gboolean inited; \ diff --git a/src/mono/mono/metadata/object-offsets.h b/src/mono/mono/metadata/object-offsets.h index 3d851753b8995e..a1ab49ff43a091 100644 --- a/src/mono/mono/metadata/object-offsets.h +++ b/src/mono/mono/metadata/object-offsets.h @@ -305,7 +305,6 @@ DECL_OFFSET(SeqPointInfo, bp_addrs) DECL_OFFSET(CallContext, gregs) DECL_OFFSET(CallContext, fregs) -DECL_OFFSET(CallContext, cregs) DECL_OFFSET(CallContext, stack_size) DECL_OFFSET(CallContext, stack) #endif diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 596d5743584761..957e4ceaaa81d7 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -62,7 +62,7 @@ static int stack_type [] = { static GENERATE_TRY_GET_CLASS_WITH_CACHE (intrinsic_klass, "System.Runtime.CompilerServices", "IntrinsicAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (doesnotreturn_klass, "System.Diagnostics.CodeAnalysis", "DoesNotReturnAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error); @@ -3750,7 +3750,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (csignature->call_convention == MONO_CALL_SWIFTCALL) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; for (int i = 0; i < csignature->param_count; ++i) { diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 8643489e44dd80..b01805e568699a 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -227,7 +227,7 @@ const gint8 mini_ins_sreg_counts[] = { #undef MINI_OP3 static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") guint32 @@ -11153,7 +11153,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (method->wrapper_type == MONO_CALL_SWIFTCALL) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; ERROR_DECL (swiftcall_error); @@ -11176,9 +11176,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } if (!is_ok (swiftcall_error)) { - emit_invalid_program_with_msg (cfg, swiftcall_error, method, cmethod); - mono_error_cleanup (swiftcall_error); - } + emit_invalid_program_with_msg (cfg, swiftcall_error, method, cmethod); + mono_error_cleanup (swiftcall_error); + } } CHECK_STACK (jit_icall_info->sig->param_count); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index f6be9458105bbc..1e2f62e622a55e 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -54,7 +54,7 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") @@ -1082,7 +1082,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (sig->call_convention == MONO_CALL_SWIFTCALL) { - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass) { diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index c4e7a410009e90..397e35ff86e84f 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -226,13 +226,12 @@ static const AMD64_Reg_No return_regs [] = { AMD64_RAX }; static const AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 }; -static const AMD64_Reg_No ctx_regs [] = { AMD64_R12, AMD64_R13 }; - #define PARAM_REGS G_N_ELEMENTS(param_regs) #define FLOAT_PARAM_REGS G_N_ELEMENTS(float_param_regs) #define RETURN_REGS G_N_ELEMENTS(return_regs) #define FLOAT_RETURN_REGS G_N_ELEMENTS(float_return_regs) -#define CTX_REGS G_N_ELEMENTS(ctx_regs) +#define CTX_REGS 2 +#define CTX_REGS_OFFSET AMD64_R12 #else #define PARAM_REGS 6 @@ -240,6 +239,7 @@ static const AMD64_Reg_No ctx_regs [] = { AMD64_R12, AMD64_R13 }; #define RETURN_REGS 2 #define FLOAT_RETURN_REGS 2 #define CTX_REGS 2 +#define CTX_REGS_OFFSET AMD64_R12 static const AMD64_Reg_No param_regs [] = {AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9}; @@ -250,7 +250,6 @@ static const AMD64_XMM_Reg_No float_param_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD6 static const AMD64_Reg_No return_regs [] = {AMD64_RAX, AMD64_RDX}; -static const AMD64_Reg_No ctx_regs [] = {AMD64_R12, AMD64_R13}; #endif typedef struct { diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 0bb7bef007b6a5..40bfbe3795e455 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -126,7 +126,7 @@ static guint8* emit_brx (guint8 *code, int reg); static guint8* emit_blrx (guint8 *code, int reg); static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_REF_WITH_CACHE (swift_error_ref, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") const char* @@ -1875,7 +1875,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (sig->call_convention == MONO_CALL_SWIFTCALL) { - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ref_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); if (klass) { @@ -1919,9 +1919,9 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgInIReg: return &ccontext->gregs [ainfo->reg]; case ArgSwiftSelf: - return &ccontext->cregs [ARMREG_R20 - CTX_REGS_OFFSET]; + return &ccontext->gregs [PARAM_REGS + 1 + ARMREG_R20 - CTX_REGS_OFFSET]; case ArgSwiftError: - return &ccontext->cregs [ARMREG_R21 - CTX_REGS_OFFSET]; + return &ccontext->gregs [PARAM_REGS + 1 + ARMREG_R21 - CTX_REGS_OFFSET]; case ArgInFReg: case ArgInFRegR4: case ArgHFA: diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index 8084de36b32ecc..b4cf593fd3f2da 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -99,7 +99,7 @@ struct SeqPointInfo { #define PARAM_REGS 8 #define FP_PARAM_REGS 8 #define CTX_REGS 2 -#define CTX_REGS_OFFSET 20 +#define CTX_REGS_OFFSET ARMREG_R20 typedef struct { host_mgreg_t res, res2; @@ -271,12 +271,10 @@ struct CallInfo { }; typedef struct { - /* General registers + ARMREG_R8 for indirect returns */ - host_mgreg_t gregs [PARAM_REGS + 1]; + /* General registers + context registers + ARMREG_R8 for indirect returns */ + host_mgreg_t gregs [PARAM_REGS + CTX_REGS + 1]; /* Floating registers */ double fregs [FP_PARAM_REGS]; - /* Context registers */ - host_mgreg_t cregs [CTX_REGS]; /* Stack usage, used for passing params on stack */ guint32 stack_size; guint8* stack; diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 26babb6aa8c87e..72f113a213a0d5 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1099,7 +1099,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* set all context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) - amd64_mov_reg_membase (code, ctx_regs [i], AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + ctx_regs [i] * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); + amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); /* load target addr */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (target_mgreg_t)); @@ -1118,7 +1118,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* set all context registers to CallContext */ for (i = 0; i < CTX_REGS; i++) - amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + ctx_regs [i] * sizeof (target_mgreg_t), ctx_regs [i], sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); #if TARGET_WIN32 amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0); diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index 58483b9842e985..f24854ac119e71 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -724,7 +724,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* set all context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) - arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); + arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); /* load target addr */ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_targetaddr); @@ -745,7 +745,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* set all context registers to CallContext */ for (i = 0; i < CTX_REGS; i++) - arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, cregs) + i * sizeof (host_mgreg_t)); + arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); From a5afdbe00a0f28779de4106887f66612825e48a8 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 17 Nov 2023 11:21:46 +0100 Subject: [PATCH 059/137] [mono] Remove mono_arch_get_swift_error from unsupported architectures --- src/mono/mono/mini/interp/interp.c | 2 ++ src/mono/mono/mini/mini-amd64.h | 4 ++++ src/mono/mono/mini/mini-arm.c | 7 ------- src/mono/mono/mini/mini-arm64.h | 4 ++++ src/mono/mono/mini/mini-riscv.c | 7 ------- src/mono/mono/mini/mini-x86.c | 7 ------- src/mono/mono/mini/mini.h | 2 ++ src/tests/Interop/Swift/Dummy.swift | 3 +++ src/tests/Interop/Swift/ErrorHandling.cs | 3 +++ src/tests/Interop/Swift/ErrorHandling.swift | 3 +++ src/tests/Interop/Swift/InvalidCallingConv.cs | 3 +++ src/tests/Interop/Swift/SelfContext.cs | 3 +++ src/tests/Interop/Swift/SelfContext.swift | 3 +++ 13 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 52596d91add3e2..d0b6534cf1bdde 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1710,6 +1710,7 @@ ves_pinvoke_method ( interp_pop_lmf (&ext); #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP +#ifdef MONO_ARCH_HAVE_SWIFTCALL if (sig->call_convention == MONO_CALL_SWIFTCALL) { int arg_index; gpointer data = mono_arch_get_swift_error (&ccontext, sig, call_info, &arg_index); @@ -1720,6 +1721,7 @@ ves_pinvoke_method ( *(gpointer*)result->data.p = *(gpointer*)data; } } +#endif if (!context->has_resume_state) { mono_arch_get_native_call_context_ret (&ccontext, &frame, sig, call_info); } diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 397e35ff86e84f..7a0ca5a2b8d0c0 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -491,6 +491,10 @@ typedef struct { // can pass context to generics or interfaces? #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#define MONO_ARCH_HAVE_SWIFTCALL 1 +#endif + void mono_amd64_patch (unsigned char* code, gpointer target); diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index fedb369ff3211d..29546e1c231991 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -1818,13 +1818,6 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } -gpointer -mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) -{ - NOT_IMPLEMENTED; - return NULL; -} - #ifndef DISABLE_JIT gboolean diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index b4cf593fd3f2da..eaa5ed731a3b4a 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -206,6 +206,10 @@ typedef struct { #define MONO_ARCH_EXPLICIT_NULL_CHECKS 1 #endif +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#define MONO_ARCH_HAVE_SWIFTCALL 1 +#endif + /* Relocations */ #define MONO_R_ARM64_B 1 #define MONO_R_ARM64_BCC 2 diff --git a/src/mono/mono/mini/mini-riscv.c b/src/mono/mono/mini/mini-riscv.c index 17665ded542d7f..fe169c316e7ca6 100644 --- a/src/mono/mono/mini/mini-riscv.c +++ b/src/mono/mono/mini/mini-riscv.c @@ -1199,13 +1199,6 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } -gpointer -mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) -{ - NOT_IMPLEMENTED; - return NULL; -} - #ifndef DISABLE_JIT #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index 9912aa699c4e60..80116fb5497f32 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -691,13 +691,6 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } -gpointer -mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) -{ - NOT_IMPLEMENTED; - return NULL; -} - /* * mono_arch_get_argument_info: * @csig: a method signature diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 656f21f303ea9b..442e9e7ba5561a 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2559,8 +2559,10 @@ void mono_arch_set_native_call_context_ret (CallContext *ccontext, gpointer gpointer mono_arch_get_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); // After the pinvoke call is done, this moves return value from the ccontext to the InterpFrame. void mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); +#ifdef MONO_ARCH_HAVE_SWIFTCALL // After the pinvoke call is done, this return an error context value from the ccontext. gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index); +#endif /* Free the structure returned by mono_arch_get_interp_native_call_info (NULL, sig) */ void mono_arch_free_interp_native_call_info (gpointer call_info); #endif diff --git a/src/tests/Interop/Swift/Dummy.swift b/src/tests/Interop/Swift/Dummy.swift index b8aae426015550..4dfe8a7fff8b3a 100644 --- a/src/tests/Interop/Swift/Dummy.swift +++ b/src/tests/Interop/Swift/Dummy.swift @@ -1 +1,4 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + public func dummyFunc() { } diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/ErrorHandling.cs index 17051d52403dcc..3ba4a0e44da180 100644 --- a/src/tests/Interop/Swift/ErrorHandling.cs +++ b/src/tests/Interop/Swift/ErrorHandling.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/ErrorHandling.swift index 4c45ff6276d9c1..c2ba2860ff511f 100644 --- a/src/tests/Interop/Swift/ErrorHandling.swift +++ b/src/tests/Interop/Swift/ErrorHandling.swift @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + import Foundation public enum MyError: Error { diff --git a/src/tests/Interop/Swift/InvalidCallingConv.cs b/src/tests/Interop/Swift/InvalidCallingConv.cs index 9c98e1eef5fe79..9ede3e7a8e672b 100644 --- a/src/tests/Interop/Swift/InvalidCallingConv.cs +++ b/src/tests/Interop/Swift/InvalidCallingConv.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/tests/Interop/Swift/SelfContext.cs b/src/tests/Interop/Swift/SelfContext.cs index 184a71afad199b..8dd171bc698b19 100644 --- a/src/tests/Interop/Swift/SelfContext.cs +++ b/src/tests/Interop/Swift/SelfContext.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/tests/Interop/Swift/SelfContext.swift b/src/tests/Interop/Swift/SelfContext.swift index bb6ce271de1ad7..047f3bd942801b 100644 --- a/src/tests/Interop/Swift/SelfContext.swift +++ b/src/tests/Interop/Swift/SelfContext.swift @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + public class SelfLibrary { public var number: Int public static let shared = SelfLibrary(number: 42) From 2faea556b1c0f1c0b0eacf945fa81bf45d1251f6 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 17 Nov 2023 11:50:25 +0100 Subject: [PATCH 060/137] Update src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs Co-authored-by: Jan Kotas --- .../src/System/Reflection/RuntimeMethodInfo.Mono.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs index c6db75764929b1..42e3f780d54980 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs @@ -69,7 +69,6 @@ internal enum PInvokeAttributes CallConvStdcall = 0x0300, CallConvThiscall = 0x0400, CallConvFastcall = 0x0500, - CallConvSwift = 0x0600, MaxValue = 0xFFFF, } From 05a8c1cb9e9590d98f8a34bb3448e689b86529d7 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 17 Nov 2023 15:23:16 +0100 Subject: [PATCH 061/137] [mono] Add ext_callconv to the MonoMethodSignature Add Swift call handling in a similar manner as SuppressGCTransition by introducing a bit in the MonoMethodSignature. The enum defines two flags: MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION and MONO_EXT_CALLCONV_SWIFTCALL. Additionally, a new function, mono_method_signature_has_ext_callconv, checks for the presence of specific flags in the ext_callconv field of MonoMethodSignature. --- src/mono/mono/metadata/icall.c | 2 +- src/mono/mono/metadata/marshal.c | 6 ++---- src/mono/mono/metadata/metadata-internals.h | 13 ++++++++++++- src/mono/mono/metadata/metadata.c | 15 +++++++-------- src/mono/mono/mini/interp/interp.c | 2 +- src/mono/mono/mini/interp/transform.c | 6 +++--- src/mono/mono/mini/method-to-ir.c | 4 ++-- src/mono/mono/mini/mini-amd64.c | 4 ++-- src/mono/mono/mini/mini-arm64.c | 6 +++--- .../public/mono/metadata/details/metadata-types.h | 1 - 10 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 75d06bace0fe8c..8a30b4a3a2c557 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -2821,7 +2821,7 @@ ves_icall_RuntimeType_GetCallingConventionFromFunctionPointerInternal (MonoQCall MonoType *type = type_handle.type; g_assert (type->type == MONO_TYPE_FNPTR); // FIXME: Once we address: https://github.com/dotnet/runtime/issues/90308 this should not be needed anymore - return GUINT_TO_INT8 (type->data.method->suppress_gc_transition ? MONO_CALL_UNMANAGED_MD : type->data.method->call_convention); + return GUINT_TO_INT8 (mono_method_signature_has_ext_callconv (type->data.method, MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION) ? MONO_CALL_UNMANAGED_MD : type->data.method->call_convention); } MonoBoolean diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 9ef9b4e5b3c34f..ec44f166824ef8 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3233,7 +3233,7 @@ mono_marshal_set_callconv_for_type(MonoType *type, MonoMethodSignature *csig, gb else if (!strcmp (class_name, "CallConvThiscall")) csig->call_convention = MONO_CALL_THISCALL; else if (!strcmp (class_name, "CallConvSwift")) - csig->call_convention = MONO_CALL_SWIFTCALL; + csig->ext_callconv |= MONO_EXT_CALLCONV_SWIFTCALL; else if (!strcmp (class_name, "CallConvSuppressGCTransition") && skip_gc_trans != NULL) *skip_gc_trans = TRUE; } @@ -3358,12 +3358,10 @@ mono_marshal_set_signature_callconv_from_attribute(MonoMethodSignature *sig, Mon sig->call_convention = MONO_CALL_STDCALL; else if (!strcmp (name, "Thiscall")) sig->call_convention = MONO_CALL_THISCALL; - else if (!strcmp (name, "Swift")) - sig->call_convention = MONO_CALL_SWIFTCALL; else if (!strcmp (name, "Fastcall")) sig->call_convention = MONO_CALL_FASTCALL; else if (!strcmp (name, "SuppressGCTransition")) - sig->suppress_gc_transition = 1; + sig->ext_callconv |= MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION; // TODO: Support CallConvMemberFunction? // TODO: Support multiple calling convetions? // - Switch MonoCallConvention enum values to powers of 2 diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index b0d1858f7148e1..05934225cbd907 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -656,11 +656,17 @@ struct _MonoMethodSignature { unsigned int pinvoke : 1; unsigned int is_inflated : 1; unsigned int has_type_parameters : 1; - unsigned int suppress_gc_transition : 1; unsigned int marshalling_disabled : 1; + uint8_t ext_callconv; // see MonoExtCallConv MonoType *params [MONO_ZERO_LEN_ARRAY]; }; +typedef enum { + MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION = 0x01, + MONO_EXT_CALLCONV_SWIFTCALL = 0x02, + /// see MonoMethodSignature:ext_callconv - only 8 bits +} MonoExtCallConv; + /* * AOT cache configuration loaded from config files. * Doesn't really belong here. @@ -1275,4 +1281,9 @@ mono_class_set_deferred_type_load_failure (MonoClass *klass, const char * fmt, . gboolean mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...); +static inline gboolean +mono_method_signature_has_ext_callconv (MonoMethodSignature *sig, MonoExtCallConv flags) { + return (sig->ext_callconv & flags) != 0; +} + #endif /* __MONO_METADATA_INTERNALS_H__ */ diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 3899d28fd148c9..05b6166d8bf946 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -2570,7 +2570,7 @@ metadata_signature_set_modopt_call_conv (MonoMethodSignature *sig, MonoType *cmo if (count == 0) return; int base_callconv = sig->call_convention; - gboolean suppress_gc_transition = sig->suppress_gc_transition; + gboolean suppress_gc_transition = mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION); for (uint8_t i = 0; i < count; ++i) { gboolean req = FALSE; MonoType *cmod = mono_type_get_custom_modifier (cmod_type, i, &req, error); @@ -2604,9 +2604,6 @@ metadata_signature_set_modopt_call_conv (MonoMethodSignature *sig, MonoType *cmo } else if (!strcmp (name, "Fastcall")) { base_callconv = MONO_CALL_FASTCALL; continue; - } else if (!strcmp (name, "Swift")) { - base_callconv = MONO_CALL_SWIFTCALL; - continue; } /* Check for known calling convention modifiers */ @@ -2616,7 +2613,8 @@ metadata_signature_set_modopt_call_conv (MonoMethodSignature *sig, MonoType *cmo } } sig->call_convention = base_callconv; - sig->suppress_gc_transition = suppress_gc_transition; + if (suppress_gc_transition) + sig->ext_callconv |= MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION; } /** @@ -2679,12 +2677,15 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c case MONO_CALL_STDCALL: case MONO_CALL_THISCALL: case MONO_CALL_FASTCALL: - case MONO_CALL_SWIFTCALL: case MONO_CALL_UNMANAGED_MD: method->pinvoke = 1; break; } + if (mono_method_signature_has_ext_callconv (method, MONO_EXT_CALLCONV_SWIFTCALL)) { + method->pinvoke = 1; + } + if (call_convention != 0xa) { method->ret = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [0] : 0, FALSE, ptr, &ptr, error); if (!method->ret) { @@ -5722,7 +5723,6 @@ mono_metadata_check_call_convention_category (unsigned int call_convention) case MONO_CALL_STDCALL: case MONO_CALL_THISCALL: case MONO_CALL_FASTCALL: - case MONO_CALL_SWIFTCALL: case MONO_CALL_UNMANAGED_MD: return 2; case MONO_CALL_VARARG: @@ -8134,7 +8134,6 @@ mono_guid_signature_append_method (GString *res, MonoMethodSignature *sig) case MONO_CALL_STDCALL: g_string_append (res, "unmanaged stdcall "); break; case MONO_CALL_THISCALL: g_string_append (res, "unmanaged thiscall "); break; case MONO_CALL_FASTCALL: g_string_append (res, "unmanaged fastcall "); break; - case MONO_CALL_SWIFTCALL: g_string_append (res, "unmanaged swiftcall "); break; case MONO_CALL_VARARG: g_string_append (res, "vararg "); break; default: break; } diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index d0b6534cf1bdde..233c01000c0f75 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1711,7 +1711,7 @@ ves_pinvoke_method ( #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP #ifdef MONO_ARCH_HAVE_SWIFTCALL - if (sig->call_convention == MONO_CALL_SWIFTCALL) { + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { int arg_index; gpointer data = mono_arch_get_swift_error (&ccontext, sig, call_info, &arg_index); diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 957e4ceaaa81d7..c650b5c02bd3b5 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3402,7 +3402,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target * the InterpMethod pointer. FIXME */ native = csignature->pinvoke || method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE; - if (!method->dynamic && !method->wrapper_type && csignature->pinvoke && !csignature->suppress_gc_transition) { + if (!method->dynamic && !method->wrapper_type && csignature->pinvoke && !mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION)) { // native calli needs a wrapper target_method = mono_marshal_get_native_func_wrapper_indirect (method->klass, csignature, FALSE); calli = FALSE; @@ -3748,7 +3748,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int *call_args = create_call_args (td, num_args); - if (csignature->call_convention == MONO_CALL_SWIFTCALL) { + if (mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); @@ -3866,7 +3866,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target #endif #endif // When using the Swift calling convention, emit MINT_CALLI_NAT opcode to manage context registers. - default_cconv = default_cconv && csignature->call_convention != MONO_CALL_SWIFTCALL; + default_cconv = default_cconv && !mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SWIFTCALL); // FIXME calli receives both the args offset and sometimes another arg for the frame pointer, // therefore some args are in the param area, while the fp is not. We should differentiate for diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index b01805e568699a..118ece2aa9e473 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7517,7 +7517,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b method->dynamic case; for other wrapper types assume the code knows what its doing and added its own GC transitions */ - gboolean skip_gc_trans = fsig->suppress_gc_transition; + gboolean skip_gc_trans = mono_method_signature_has_ext_callconv (fsig, MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION); if (!skip_gc_trans) { #if 0 fprintf (stderr, "generating wrapper for calli in method %s with wrapper type %s\n", method->name, mono_wrapper_type_to_str (method->wrapper_type)); @@ -11151,7 +11151,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b const MonoJitICallId jit_icall_id = (MonoJitICallId)token; MonoJitICallInfo * const jit_icall_info = mono_find_jit_icall_info (jit_icall_id); - if (method->wrapper_type == MONO_CALL_SWIFTCALL) { + if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 1e2f62e622a55e..f044e5b2ac7714 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1081,7 +1081,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) g_assert_not_reached (); } - if (sig->call_convention == MONO_CALL_SWIFTCALL) { + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); @@ -1670,7 +1670,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* We use the callee saved registers for global allocation */ regs = g_list_prepend (regs, (gpointer)AMD64_RBX); - if (cfg->method->signature->call_convention != MONO_CALL_SWIFTCALL) { + if (!mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { regs = g_list_prepend (regs, (gpointer)AMD64_R12); regs = g_list_prepend (regs, (gpointer)AMD64_R13); } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 40bfbe3795e455..c0747f366f9bc0 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1874,7 +1874,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } } - if (sig->call_convention == MONO_CALL_SWIFTCALL) { + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); @@ -2607,7 +2607,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* r28 is reserved for cfg->arch.args_reg */ /* r27 is reserved for the imt argument */ for (i = ARMREG_R19; i <= ARMREG_R26; ++i) { - if (!(cfg->method->signature->call_convention == MONO_CALL_SWIFTCALL && (i == ARMREG_R20 || i == ARMREG_R21))) + if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && (i == ARMREG_R20 || i == ARMREG_R21))) regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); } @@ -2714,7 +2714,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->used_int_regs |= 1 << ARMREG_R28; } - if (sig->call_convention == MONO_CALL_SWIFTCALL) { + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { g_assert (!(cfg->used_int_regs & (1 << ARMREG_R20))); cfg->used_int_regs |= 1 << ARMREG_R20; g_assert (!(cfg->used_int_regs & (1 << ARMREG_R21))); diff --git a/src/native/public/mono/metadata/details/metadata-types.h b/src/native/public/mono/metadata/details/metadata-types.h index ed1d1ad0e3825c..841f32fbb3521e 100644 --- a/src/native/public/mono/metadata/details/metadata-types.h +++ b/src/native/public/mono/metadata/details/metadata-types.h @@ -29,7 +29,6 @@ typedef enum { MONO_CALL_THISCALL, MONO_CALL_FASTCALL, MONO_CALL_VARARG = 0x05, - MONO_CALL_SWIFTCALL = 0x06, /* unused, */ /* unused, */ MONO_CALL_UNMANAGED_MD = 0x09, /* default unmanaged calling convention, with additional attributed encoded in modopts */ From b67c3c6e5bcecdac1e8538beade072dca9e826cf Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 17 Nov 2023 16:23:50 +0100 Subject: [PATCH 062/137] [mono] Throw NotImplementedException Swift calling convention on not supported --- src/mono/mono/mini/interp/transform.c | 5 +++++ src/mono/mono/mini/method-to-ir.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index c650b5c02bd3b5..ed43067cc9db53 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3749,6 +3749,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int *call_args = create_call_args (td, num_args); if (mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SWIFTCALL)) { +#ifdef MONO_ARCH_HAVE_SWIFTCALL MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); @@ -3771,6 +3772,10 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target mono_error_set_invalid_program (error, "Method signature contains multiple SwiftSelf/SwiftError arguments."); return FALSE; } +#else + mono_error_set_not_implemented (error, "CallConvSwift is not supported on this platform."); + return FALSE; +#endif } // We overwrite it with the return local, save it for future use diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 118ece2aa9e473..91804c482c38c2 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -11152,11 +11152,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoJitICallInfo * const jit_icall_info = mono_find_jit_icall_info (jit_icall_id); if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + ERROR_DECL (swiftcall_error); +#ifdef MONO_ARCH_HAVE_SWIFTCALL MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; - ERROR_DECL (swiftcall_error); for (int i = 0; i < method->signature->param_count; ++i) { MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); if (param_klass) { @@ -11179,6 +11180,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b emit_invalid_program_with_msg (cfg, swiftcall_error, method, cmethod); mono_error_cleanup (swiftcall_error); } +#else + emit_not_supported_failure (cfg); +#endif } CHECK_STACK (jit_icall_info->sig->param_count); From 4dad320c3964c1799321c05c1de203dd338de7c3 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 17 Nov 2023 18:05:45 +0100 Subject: [PATCH 063/137] [mono] Simplify runtime tests and add error logging --- src/mono/mono/mini/method-to-ir.c | 2 +- src/tests/Interop/CMakeLists.txt | 4 +- src/tests/Interop/Swift/CMakeLists.txt | 19 ----- src/tests/Interop/Swift/InvalidCallingConv.cs | 54 ------------ .../Swift/SwiftErrorHandling/CMakeLists.txt | 14 ++++ .../SwiftErrorHandling.cs} | 46 ++++++++--- .../SwiftErrorHandling.csproj | 2 +- .../SwiftErrorHandling.swift} | 0 .../Swift/SwiftInvalidCallConv/CMakeLists.txt | 14 ++++ .../SwiftInvalidCallConv.cs | 82 +++++++++++++++++++ .../SwiftInvalidCallConv.csproj} | 2 +- .../SwiftInvalidCallConv.swift} | 2 +- .../Swift/SwiftSelfContext/CMakeLists.txt | 14 ++++ .../SwiftSelfContext.cs} | 19 +++-- .../SwiftSelfContext.csproj | 2 +- .../SwiftSelfContext.swift} | 0 16 files changed, 175 insertions(+), 101 deletions(-) delete mode 100644 src/tests/Interop/Swift/CMakeLists.txt delete mode 100644 src/tests/Interop/Swift/InvalidCallingConv.cs create mode 100644 src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt rename src/tests/Interop/Swift/{ErrorHandling.cs => SwiftErrorHandling/SwiftErrorHandling.cs} (54%) rename src/tests/Interop/Swift/{ => SwiftErrorHandling}/SwiftErrorHandling.csproj (91%) rename src/tests/Interop/Swift/{ErrorHandling.swift => SwiftErrorHandling/SwiftErrorHandling.swift} (100%) create mode 100644 src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt create mode 100644 src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs rename src/tests/Interop/Swift/{SwiftInvalidCallingConv.csproj => SwiftInvalidCallConv/SwiftInvalidCallConv.csproj} (91%) rename src/tests/Interop/Swift/{Dummy.swift => SwiftInvalidCallConv/SwiftInvalidCallConv.swift} (82%) create mode 100644 src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt rename src/tests/Interop/Swift/{SelfContext.cs => SwiftSelfContext/SwiftSelfContext.cs} (53%) rename src/tests/Interop/Swift/{ => SwiftSelfContext}/SwiftSelfContext.csproj (91%) rename src/tests/Interop/Swift/{SelfContext.swift => SwiftSelfContext/SwiftSelfContext.swift} (100%) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 91804c482c38c2..700a8613fe6478 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -11152,12 +11152,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoJitICallInfo * const jit_icall_info = mono_find_jit_icall_info (jit_icall_id); if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - ERROR_DECL (swiftcall_error); #ifdef MONO_ARCH_HAVE_SWIFTCALL MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; + ERROR_DECL (swiftcall_error); for (int i = 0; i < method->signature->param_count; ++i) { MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); if (param_klass) { diff --git a/src/tests/Interop/CMakeLists.txt b/src/tests/Interop/CMakeLists.txt index 7eb6cf79ba32ae..9c3985d6ccd00e 100644 --- a/src/tests/Interop/CMakeLists.txt +++ b/src/tests/Interop/CMakeLists.txt @@ -103,5 +103,7 @@ endif(CLR_CMAKE_TARGET_UNIX) if(CLR_CMAKE_TARGET_APPLE) add_subdirectory(ObjectiveC/AutoReleaseTest) add_subdirectory(ObjectiveC/ObjectiveCMarshalAPI) - add_subdirectory(Swift) + add_subdirectory(Swift/SwiftErrorHandling) + add_subdirectory(Swift/SwiftSelfContext) + add_subdirectory(Swift/SwiftInvalidCallConv) endif() diff --git a/src/tests/Interop/Swift/CMakeLists.txt b/src/tests/Interop/Swift/CMakeLists.txt deleted file mode 100644 index b771e7330d92cb..00000000000000 --- a/src/tests/Interop/Swift/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -project(SwiftInteropLibraries) -include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") - -set(SWIFT_SOURCES - Dummy - ErrorHandling - SelfContext -) - -foreach(SOURCE ${SWIFT_SOURCES}) - add_custom_target(${SOURCE}SwiftLibrary ALL - COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift - COMMENT "Generating ${SOURCE} library" - ) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib - DESTINATION bin - ) -endforeach() diff --git a/src/tests/Interop/Swift/InvalidCallingConv.cs b/src/tests/Interop/Swift/InvalidCallingConv.cs deleted file mode 100644 index 9ede3e7a8e672b..00000000000000 --- a/src/tests/Interop/Swift/InvalidCallingConv.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Swift; -using Xunit; - -public class InvalidCallingConvTests -{ - private const string SwiftLib = "libDummy.dylib"; - - [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] - public static extern nint DummyFunc1(SwiftSelf self1, SwiftSelf self2); - - [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] - public unsafe static extern nint DummyFunc2(SwiftError* error1, SwiftError* error2); - - [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] - public unsafe static extern nint DummyFunc3(SwiftSelf self1, SwiftSelf self2, SwiftError* error1, SwiftError* error2); - - [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s5Dummy9dummyFuncyyF")] - public static extern nint DummyFunc4(SwiftError error1); - - [Fact] - public unsafe static int TestEntryPoint() - { - SwiftSelf self = new SwiftSelf(IntPtr.Zero); - SwiftError error = new SwiftError(IntPtr.Zero); - - try { - DummyFunc1(self, self); - return 101; - } catch (InvalidProgramException e) { } - try { - DummyFunc2(&error, &error); - return 102; - } catch (InvalidProgramException e) { } - try { - DummyFunc3(self, self, &error, &error); - return 103; - } catch (InvalidProgramException e) { } - try { - DummyFunc4(error); - return 104; - } catch (InvalidProgramException e) { } - return 100; - } -} diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt b/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt new file mode 100644 index 00000000000000..32dd8687a85158 --- /dev/null +++ b/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt @@ -0,0 +1,14 @@ +project(SwiftErrorHandling) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") + +set(SOURCE SwiftErrorHandling) + +add_custom_target(${SOURCE} ALL + COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift + COMMENT "Generating ${SOURCE} library" +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DESTINATION bin +) diff --git a/src/tests/Interop/Swift/ErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs similarity index 54% rename from src/tests/Interop/Swift/ErrorHandling.cs rename to src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 3ba4a0e44da180..85169e3851dae0 100644 --- a/src/tests/Interop/Swift/ErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -10,20 +10,20 @@ public class ErrorHandlingTests { - private const string SwiftLib = "libErrorHandling.dylib"; + private const string SwiftLib = "libSwiftErrorHandling.dylib"; - [DllImport(SwiftLib, EntryPoint = "$s13ErrorHandling05setMyA7Message5bytes6lengthySPys5UInt8VG_SitF")] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message5bytes6lengthySPys5UInt8VG_SitF")] public static extern void SetErrorMessage(byte[] strBytes, int length); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s13ErrorHandling018conditionallyThrowA004willD0SiSb_tKF")] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); - [DllImport(SwiftLib, EntryPoint = "$s13ErrorHandling05getMyA7Message4fromSPys5UInt8VGSgSPyAA0dA0OG_tF")] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4fromSPys5UInt8VGSgSPyAA0eB0OG_tF")] public static extern IntPtr GetErrorMessage(IntPtr handle); [Fact] - public unsafe static int TestEntryPoint() + public unsafe static void TestSwiftErrorThrown() { const string expectedErrorMessage = "Catch me if you can!"; SetErrorMessageForSwift(expectedErrorMessage); @@ -32,19 +32,39 @@ public unsafe static int TestEntryPoint() // This will throw an error conditionallyThrowError(true, &error); - if (error.Value == IntPtr.Zero) { - return 101; + + if (error.Value == IntPtr.Zero) + { + Assert.Fail("A Swift error was expected to be thrown."); } + string errorMessage = GetErrorMessageFromSwift(error, expectedErrorMessage.Length); - Assert.Equal(expectedErrorMessage, errorMessage); + if (errorMessage != expectedErrorMessage) + { + Assert.Fail("The error message retrieved from Swift does not match the expected message."); + } + } + + [Fact] + public unsafe static void TestSwiftErrorNotThrown() + { + const string expectedErrorMessage = "Catch me if you can!"; + SetErrorMessageForSwift(expectedErrorMessage); + + SwiftError error; // This will not throw an error - int result = (int) conditionallyThrowError(false, &error); - if (error.Value != IntPtr.Zero) { - return 102; + int result = (int)conditionallyThrowError(false, &error); + + if (error.Value != IntPtr.Zero) + { + Assert.Fail("No Swift error was expected to be thrown."); + } + + if (result != 42) + { + Assert.Fail("The result from Swift does not match the expected value."); } - Assert.Equal(42, result); - return 100; } private static void SetErrorMessageForSwift(string message) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj similarity index 91% rename from src/tests/Interop/Swift/SwiftErrorHandling.csproj rename to src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index 47e8d5d25a0cdb..62abae44ce1fa7 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -7,7 +7,7 @@ true - + diff --git a/src/tests/Interop/Swift/ErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift similarity index 100% rename from src/tests/Interop/Swift/ErrorHandling.swift rename to src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt b/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt new file mode 100644 index 00000000000000..67eca68857f1d1 --- /dev/null +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt @@ -0,0 +1,14 @@ +project(SwiftInvalidCallConv) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") + +set(SOURCE SwiftInvalidCallConv) + +add_custom_target(${SOURCE} ALL + COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift + COMMENT "Generating ${SOURCE} library" +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DESTINATION bin +) diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs new file mode 100644 index 00000000000000..0de8d9e94d585a --- /dev/null +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Swift; +using Xunit; + +public class InvalidCallingConvTests +{ + private const string SwiftLib = "libSwiftInvalidCallConv.dylib"; + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] + public static extern nint FuncWithTwoSelfParameters(SwiftSelf self1, SwiftSelf self2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] + public unsafe static extern nint FuncWithTwoErrorParameters(SwiftError* error1, SwiftError* error2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] + public unsafe static extern nint FuncWithMixedParameters(SwiftSelf self1, SwiftSelf self2, SwiftError* error1, SwiftError* error2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] + public static extern nint FuncWithSwiftErrorAsArg(SwiftError error1); + + [Fact] + public static void TestFuncWithTwoSelfParameters() + { + SwiftSelf self = new SwiftSelf(IntPtr.Zero); + + try + { + FuncWithTwoSelfParameters(self, self); + Assert.Fail("FuncWithTwoSelfParameters should have thrown InvalidProgramException"); + } + catch (InvalidProgramException e) { } + } + + [Fact] + public unsafe static void TestFuncWithTwoErrorParameters() + { + SwiftError error = new SwiftError(IntPtr.Zero); + + try + { + FuncWithTwoErrorParameters(&error, &error); + Assert.Fail("FuncWithTwoErrorParameters should have thrown InvalidProgramException"); + } + catch (InvalidProgramException e) { } + } + + [Fact] + public unsafe static void TestFuncWithMixedParameters() + { + SwiftSelf self = new SwiftSelf(IntPtr.Zero); + SwiftError error = new SwiftError(IntPtr.Zero); + + try + { + FuncWithMixedParameters(self, self, &error, &error); + Assert.Fail("FuncWithMixedParameters should have thrown InvalidProgramException"); + } + catch (InvalidProgramException e) { } + } + + [Fact] + public unsafe static void TestFuncWithSwiftErrorAsArg() + { + SwiftError error = new SwiftError(IntPtr.Zero); + + try + { + FuncWithSwiftErrorAsArg(error); + Assert.Fail("FuncWithSwiftErrorAsArg should have thrown InvalidProgramException"); + } + catch (InvalidProgramException e) { } + } +} diff --git a/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj similarity index 91% rename from src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj rename to src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index 57995b528b07c5..62abae44ce1fa7 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallingConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -7,7 +7,7 @@ true - + diff --git a/src/tests/Interop/Swift/Dummy.swift b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.swift similarity index 82% rename from src/tests/Interop/Swift/Dummy.swift rename to src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.swift index 4dfe8a7fff8b3a..f75d1f069a659b 100644 --- a/src/tests/Interop/Swift/Dummy.swift +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.swift @@ -1,4 +1,4 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -public func dummyFunc() { } +public func simpleFunc() { } diff --git a/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt b/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt new file mode 100644 index 00000000000000..874cd5501498db --- /dev/null +++ b/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt @@ -0,0 +1,14 @@ +project(SwiftSelfContext) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") + +set(SOURCE SwiftSelfContext) + +add_custom_target(${SOURCE} ALL + COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift + COMMENT "Generating ${SOURCE} library" +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + DESTINATION bin +) diff --git a/src/tests/Interop/Swift/SelfContext.cs b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs similarity index 53% rename from src/tests/Interop/Swift/SelfContext.cs rename to src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs index 8dd171bc698b19..6311c02ad760bf 100644 --- a/src/tests/Interop/Swift/SelfContext.cs +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs @@ -9,27 +9,28 @@ public class SelfContextTests { - private const string SwiftLib = "libSelfContext.dylib"; + private const string SwiftLib = "libSwiftSelfContext.dylib"; - [DllImport(SwiftLib, EntryPoint = "$s11SelfContext0A7LibraryC11getInstanceSvyFZ")] + [DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC11getInstanceSvyFZ")] public static extern IntPtr getInstance(); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s11SelfContext0A7LibraryC14getMagicNumberSiyF")] + [DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyF")] public static extern nint getMagicNumber(SwiftSelf self); [Fact] - public static int TestEntryPoint() + public static void TestSwiftSelfContext() { IntPtr pointer = getInstance(); SwiftSelf self = new SwiftSelf(pointer); if (self.Value == IntPtr.Zero) { - return 101; + Assert.Fail("Failed to obtain an instance of SwiftSelf from the Swift library."); + } else { + int result = (int)getMagicNumber(self); + if (result != 42) { + Assert.Fail("The result from Swift does not match the expected value."); + } } - - int result = (int) getMagicNumber(self); - Assert.Equal(42, result); - return 100; } } diff --git a/src/tests/Interop/Swift/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj similarity index 91% rename from src/tests/Interop/Swift/SwiftSelfContext.csproj rename to src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index c13b06e9e79f4e..62abae44ce1fa7 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -7,7 +7,7 @@ true - + diff --git a/src/tests/Interop/Swift/SelfContext.swift b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.swift similarity index 100% rename from src/tests/Interop/Swift/SelfContext.swift rename to src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.swift From c088a5778abb6bacdec1a640fa1cc67e773f529f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 17 Nov 2023 18:11:21 +0100 Subject: [PATCH 064/137] [mono] Add better error logging in test cases --- src/mono/mono/mini/method-to-ir.c | 2 +- .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 700a8613fe6478..8c9cfbb4d76bae 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -11163,7 +11163,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (param_klass) { if (param_klass == swift_error) { swift_error_args = swift_self_args = 0; - mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("SwiftError argument must be a reference."), mono_method_full_name (method, TRUE)); + mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("SwiftError argument must be a pointer."), mono_method_full_name (method, TRUE)); break; } else if (param_klass == swift_error_ptr) { swift_self_args++; diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs index 0de8d9e94d585a..9617aea375f25f 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -35,7 +35,7 @@ public static void TestFuncWithTwoSelfParameters() try { FuncWithTwoSelfParameters(self, self); - Assert.Fail("FuncWithTwoSelfParameters should have thrown InvalidProgramException"); + Assert.Fail("FuncWithTwoSelfParameters should have thrown InvalidProgramException. Invalid due to multiple SwiftSelf arguments."); } catch (InvalidProgramException e) { } } @@ -48,7 +48,7 @@ public unsafe static void TestFuncWithTwoErrorParameters() try { FuncWithTwoErrorParameters(&error, &error); - Assert.Fail("FuncWithTwoErrorParameters should have thrown InvalidProgramException"); + Assert.Fail("FuncWithTwoErrorParameters should have thrown InvalidProgramException. Invalid due to multiple SwiftError arguments."); } catch (InvalidProgramException e) { } } @@ -62,7 +62,7 @@ public unsafe static void TestFuncWithMixedParameters() try { FuncWithMixedParameters(self, self, &error, &error); - Assert.Fail("FuncWithMixedParameters should have thrown InvalidProgramException"); + Assert.Fail("FuncWithMixedParameters should have thrown InvalidProgramException. Invalid due to multiple SwiftSelf/SwiftError arguments."); } catch (InvalidProgramException e) { } } @@ -75,7 +75,7 @@ public unsafe static void TestFuncWithSwiftErrorAsArg() try { FuncWithSwiftErrorAsArg(error); - Assert.Fail("FuncWithSwiftErrorAsArg should have thrown InvalidProgramException"); + Assert.Fail("FuncWithSwiftErrorAsArg should have thrown InvalidProgramException. Invalid due to SwiftError not passed as a pointer."); } catch (InvalidProgramException e) { } } From 91e6955e1277749d39afcc7d86d4092d08e1e318 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 21 Nov 2023 10:33:18 +0100 Subject: [PATCH 065/137] Update src/native/public/mono/metadata/details/metadata-types.h Co-authored-by: Aaron Robinson --- src/native/public/mono/metadata/details/metadata-types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/native/public/mono/metadata/details/metadata-types.h b/src/native/public/mono/metadata/details/metadata-types.h index 841f32fbb3521e..7ae6ab2d3d95da 100644 --- a/src/native/public/mono/metadata/details/metadata-types.h +++ b/src/native/public/mono/metadata/details/metadata-types.h @@ -31,6 +31,7 @@ typedef enum { MONO_CALL_VARARG = 0x05, /* unused, */ /* unused, */ + /* unused, */ MONO_CALL_UNMANAGED_MD = 0x09, /* default unmanaged calling convention, with additional attributed encoded in modopts */ } MonoCallConvention; From 9327d1e1f97a20d7ba431213435d01542365500f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 21 Nov 2023 10:34:20 +0100 Subject: [PATCH 066/137] Update src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs Co-authored-by: Aaron Robinson --- .../Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 85169e3851dae0..e52b47c54ac937 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -56,15 +56,8 @@ public unsafe static void TestSwiftErrorNotThrown() // This will not throw an error int result = (int)conditionallyThrowError(false, &error); - if (error.Value != IntPtr.Zero) - { - Assert.Fail("No Swift error was expected to be thrown."); - } - - if (result != 42) - { - Assert.Fail("The result from Swift does not match the expected value."); - } + Assert.True(error.Value != IntPtr.Zero, "No Swift error was expected to be thrown."); + Assert.True(result != 42, "The result from Swift does not match the expected value."); } private static void SetErrorMessageForSwift(string message) From 5df0523aba95dd13bfb62509518e9b4a6414cbf2 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 21 Nov 2023 10:47:27 +0100 Subject: [PATCH 067/137] [tests] Update Swift tests to utilize Assert.True with error message --- .../Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 11 ++--------- .../Swift/SwiftSelfContext/SwiftSelfContext.cs | 11 +++-------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index e52b47c54ac937..dc968222c85944 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -32,17 +32,10 @@ public unsafe static void TestSwiftErrorThrown() // This will throw an error conditionallyThrowError(true, &error); - - if (error.Value == IntPtr.Zero) - { - Assert.Fail("A Swift error was expected to be thrown."); - } + Assert.True(error.Value == IntPtr.Zero, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error, expectedErrorMessage.Length); - if (errorMessage != expectedErrorMessage) - { - Assert.Fail("The error message retrieved from Swift does not match the expected message."); - } + Assert.True(errorMessage != expectedErrorMessage, "The error message retrieved from Swift does not match the expected message."); } [Fact] diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs index 6311c02ad760bf..5c1612774cf941 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs @@ -23,14 +23,9 @@ public static void TestSwiftSelfContext() { IntPtr pointer = getInstance(); SwiftSelf self = new SwiftSelf(pointer); + Assert.True(self.Value == IntPtr.Zero, "Failed to obtain an instance of SwiftSelf from the Swift library."); - if (self.Value == IntPtr.Zero) { - Assert.Fail("Failed to obtain an instance of SwiftSelf from the Swift library."); - } else { - int result = (int)getMagicNumber(self); - if (result != 42) { - Assert.Fail("The result from Swift does not match the expected value."); - } - } + int result = (int)getMagicNumber(self); + Assert.True(result != 42, "The result from Swift does not match the expected value."); } } From fc9178e080c5ab4904aff2d281f6ca83b4865cd7 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 21 Nov 2023 10:48:42 +0100 Subject: [PATCH 068/137] Remove README.md --- src/tests/Interop/Swift/README.md | 96 ------------------------------- 1 file changed, 96 deletions(-) delete mode 100644 src/tests/Interop/Swift/README.md diff --git a/src/tests/Interop/Swift/README.md b/src/tests/Interop/Swift/README.md deleted file mode 100644 index b8ca714bd46140..00000000000000 --- a/src/tests/Interop/Swift/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# .NET Swift Interop - -The Swift programming language has a different ABI, runtime environment, and object model, making it challenging to call from the .NET runtime. Existing solutions, like [Binding Tools for Swift](https://github.com/xamarin/binding-tools-for-swift) and [BeyondNet](https://github.com/royalapplications/beyondnet). - -This project aims to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. For a comprehensive .NET Swift interop, the Binding Tools for Swift contains valuable components that could be reused or built upon. - -We want to focus on the runtime support for direct P/Invoke interop with Swift, which Xamarin bindings will consume to support running Maui apps with third-party Swift libraries. Ideally, we want to avoid generating extra wrappers and attempt to directly call all kinds of Swift functions. While external tools can be helpful, they may introduce additional complexity, and we intend to integrate them into the .NET toolchain ecosystem. - -## Swift ABI in a nutshell - -The Swift ABI specifies how to call functions and how their data and metadata are represented in memory. Here are important components of the ABI that we need to consider. - -### Type layout - -The types we want to support are: blittable value types, non-blittable value types, tuples, classes/actors, existential containers, generics types, protocols with associated types, and closures. Objects of types are stored in registers or memory. A data member of an object is any value that requires layout within the object itself. Data members include an object's stored properties and associated values. A layout for static types is determined during the compilation, while the layout for opaque types is not determined until the runtime. For each type the alignment, size, and offset are calculated. - -Enabling library evolution simplifies marshaling rules to some extent. For each entry point, the Swift compiler generates a thunk that is forward compatible. For instance, if there is an enum parameter that would typically fit into registers, the created thunk takes the value by reference rather than by value to account for potential changes in the enum's size. Additionally, there are some edge cases where Swift compiler tries to optimize structs by allocating spare bits from the alignment. - -Memory management is handled by [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/). - -### Type metadata - -The Swift runtime keeps a metadata record for every type used in a program, including every instantiation of generic types. They can be used for class methods, reflection and debugger tools. The metadata layout consists of common properties and type-specific metadata. Common properties are value witness table pointer and kind. The value witness table references a vtable of functions that implement the value semantics of the type (alloc, copy, destroy, move). Additionally, it contains size, alignment, and type. The value witness table pointer is at`offset -1` from the metadata pointer, that is, the pointer-sized word immediately before the pointer's referenced address. This field is at offset 0 from the metadata pointer. - -### Calling convention - -In Swift programming language, functions parameters can be passed either by reference or value. This is called "pass-by-X" for consistency. Swift allows l-values parameters to be marked as pass-by-reference with"`in/out`. It's assumed the caller ensures validity and ownership of parameters in both cases. - -According to the calling convention, the `self`` context has dedicated registers, and it is always passed through them since it's heavily used. Methods calling other methods on the same object can share the self context. - -Here are cases when `self` context is passed via register: - - Instance methods on class types: pointer to self - - Class methods: pointer to type metadata (which may be subclass metadata) - - Mutating method on value types: pointer to the value (i.e. value is passed indirectly) - - Non-mutating methods on value types: self may fit in one or more registers, else passed indirectly - - Thick closures, i.e. closures requiring a context: the closure context - -Error handling is also handled through registers, so the caller needs to check for errors and throw if necessary. Similarly, the async context is handled through a register which contains a pointer to an object with information about the current state of the asynchronous operation. More details available at https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst. - -### Name mangling - -Swift uses mangling for generating unique names in a binary. This process can change in different major versions (i.e. Swift 4 vs Swift 5). The Swift compiler puts mangled names in binary images to encode type references for runtime instantiation and reflection. In a binary, these mangled names may contain pointers to runtime data structures to represent locally-defined types more efficiently. - -Be aware of the edge cases that can't be mapped 1:1 in C#. Consider the following example in Swift: -```swift -public static func getValue() -> Double { - return 5.0 -} - -public static func getValue() -> Int { - return 5 -} -``` - -The Swift compiler generates the following mangled names for the functions: -``` -_$s11MathLibraryAAC8getValueSdyFZ ---> static MathLibrary.MathLibrary.getValue() -> Swift.Double -_$s11MathLibraryAAC8getValueSiyFZ ---> static MathLibrary.MathLibrary.getValue() -> Swift.Int -``` - -In such case, generating entry points automatically from the C# would be problematic because both methods have the same name and parameter list, but different return types. According to the C# documentation, a return type of a method is not part of the signature of the method for the purposes of method overloading. - -https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods#method-signatures - -The Binding Tools for Swift resolves that by reading the native library, extracting the public symbols, and demangling them. On the runtime level the user is supposed to provide the mangled name as the entry point. - -## Goals - -The goal of this experiment is to explore the possibilities and limitations of direct P/Invoke interop with Swift. It should implement runtime mechanisms for handling Swift ABI differences. In the first iteration of the experiment, our focus will be on the self context and error handling calling conventions with blittable types targeting MacCatalyst. After that, we plan to expand support for non-blittable types using binding wrappers and to include other Apple targets. - -We can choose to first support Mono AOT either with or without LLVM according to the initial analysis. - -## Tasks - -Progress on the implementation can be tracked at https://github.com/dotnet/runtime/issues/93631. - -## Local build and testing - -Build the runtime: -```sh -./build.sh mono+libs+clr.hosts /p:KeepNativeSymbols=true -``` -Build the coreroot: -```sh -./src/tests/build.sh -mono debug generatelayoutonly /p:LibrariesConfiguration=Debug -``` -Build the tests: -```sh -./src/tests/build.sh -mono debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug -``` -Build the tests in full AOT mode: -```sh -./src/tests/build.sh -log:MonoAot -mono_fullaot debug -tree:Interop/Swift /p:LibrariesConfiguration=Debug /p:RuntimeVariant=llvmfullaot -``` -Run tests in full AOT mode: -- set `MONO_ENV_OPTIONS=--full-aot` and run as usual From 738d14d070b11cc66e327a4746eca2502e265cf7 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 21 Nov 2023 11:08:08 +0100 Subject: [PATCH 069/137] [tests] Document Swift error offset constants in the tests --- .../Swift/SwiftErrorHandling/SwiftErrorHandling.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index c2ba2860ff511f..1377eb9de05386 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -24,6 +24,11 @@ public func conditionallyThrowError(willThrow: Bool) throws -> Int { public func getMyErrorMessage(from pointer: UnsafePointer) -> UnsafePointer? { let pointerValue = UInt(bitPattern: pointer) + // The swift_allocError function allocates memory for a Swift error object. + // In this context, valuePtr is a pointer that points to the location within the + // allocated memory block where the payload of the Swift object is stored. + // The calculation involves adding an offset (offsetValue) to the instance pointer, + // accounting for an additional metadata or padding before the actual value. var offsetValue: UInt #if arch(arm64) offsetValue = 0x48 From dccf89ea21848e54f8de46a6c884f8d2a906c5d8 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 21 Nov 2023 14:38:38 +0100 Subject: [PATCH 070/137] Update MONO_ARCH_HAVE_SWIFTCALL condition --- src/mono/mono/mini/mini-amd64.h | 3 +-- src/mono/mono/mini/mini-arm64.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 7a0ca5a2b8d0c0..a8a66a5ae0969d 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -249,7 +249,6 @@ static const AMD64_XMM_Reg_No float_param_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD6 AMD64_XMM6, AMD64_XMM7}; static const AMD64_Reg_No return_regs [] = {AMD64_RAX, AMD64_RDX}; - #endif typedef struct { @@ -491,7 +490,7 @@ typedef struct { // can pass context to generics or interfaces? #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 -#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) #define MONO_ARCH_HAVE_SWIFTCALL 1 #endif diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index eaa5ed731a3b4a..2a730c800e3679 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -206,7 +206,7 @@ typedef struct { #define MONO_ARCH_EXPLICIT_NULL_CHECKS 1 #endif -#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) #define MONO_ARCH_HAVE_SWIFTCALL 1 #endif From 9a8cc672470ba31f2f77fd788ce128620cd336b4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 22 Nov 2023 11:16:41 +0100 Subject: [PATCH 071/137] Update src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs Co-authored-by: Jeremy Koritzinsky --- .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs index 9617aea375f25f..faa2c2bed89de1 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -32,12 +32,7 @@ public static void TestFuncWithTwoSelfParameters() { SwiftSelf self = new SwiftSelf(IntPtr.Zero); - try - { - FuncWithTwoSelfParameters(self, self); - Assert.Fail("FuncWithTwoSelfParameters should have thrown InvalidProgramException. Invalid due to multiple SwiftSelf arguments."); - } - catch (InvalidProgramException e) { } + Assert.Throws(() => FuncWithTwoSelfParameters(self, self)); } [Fact] From 8c5cf81f220a358983ff9319726e55a67346a68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Koz=C3=A1k?= Date: Wed, 22 Nov 2023 10:27:27 +0000 Subject: [PATCH 072/137] disable swift interop tests on mono windows --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 8fe55ce4e9a43c..b62c59a1e58eff 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2031,6 +2031,9 @@ https://github.com/dotnet/runtime/issues/67047 + + Not supported + From 6ee1c1ec895cffab99b0fce1a7fce6bfdc0f9cbd Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 22 Nov 2023 11:40:26 +0100 Subject: [PATCH 073/137] [tests] Update conditions to match Assert.True --- .../SwiftErrorHandling/SwiftErrorHandling.cs | 8 ++-- .../SwiftInvalidCallConv.cs | 41 +++++++------------ .../SwiftSelfContext/SwiftSelfContext.cs | 4 +- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index dc968222c85944..eabc08d31dd18c 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -32,10 +32,10 @@ public unsafe static void TestSwiftErrorThrown() // This will throw an error conditionallyThrowError(true, &error); - Assert.True(error.Value == IntPtr.Zero, "A Swift error was expected to be thrown."); + Assert.True(error.Value != IntPtr.Zero, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error, expectedErrorMessage.Length); - Assert.True(errorMessage != expectedErrorMessage, "The error message retrieved from Swift does not match the expected message."); + Assert.True(errorMessage == expectedErrorMessage, "The error message retrieved from Swift does not match the expected message."); } [Fact] @@ -49,8 +49,8 @@ public unsafe static void TestSwiftErrorNotThrown() // This will not throw an error int result = (int)conditionallyThrowError(false, &error); - Assert.True(error.Value != IntPtr.Zero, "No Swift error was expected to be thrown."); - Assert.True(result != 42, "The result from Swift does not match the expected value."); + Assert.True(error.Value == IntPtr.Zero, "No Swift error was expected to be thrown."); + Assert.True(result == 42, "The result from Swift does not match the expected value."); } private static void SetErrorMessageForSwift(string message) diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs index faa2c2bed89de1..b23213764ca710 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -30,48 +30,35 @@ public class InvalidCallingConvTests [Fact] public static void TestFuncWithTwoSelfParameters() { - SwiftSelf self = new SwiftSelf(IntPtr.Zero); - + // Invalid due to multiple SwiftSelf arguments. + SwiftSelf self = new SwiftSelf(); Assert.Throws(() => FuncWithTwoSelfParameters(self, self)); } [Fact] public unsafe static void TestFuncWithTwoErrorParameters() { - SwiftError error = new SwiftError(IntPtr.Zero); - - try - { - FuncWithTwoErrorParameters(&error, &error); - Assert.Fail("FuncWithTwoErrorParameters should have thrown InvalidProgramException. Invalid due to multiple SwiftError arguments."); - } - catch (InvalidProgramException e) { } + // Invalid due to multiple SwiftError arguments. + SwiftError error = new SwiftError(); + SwiftError* errorPtr = &error; + Assert.Throws(() => FuncWithTwoErrorParameters(errorPtr, errorPtr)); } [Fact] public unsafe static void TestFuncWithMixedParameters() { - SwiftSelf self = new SwiftSelf(IntPtr.Zero); - SwiftError error = new SwiftError(IntPtr.Zero); - - try - { - FuncWithMixedParameters(self, self, &error, &error); - Assert.Fail("FuncWithMixedParameters should have thrown InvalidProgramException. Invalid due to multiple SwiftSelf/SwiftError arguments."); - } - catch (InvalidProgramException e) { } + // Invalid due to multiple SwiftSelf/SwiftError arguments. + SwiftSelf self = new SwiftSelf(); + SwiftError error = new SwiftError(); + SwiftError* errorPtr = &error; + Assert.Throws(() => FuncWithMixedParameters(self, self, errorPtr, errorPtr)); } [Fact] public unsafe static void TestFuncWithSwiftErrorAsArg() { - SwiftError error = new SwiftError(IntPtr.Zero); - - try - { - FuncWithSwiftErrorAsArg(error); - Assert.Fail("FuncWithSwiftErrorAsArg should have thrown InvalidProgramException. Invalid due to SwiftError not passed as a pointer."); - } - catch (InvalidProgramException e) { } + // Invalid due to SwiftError not passed as a pointer. + SwiftError error = new SwiftError(); + Assert.Throws(() => FuncWithSwiftErrorAsArg(error)); } } diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs index 5c1612774cf941..96337eaf7d3d84 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs @@ -23,9 +23,9 @@ public static void TestSwiftSelfContext() { IntPtr pointer = getInstance(); SwiftSelf self = new SwiftSelf(pointer); - Assert.True(self.Value == IntPtr.Zero, "Failed to obtain an instance of SwiftSelf from the Swift library."); + Assert.True(self.Value != IntPtr.Zero, "Failed to obtain an instance of SwiftSelf from the Swift library."); int result = (int)getMagicNumber(self); - Assert.True(result != 42, "The result from Swift does not match the expected value."); + Assert.True(result == 42, "The result from Swift does not match the expected value."); } } From 5c5daad6ee42cc44340cbc7b7cb865b9be799ee0 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 23 Nov 2023 09:44:03 +0100 Subject: [PATCH 074/137] [tests] Simplify error handling tests by taking Error instead of UnsafePointer --- .../SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- .../SwiftErrorHandling.swift | 27 +++---------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index eabc08d31dd18c..2b93b7cf2f8749 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -19,7 +19,7 @@ public class ErrorHandlingTests [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4fromSPys5UInt8VGSgSPyAA0eB0OG_tF")] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4fromSPys5UInt8VGSgs0B0_p_tF")] public static extern IntPtr GetErrorMessage(IntPtr handle); [Fact] diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 1377eb9de05386..7e6cc5e4a312b6 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -22,34 +22,15 @@ public func conditionallyThrowError(willThrow: Bool) throws -> Int { } } -public func getMyErrorMessage(from pointer: UnsafePointer) -> UnsafePointer? { - let pointerValue = UInt(bitPattern: pointer) - // The swift_allocError function allocates memory for a Swift error object. - // In this context, valuePtr is a pointer that points to the location within the - // allocated memory block where the payload of the Swift object is stored. - // The calculation involves adding an offset (offsetValue) to the instance pointer, - // accounting for an additional metadata or padding before the actual value. - var offsetValue: UInt -#if arch(arm64) - offsetValue = 0x48 -#elseif arch(x86_64) - offsetValue = 0x20 -#else - fatalError("Unsupported architecture") -#endif - let offsetPointerValue = pointerValue + offsetValue - let offsetPointer = UnsafeRawPointer(bitPattern: offsetPointerValue) - - if let offsetErrorPointer = offsetPointer?.assumingMemoryBound(to: MyError.self) { - let errorInstance = offsetErrorPointer.pointee - switch errorInstance { +public func getMyErrorMessage(from error: Error) -> UnsafePointer? { + if let myError = error as? MyError { + switch myError { case .runtimeError(let message): let messageBytes: [UInt8] = Array(message.utf8) let buffer = UnsafeMutableBufferPointer.allocate(capacity: messageBytes.count) _ = buffer.initialize(from: messageBytes) return UnsafePointer(buffer.baseAddress!) } - } else { - return nil } + return nil } From f4127211244fcf143077121d8a122387219e31df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Koz=C3=A1k?= Date: Mon, 27 Nov 2023 11:39:36 +0000 Subject: [PATCH 075/137] add process isolation to runtime tests --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj | 2 ++ .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj | 2 ++ .../Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index 62abae44ce1fa7..59fbbe13e868f2 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -1,6 +1,8 @@ Exe + + true true true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index 62abae44ce1fa7..59fbbe13e868f2 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -1,6 +1,8 @@ Exe + + true true true diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index 62abae44ce1fa7..59fbbe13e868f2 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -1,6 +1,8 @@ Exe + + true true true From 9482a7923778f0c4016cde1ff684145b06b9a99c Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 27 Nov 2023 13:07:56 +0000 Subject: [PATCH 076/137] enable Swift tests on Apple OS --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj | 2 +- .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj | 2 +- .../Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index 59fbbe13e868f2..c1db8d2de9b855 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -6,7 +6,7 @@ true true - true + true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index 59fbbe13e868f2..c1db8d2de9b855 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -6,7 +6,7 @@ true true - true + true diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index 59fbbe13e868f2..c1db8d2de9b855 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -6,7 +6,7 @@ true true - true + true From 883d64554978d2420cff52635f9e31a14b0fa5ef Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 27 Nov 2023 14:59:38 +0000 Subject: [PATCH 077/137] Revert "enable Swift tests on Apple OS" This reverts commit 9482a7923778f0c4016cde1ff684145b06b9a99c. --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj | 2 +- .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj | 2 +- .../Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index c1db8d2de9b855..59fbbe13e868f2 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -6,7 +6,7 @@ true true - true + true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index c1db8d2de9b855..59fbbe13e868f2 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -6,7 +6,7 @@ true true - true + true diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index c1db8d2de9b855..59fbbe13e868f2 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -6,7 +6,7 @@ true true - true + true From 4f788fcc15802039a6beb3a9bd87c98a8f3aa2a8 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 27 Nov 2023 15:07:57 +0000 Subject: [PATCH 078/137] enable Swift tests on OSX --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj | 2 +- .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj | 2 +- .../Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index 59fbbe13e868f2..f5d4d8f11fe3b0 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -6,7 +6,7 @@ true true - true + true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index 59fbbe13e868f2..f5d4d8f11fe3b0 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -6,7 +6,7 @@ true true - true + true diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index 59fbbe13e868f2..f5d4d8f11fe3b0 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -6,7 +6,7 @@ true true - true + true From 7b689a2c752f4df45b705f775d76bb94da19f1fe Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 4 Dec 2023 15:43:22 +0100 Subject: [PATCH 079/137] Add pointer deallocation in SwiftError test --- src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 2b93b7cf2f8749..0d9b61b8476eea 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -64,6 +64,7 @@ private static string GetErrorMessageFromSwift(SwiftError error, int length) IntPtr pointer = GetErrorMessage(error.Value); byte[] byteArray = new byte[length]; Marshal.Copy(pointer, byteArray, 0, length); + Marshal.FreeCoTaskMem(pointer); return Encoding.UTF8.GetString(byteArray); } } From 152fa6e70cd345307e3972fc38895c9ddee67f59 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 4 Dec 2023 16:33:16 +0100 Subject: [PATCH 080/137] Use NativeLibrary.Free for Swift interop scenarios --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 0d9b61b8476eea..da0a7c18023552 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -64,7 +64,7 @@ private static string GetErrorMessageFromSwift(SwiftError error, int length) IntPtr pointer = GetErrorMessage(error.Value); byte[] byteArray = new byte[length]; Marshal.Copy(pointer, byteArray, 0, length); - Marshal.FreeCoTaskMem(pointer); + NativeLibrary.Free(pointer); return Encoding.UTF8.GetString(byteArray); } } From c732e25976046df95830ea81f7dac390fd3aa747 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 4 Dec 2023 17:30:06 +0100 Subject: [PATCH 081/137] Update src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs Co-authored-by: Jan Kotas --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index da0a7c18023552..1725f03ae502c9 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -64,7 +64,7 @@ private static string GetErrorMessageFromSwift(SwiftError error, int length) IntPtr pointer = GetErrorMessage(error.Value); byte[] byteArray = new byte[length]; Marshal.Copy(pointer, byteArray, 0, length); - NativeLibrary.Free(pointer); + NativeMemory.Free(pointer); return Encoding.UTF8.GetString(byteArray); } } From 40f6e355b86fbeb1d646a71368c8579658fbfe45 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 4 Dec 2023 18:36:29 +0100 Subject: [PATCH 082/137] Use ReadOnlySpan in GetErrorMessageFromSwift --- .../Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index da0a7c18023552..a04e6d099471b6 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -59,12 +59,12 @@ private static void SetErrorMessageForSwift(string message) SetErrorMessage(messageBytes, messageBytes.Length); } - private static string GetErrorMessageFromSwift(SwiftError error, int length) + private unsafe static string GetErrorMessageFromSwift(SwiftError error, int length) { IntPtr pointer = GetErrorMessage(error.Value); - byte[] byteArray = new byte[length]; - Marshal.Copy(pointer, byteArray, 0, length); + ReadOnlySpan byteArraySpan = new ReadOnlySpan((void*)pointer, length); + string errorMessage = Encoding.UTF8.GetString(byteArraySpan); NativeLibrary.Free(pointer); - return Encoding.UTF8.GetString(byteArray); + return errorMessage; } } From c29a35f6c1f092fbb4186d181cee8360183c3b87 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 4 Dec 2023 18:40:20 +0100 Subject: [PATCH 083/137] Use NativeMemory.Free in GetErrorMessageFromSwift --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index c0d5adfb4ff57b..a8811ab422d683 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -64,7 +64,7 @@ private unsafe static string GetErrorMessageFromSwift(SwiftError error, int leng IntPtr pointer = GetErrorMessage(error.Value); ReadOnlySpan byteArraySpan = new ReadOnlySpan((void*)pointer, length); string errorMessage = Encoding.UTF8.GetString(byteArraySpan); - NativeMemory.Free(pointer); + NativeMemory.Free((void*)pointer); return errorMessage; } } From 8663c3c4dd9ca66b53d32742b222ae06b0fcecdd Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 5 Dec 2023 10:07:02 +0100 Subject: [PATCH 084/137] Simplify GetErrorMessageFromSwift to copy zero-terminated C string --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index a8811ab422d683..a5b75823ab7aa5 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -34,7 +34,7 @@ public unsafe static void TestSwiftErrorThrown() conditionallyThrowError(true, &error); Assert.True(error.Value != IntPtr.Zero, "A Swift error was expected to be thrown."); - string errorMessage = GetErrorMessageFromSwift(error, expectedErrorMessage.Length); + string errorMessage = GetErrorMessageFromSwift(error); Assert.True(errorMessage == expectedErrorMessage, "The error message retrieved from Swift does not match the expected message."); } @@ -59,11 +59,10 @@ private static void SetErrorMessageForSwift(string message) SetErrorMessage(messageBytes, messageBytes.Length); } - private unsafe static string GetErrorMessageFromSwift(SwiftError error, int length) + private unsafe static string GetErrorMessageFromSwift(SwiftError error) { IntPtr pointer = GetErrorMessage(error.Value); - ReadOnlySpan byteArraySpan = new ReadOnlySpan((void*)pointer, length); - string errorMessage = Encoding.UTF8.GetString(byteArraySpan); + string errorMessage = Marshal.PtrToStringUTF8(pointer); NativeMemory.Free((void*)pointer); return errorMessage; } From 3ed6733d5d4aff7666d73bd0a8a4d927603e1043 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 5 Dec 2023 11:16:39 +0100 Subject: [PATCH 085/137] remove OutputType Exe from tests --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj | 1 - .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj | 1 - src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj | 1 - 3 files changed, 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index f5d4d8f11fe3b0..18f877082a8e36 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -1,6 +1,5 @@ - Exe true true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index f5d4d8f11fe3b0..18f877082a8e36 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -1,6 +1,5 @@ - Exe true true diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index f5d4d8f11fe3b0..18f877082a8e36 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -1,6 +1,5 @@ - Exe true true From cb206909adf137a28958911b4e450a31ab50c68f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 6 Dec 2023 22:14:49 +0100 Subject: [PATCH 086/137] [mono][interp] Implement context register backup and restore mechanism This commit adds backup and restore ins for all context registers. In the first part, the tramp backups all context registers by storing them in the ccontext. In the second part, the tramp restores all context registers by loading them from the ccontext. This is necessary for maintaining the execution context after the native call. --- src/mono/mono/mini/tramp-amd64.c | 14 ++++++++++---- src/mono/mono/mini/tramp-arm64.c | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 72f113a213a0d5..f5dc23f51f27d2 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1097,9 +1097,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_PARAM_REGS; ++i) amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); - /* set all context registers from CallContext */ - for (i = 0; i < CTX_REGS; i++) + /* backup all context registers and set from CallContext */ + for (i = 0; i < CTX_REGS; i++) { + amd64_mov_reg_reg (code, AMD64_R10, i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), AMD64_R10, sizeof (target_mgreg_t)); + } /* load target addr */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (target_mgreg_t)); @@ -1116,9 +1119,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_RETURN_REGS; i++) amd64_sse_movsd_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double), i); - /* set all context registers to CallContext */ - for (i = 0; i < CTX_REGS; i++) + /* restore all context registers and set to CallContext */ + for (i = 0; i < CTX_REGS; i++) { + amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); + amd64_mov_reg_reg (code, i + CTX_REGS_OFFSET, AMD64_R10, sizeof (target_mgreg_t)); + } #if TARGET_WIN32 amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0); diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index f24854ac119e71..5e9496f9426901 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -722,9 +722,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); - /* set all context registers from CallContext */ - for (i = 0; i < CTX_REGS; i++) + /* backup all context registers and set from CallContext */ + for (i = 0; i < CTX_REGS; i++) { + arm_movx (code, ARMREG_IP1, i + CTX_REGS_OFFSET); arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); + arm_strx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); + } /* load target addr */ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_targetaddr); @@ -743,9 +746,12 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); - /* set all context registers to CallContext */ - for (i = 0; i < CTX_REGS; i++) + /* restore all context registers and set to CallContext */ + for (i = 0; i < CTX_REGS; i++) { + arm_ldrx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); + arm_movx (code, i + CTX_REGS_OFFSET, ARMREG_IP1); + } arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); From da5279b696465115828e99e3d57121c7f5db8fbf Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 7 Dec 2023 12:43:31 +0100 Subject: [PATCH 087/137] remove BuildAsStandalone --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj | 1 - .../Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj | 1 - src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj | 1 - 3 files changed, 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj index 18f877082a8e36..a57cd84cf8842c 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.csproj @@ -3,7 +3,6 @@ true true - true true diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj index 18f877082a8e36..a57cd84cf8842c 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.csproj @@ -3,7 +3,6 @@ true true - true true diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj index 18f877082a8e36..a57cd84cf8842c 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.csproj @@ -3,7 +3,6 @@ true true - true true From a32421ace9b22884978c405bb01feb9011b8e4d1 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 7 Dec 2023 16:19:10 +0100 Subject: [PATCH 088/137] [mono][interp] Refactor context register backup and restore mechanism This commit updates backup and restore mechanism for all context registers. The native trampoline should always restore the original value of the ctx_regs to be compatible with C cconv. Before the native call, all context registers are saved onto the stack. After the native call, the context registers are saved in ccontext and then restored from the stack. --- src/mono/mono/mini/tramp-amd64.c | 29 +++++++++++++++++------------ src/mono/mono/mini/tramp-arm64.c | 15 ++++++++------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index f5dc23f51f27d2..322372d8ed5f92 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1035,7 +1035,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) guint8 *label_start_copy, *label_exit_copy; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; - int buf_len, i, cfa_offset, off_methodargs, off_targetaddr; + int buf_len, i, cfa_offset, framesize = 8, off_ctxregs, off_methodargs, off_targetaddr; buf_len = 512; start = code = (guint8 *) mono_global_codeman_reserve (buf_len + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE); @@ -1055,15 +1055,22 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) mono_add_unwind_op_def_cfa_reg (unwind_ops, code, start, AMD64_RBP); mono_add_unwind_op_fp_alloc (unwind_ops, code, start, AMD64_RBP, 0); - /* allocate space for saving the target addr and the call context */ - amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 2 * sizeof (target_mgreg_t)); + /* allocate space for saving the target addr, call context, and context registers */ + off_ctxregs = -framesize; + framesize += CTX_REGS * sizeof (host_mgreg_t); + + off_methodargs = -framesize; + framesize += sizeof (host_mgreg_t); + + off_targetaddr = -framesize; + framesize += sizeof (host_mgreg_t); + + amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, (framesize - 8) * sizeof (target_mgreg_t)); /* save CallContext* onto stack */ - off_methodargs = - 8; amd64_mov_membase_reg (code, AMD64_RBP, off_methodargs, AMD64_ARG_REG2, sizeof (target_mgreg_t)); /* save target address on stack */ - off_targetaddr = - 2 * 8; amd64_mov_membase_reg (code, AMD64_RBP, off_targetaddr, AMD64_ARG_REG1, sizeof (target_mgreg_t)); /* load pointer to CallContext* into R11 */ @@ -1097,11 +1104,10 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_PARAM_REGS; ++i) amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); - /* backup all context registers and set from CallContext */ + /* store the values of context registers onto the stack and set the context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) { - amd64_mov_reg_reg (code, AMD64_R10, i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); - amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); - amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), AMD64_R10, sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_RBP, off_ctxregs - i * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); + amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); } /* load target addr */ @@ -1119,11 +1125,10 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_RETURN_REGS; i++) amd64_sse_movsd_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double), i); - /* restore all context registers and set to CallContext */ + /* set context registers to CallContext and load context registers from the stack */ for (i = 0; i < CTX_REGS; i++) { - amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); - amd64_mov_reg_reg (code, i + CTX_REGS_OFFSET, AMD64_R10, sizeof (target_mgreg_t)); + amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_RBP, off_ctxregs - i * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); } #if TARGET_WIN32 diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index 5e9496f9426901..9c52f33f054ec2 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -660,7 +660,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) guint8 *label_start_copy, *label_exit_copy; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; - int buf_len, i, framesize = 0, off_methodargs, off_targetaddr; + int buf_len, i, framesize = 0, off_ctxregs, off_methodargs, off_targetaddr; buf_len = 512 + 1024; start = code = (guint8 *) mono_global_codeman_reserve (buf_len); @@ -668,6 +668,9 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* allocate frame */ framesize += 2 * sizeof (host_mgreg_t); + off_ctxregs = framesize; + framesize += CTX_REGS * sizeof (host_mgreg_t); + off_methodargs = framesize; framesize += sizeof (host_mgreg_t); @@ -722,11 +725,10 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); - /* backup all context registers and set from CallContext */ + /* store the values of context registers onto the stack and set the context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) { - arm_movx (code, ARMREG_IP1, i + CTX_REGS_OFFSET); + arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_FP, off_ctxregs + i * sizeof (host_mgreg_t)); arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); - arm_strx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); } /* load target addr */ @@ -746,11 +748,10 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); - /* restore all context registers and set to CallContext */ + /* set context registers to CallContext and load context registers from the stack */ for (i = 0; i < CTX_REGS; i++) { - arm_ldrx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); - arm_movx (code, i + CTX_REGS_OFFSET, ARMREG_IP1); + arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_FP, off_ctxregs + i * sizeof (host_mgreg_t)); } arm_movspx (code, ARMREG_SP, ARMREG_FP); From 3b1b4dd3ba42a07d39ace40c9d1ee8ebb085006e Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 7 Dec 2023 18:09:58 +0100 Subject: [PATCH 089/137] add expected error printout --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index a5b75823ab7aa5..7ecaf72e69c0b1 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -35,7 +35,7 @@ public unsafe static void TestSwiftErrorThrown() Assert.True(error.Value != IntPtr.Zero, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); - Assert.True(errorMessage == expectedErrorMessage, "The error message retrieved from Swift does not match the expected message."); + Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: {0}, Actual: {1}", expectedErrorMessage, errorMessage)); } [Fact] From 37230be6d33c289a061759df6151b8089d0f3d45 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 7 Dec 2023 18:10:44 +0100 Subject: [PATCH 090/137] null-terminate error message string --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 7ecaf72e69c0b1..c228bbb34de70e 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -55,7 +55,7 @@ public unsafe static void TestSwiftErrorNotThrown() private static void SetErrorMessageForSwift(string message) { - var messageBytes = Encoding.UTF8.GetBytes(message); + var messageBytes = Encoding.UTF8.GetBytes(message + char.MinValue); // Add null terminator SetErrorMessage(messageBytes, messageBytes.Length); } From c25d435bb7a7cefc337fee04024a5b37ef3b3026 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Fri, 8 Dec 2023 15:33:43 +0100 Subject: [PATCH 091/137] Revert "null-terminate error message string" This reverts commit 37230be6d33c289a061759df6151b8089d0f3d45. --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index c228bbb34de70e..7ecaf72e69c0b1 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -55,7 +55,7 @@ public unsafe static void TestSwiftErrorNotThrown() private static void SetErrorMessageForSwift(string message) { - var messageBytes = Encoding.UTF8.GetBytes(message + char.MinValue); // Add null terminator + var messageBytes = Encoding.UTF8.GetBytes(message); SetErrorMessage(messageBytes, messageBytes.Length); } From a57307f3e9fc393f796ec6e073531c210634c857 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Fri, 8 Dec 2023 17:23:56 +0100 Subject: [PATCH 092/137] refactor SwiftErrorHandling to use NSString --- .../SwiftErrorHandling/SwiftErrorHandling.cs | 10 +++++----- .../SwiftErrorHandling/SwiftErrorHandling.swift | 16 +++++++--------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 7ecaf72e69c0b1..978b23b5b52a57 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -12,14 +12,14 @@ public class ErrorHandlingTests { private const string SwiftLib = "libSwiftErrorHandling.dylib"; - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message5bytes6lengthySPys5UInt8VG_SitF")] - public static extern void SetErrorMessage(byte[] strBytes, int length); + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message7message6lengthySPys6UInt16VG_SitF")] + public static extern void SetErrorMessage(char[] message, int length); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4fromSPys5UInt8VGSgs0B0_p_tF")] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4fromSPys6UInt16VGSgs0B0_p_tF")] public static extern IntPtr GetErrorMessage(IntPtr handle); [Fact] @@ -55,8 +55,8 @@ public unsafe static void TestSwiftErrorNotThrown() private static void SetErrorMessageForSwift(string message) { - var messageBytes = Encoding.UTF8.GetBytes(message); - SetErrorMessage(messageBytes, messageBytes.Length); + char[] buffer = message.ToCharArray(); + SetErrorMessage(buffer, buffer.Length); } private unsafe static string GetErrorMessageFromSwift(SwiftError error) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 7e6cc5e4a312b6..28115e1bde388c 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -4,14 +4,13 @@ import Foundation public enum MyError: Error { - case runtimeError(message: String) + case runtimeError(message: NSString) } -var errorMessage: String = "" +var errorMessage: NSString = "" -public func setMyErrorMessage(bytes: UnsafePointer, length: Int) { - let data = Data(bytes: bytes, count: length) - errorMessage = String(data: data, encoding: .utf8)! +public func setMyErrorMessage(message: UnsafePointer, length: Int) { + errorMessage = NSString(characters: message, length: length) } public func conditionallyThrowError(willThrow: Bool) throws -> Int { @@ -22,13 +21,12 @@ public func conditionallyThrowError(willThrow: Bool) throws -> Int { } } -public func getMyErrorMessage(from error: Error) -> UnsafePointer? { +public func getMyErrorMessage(from error: Error) -> UnsafePointer? { if let myError = error as? MyError { switch myError { case .runtimeError(let message): - let messageBytes: [UInt8] = Array(message.utf8) - let buffer = UnsafeMutableBufferPointer.allocate(capacity: messageBytes.count) - _ = buffer.initialize(from: messageBytes) + let buffer = UnsafeMutableBufferPointer.allocate(capacity: message.length) + message.getCharacters(buffer.baseAddress!, range: NSRange(location: 0, length: message.length)) return UnsafePointer(buffer.baseAddress!) } } From 1fe961130f25ed7dac355b90867ba92705b91218 Mon Sep 17 00:00:00 2001 From: Matous Kozak <55735845+matouskozak@users.noreply.github.com> Date: Sat, 9 Dec 2023 11:51:26 +0100 Subject: [PATCH 093/137] Update src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs Co-authored-by: Jan Kotas --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 978b23b5b52a57..81f9d39b34e51b 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -55,8 +55,7 @@ public unsafe static void TestSwiftErrorNotThrown() private static void SetErrorMessageForSwift(string message) { - char[] buffer = message.ToCharArray(); - SetErrorMessage(buffer, buffer.Length); + SetErrorMessage(message, message.Length); } private unsafe static string GetErrorMessageFromSwift(SwiftError error) From e256556dac73bb06ef648e1681c14c32af71e7b8 Mon Sep 17 00:00:00 2001 From: Matous Kozak <55735845+matouskozak@users.noreply.github.com> Date: Sat, 9 Dec 2023 11:51:49 +0100 Subject: [PATCH 094/137] Update src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs Co-authored-by: Jan Kotas --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 81f9d39b34e51b..72b72f82ee35bf 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -12,8 +12,8 @@ public class ErrorHandlingTests { private const string SwiftLib = "libSwiftErrorHandling.dylib"; - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message7message6lengthySPys6UInt16VG_SitF")] - public static extern void SetErrorMessage(char[] message, int length); + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message7message6lengthySPys6UInt16VG_SitF", CharSet = CharSet.Unicode)] + public static extern void SetErrorMessage(string message, int length); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] From e9ce7d9e3051c4de9080b61f1c6f7823d10c7251 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Sat, 9 Dec 2023 11:53:46 +0100 Subject: [PATCH 095/137] Change PtrToStringUTF8 to PtrToStringUni --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 72b72f82ee35bf..3058d1d7fa412a 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -61,7 +61,7 @@ private static void SetErrorMessageForSwift(string message) private unsafe static string GetErrorMessageFromSwift(SwiftError error) { IntPtr pointer = GetErrorMessage(error.Value); - string errorMessage = Marshal.PtrToStringUTF8(pointer); + string errorMessage = Marshal.PtrToStringUni(pointer); NativeMemory.Free((void*)pointer); return errorMessage; } From 91a3263bfaac681e1fe79acdd50d827a668d2433 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 11 Dec 2023 16:00:38 +0100 Subject: [PATCH 096/137] Change Swift to receive Int32 instead of Int --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 3058d1d7fa412a..14b523f4d879cd 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -12,7 +12,7 @@ public class ErrorHandlingTests { private const string SwiftLib = "libSwiftErrorHandling.dylib"; - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message7message6lengthySPys6UInt16VG_SitF", CharSet = CharSet.Unicode)] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05setMyB7Message7message6lengthySPys6UInt16VG_s5Int32VtF", CharSet = CharSet.Unicode)] public static extern void SetErrorMessage(string message, int length); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 28115e1bde388c..78591f65a9b22e 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -9,8 +9,8 @@ public enum MyError: Error { var errorMessage: NSString = "" -public func setMyErrorMessage(message: UnsafePointer, length: Int) { - errorMessage = NSString(characters: message, length: length) +public func setMyErrorMessage(message: UnsafePointer, length: Int32) { + errorMessage = NSString(characters: message, length: Int(length)) } public func conditionallyThrowError(willThrow: Bool) throws -> Int { From 97a74cc2843028a7679ec8e67193b8f61b32c7ba Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 12 Dec 2023 09:17:09 +0100 Subject: [PATCH 097/137] null-terminate error message in swift We must add null-terminator on the swift side to the end of the string so that it can be read correctly by PtrToStringUni on C# side (requires null-terminator). There is a swift function that could be used https://developer.apple.com/documentation/foundation/nsstring/1415702-getcstring for this but it works with CChar not unichar. CChar is C-char like type which is either signed or unsigned depending on the platform. I don't think C# has a similar type to map onto so I think it is better to stick with unichar and add null-terminator manually. --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 14b523f4d879cd..c63d5d21f19d3b 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -35,7 +35,7 @@ public unsafe static void TestSwiftErrorThrown() Assert.True(error.Value != IntPtr.Zero, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); - Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: {0}, Actual: {1}", expectedErrorMessage, errorMessage)); + Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: '{0}', Actual: '{1}'", expectedErrorMessage, errorMessage)); } [Fact] diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 78591f65a9b22e..224c29d2708741 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -25,8 +25,9 @@ public func getMyErrorMessage(from error: Error) -> UnsafePointer? { if let myError = error as? MyError { switch myError { case .runtimeError(let message): - let buffer = UnsafeMutableBufferPointer.allocate(capacity: message.length) + let buffer = UnsafeMutableBufferPointer.allocate(capacity: message.length + 1) message.getCharacters(buffer.baseAddress!, range: NSRange(location: 0, length: message.length)) + buffer[message.length] = 0 // must be null terminated so that it can be read by managed code return UnsafePointer(buffer.baseAddress!) } } From 5384dceaa7f2a8d7d0474b134834dd937564af82 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 12 Dec 2023 20:17:37 +0100 Subject: [PATCH 098/137] Revert "null-terminate error message in swift" This reverts commit 97a74cc2843028a7679ec8e67193b8f61b32c7ba. --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 2 +- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index c63d5d21f19d3b..14b523f4d879cd 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -35,7 +35,7 @@ public unsafe static void TestSwiftErrorThrown() Assert.True(error.Value != IntPtr.Zero, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); - Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: '{0}', Actual: '{1}'", expectedErrorMessage, errorMessage)); + Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: {0}, Actual: {1}", expectedErrorMessage, errorMessage)); } [Fact] diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 224c29d2708741..78591f65a9b22e 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -25,9 +25,8 @@ public func getMyErrorMessage(from error: Error) -> UnsafePointer? { if let myError = error as? MyError { switch myError { case .runtimeError(let message): - let buffer = UnsafeMutableBufferPointer.allocate(capacity: message.length + 1) + let buffer = UnsafeMutableBufferPointer.allocate(capacity: message.length) message.getCharacters(buffer.baseAddress!, range: NSRange(location: 0, length: message.length)) - buffer[message.length] = 0 // must be null terminated so that it can be read by managed code return UnsafePointer(buffer.baseAddress!) } } From 7103cfc19b5ef32120ddb74b9c03d68ad49da472 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 12 Dec 2023 20:18:22 +0100 Subject: [PATCH 099/137] Retrieve both content and length of error message We need to use Int32 on Swift side to match C# int behavior. Swift integer size is 32-bit or 64-bit depending on the platform. --- .../Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 9 +++++---- .../Swift/SwiftErrorHandling/SwiftErrorHandling.swift | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 14b523f4d879cd..92ef38438ae6fe 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -19,8 +19,8 @@ public class ErrorHandlingTests [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4fromSPys6UInt16VGSgs0B0_p_tF")] - public static extern IntPtr GetErrorMessage(IntPtr handle); + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4from13messageLengthSPys6UInt16VGSgs0B0_p_s5Int32VztF")] + public static extern IntPtr GetErrorMessage(IntPtr handle, out int length); [Fact] public unsafe static void TestSwiftErrorThrown() @@ -60,8 +60,9 @@ private static void SetErrorMessageForSwift(string message) private unsafe static string GetErrorMessageFromSwift(SwiftError error) { - IntPtr pointer = GetErrorMessage(error.Value); - string errorMessage = Marshal.PtrToStringUni(pointer); + int messageLength; + IntPtr pointer = GetErrorMessage(error.Value, out messageLength); + string errorMessage = Marshal.PtrToStringUni(pointer, messageLength); NativeMemory.Free((void*)pointer); return errorMessage; } diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 78591f65a9b22e..2cdbae92783066 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -21,12 +21,13 @@ public func conditionallyThrowError(willThrow: Bool) throws -> Int { } } -public func getMyErrorMessage(from error: Error) -> UnsafePointer? { +public func getMyErrorMessage(from error: Error, messageLength: inout Int32) -> UnsafePointer? { if let myError = error as? MyError { switch myError { case .runtimeError(let message): let buffer = UnsafeMutableBufferPointer.allocate(capacity: message.length) message.getCharacters(buffer.baseAddress!, range: NSRange(location: 0, length: message.length)) + messageLength = Int32(message.length) return UnsafePointer(buffer.baseAddress!) } } From ed2a7dc1be14323af562a93ada53937c7a86ab5f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Dec 2023 14:43:52 +0100 Subject: [PATCH 100/137] Don't allocate amd64_rbx for Swift calling convention --- src/mono/mono/mini/mini-amd64.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index b7ab51f919437c..3eed8e32854029 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1669,8 +1669,8 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) regs = g_list_prepend (regs, (gpointer)AMD64_RBP); /* We use the callee saved registers for global allocation */ - regs = g_list_prepend (regs, (gpointer)AMD64_RBX); if (!mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + regs = g_list_prepend (regs, (gpointer)AMD64_RBX); regs = g_list_prepend (regs, (gpointer)AMD64_R12); regs = g_list_prepend (regs, (gpointer)AMD64_R13); } @@ -1824,6 +1824,13 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->arch.saved_iregs |= iregs_to_save; } + if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + cfg->arch.saved_iregs |= AMD64_R12; + cfg->used_int_regs |= (size_t)(1 << AMD64_R12); + cfg->arch.saved_iregs |= AMD64_R13; + cfg->used_int_regs |= (size_t)(1 << AMD64_R13); + } + if (cfg->arch.omit_fp) cfg->arch.reg_save_area_offset = offset; /* Reserve space for callee saved registers */ From 7961e29c0c647ba426587c82b1e1652734100353 Mon Sep 17 00:00:00 2001 From: Matous Kozak <55735845+matouskozak@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:01:35 +0100 Subject: [PATCH 101/137] Update src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs Co-authored-by: Jan Kotas --- .../Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 92ef38438ae6fe..70ed23fdda8279 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -60,8 +60,7 @@ private static void SetErrorMessageForSwift(string message) private unsafe static string GetErrorMessageFromSwift(SwiftError error) { - int messageLength; - IntPtr pointer = GetErrorMessage(error.Value, out messageLength); + IntPtr pointer = GetErrorMessage(error.Value, out int messageLength); string errorMessage = Marshal.PtrToStringUni(pointer, messageLength); NativeMemory.Free((void*)pointer); return errorMessage; From 5e1afb5ea985a9764aa09eaa56b9438c7cda4106 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 13 Dec 2023 18:20:10 +0100 Subject: [PATCH 102/137] Add missing case for ArgSwiftSelf The case handles the ArgSwiftSelf same as ArgValuetypeInReg. Otherwise, it fallbacks to the default case where the argument is stored onto the stack, overriding existing data. --- src/mono/mono/mini/mini-amd64.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 3eed8e32854029..faa91c1cb6442c 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1669,8 +1669,8 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) regs = g_list_prepend (regs, (gpointer)AMD64_RBP); /* We use the callee saved registers for global allocation */ + regs = g_list_prepend (regs, (gpointer)AMD64_RBX); if (!mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - regs = g_list_prepend (regs, (gpointer)AMD64_RBX); regs = g_list_prepend (regs, (gpointer)AMD64_R12); regs = g_list_prepend (regs, (gpointer)AMD64_R13); } @@ -1825,9 +1825,9 @@ mono_arch_allocate_vars (MonoCompile *cfg) } if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - cfg->arch.saved_iregs |= AMD64_R12; + cfg->arch.saved_iregs |= (size_t)(1 << AMD64_R12) ; cfg->used_int_regs |= (size_t)(1 << AMD64_R12); - cfg->arch.saved_iregs |= AMD64_R13; + cfg->arch.saved_iregs |= (size_t)(1 << AMD64_R13); cfg->used_int_regs |= (size_t)(1 << AMD64_R13); } @@ -1934,7 +1934,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) * are volatile across calls. * FIXME: Optimize this. */ - if ((ainfo->storage == ArgInIReg) || (ainfo->storage == ArgInFloatSSEReg) || (ainfo->storage == ArgInDoubleSSEReg) || (ainfo->storage == ArgValuetypeInReg) || (ainfo->storage == ArgGSharedVtInReg) || (ainfo->storage == ArgSwiftError)) + if ((ainfo->storage == ArgInIReg) || (ainfo->storage == ArgInFloatSSEReg) || (ainfo->storage == ArgInDoubleSSEReg) || (ainfo->storage == ArgValuetypeInReg) || (ainfo->storage == ArgGSharedVtInReg) || (ainfo->storage == ArgSwiftError) || (ainfo->storage == ArgSwiftSelf)) inreg = FALSE; ins->opcode = OP_REGOFFSET; @@ -2503,7 +2503,8 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) int size = ins->backend.size; switch (ainfo->storage) { - case ArgValuetypeInReg: { + case ArgValuetypeInReg: + case ArgSwiftSelf: { MonoInst *load; int part; From d9da03d95008b08b41cbe9a4219021c9a41cff17 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 15 Dec 2023 12:53:09 +0100 Subject: [PATCH 103/137] [mono] Fix invalid calling convention counter --- src/mono/mono/mini/interp/transform.c | 2 +- src/mono/mono/mini/method-to-ir.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index ad3fdbd2bc3617..f87b42ffb8689d 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3766,7 +3766,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target mono_error_set_invalid_program (error, "SwiftError argument must be a reference."); return FALSE; } else if (klass == swift_error_ptr) { - swift_self_args++; + swift_error_args++; } else if (klass == swift_self) { swift_self_args++; } diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 3f9a9408804939..946ca51032b830 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -11160,7 +11160,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("SwiftError argument must be a pointer."), mono_method_full_name (method, TRUE)); break; } else if (param_klass == swift_error_ptr) { - swift_self_args++; + swift_error_args++; } else if (param_klass == swift_self) { swift_self_args++; } From 672ac92c0283734cd91996f5bd1105d88c922d94 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 11 Jan 2024 14:25:34 +0100 Subject: [PATCH 104/137] [mono] Resolve conflicts in SwiftTypes.cs and CallConvSwift class --- .../System.Private.CoreLib.Shared.projitems | 1 - .../CompilerServices/CallingConventions.cs | 1 - .../InteropServices/Swift/SwiftType.cs | 47 ------------------- .../System.Runtime/ref/System.Runtime.cs | 4 -- src/mono/mono/mini/mini-arm64.c | 1 - .../SwiftErrorHandling/SwiftErrorHandling.cs | 10 ++-- .../SwiftSelfContext/SwiftSelfContext.cs | 8 ++-- 7 files changed, 9 insertions(+), 63 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 7f3713121caa59..3605169e9b9d50 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -974,7 +974,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs index 5dfd1617fd39ce..f80dbcecc14907 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs @@ -15,7 +15,6 @@ public class CallConvStdcall { public CallConvStdcall() { } } - /// /// Indicates that a method should using the Swiftcalling convention. /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs deleted file mode 100644 index cc0eb66d2508e1..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftType.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.InteropServices.Swift -{ - /// - /// Indicates that the argument is the self context. - /// - public readonly struct SwiftSelf - { - /// Creates a new instance of the SwiftSelf struct with the specified pointer value. - /// The pointer value of the self context - public SwiftSelf(IntPtr value) { - Value = value; - } - /// Gets the pointer of the self context. - public IntPtr Value { get; } - } - - /// - /// Indicates that the argument is the error context. - /// - public readonly struct SwiftError - { - /// Creates a new instance of the SwiftError struct with the specified pointer value. - /// The pointer value of the error context - public SwiftError(IntPtr value) { - Value = value; - } - /// Gets the pointer of the error context. - public IntPtr Value { get; } - } - - /// - /// Indicates that the argument is the async context. - /// - public readonly struct SwiftAsyncContext - { - /// Creates a new instance of the SwiftAsyncContext struct with the specified pointer value. - /// The pointer value of the async context - public SwiftAsyncContext(IntPtr value) { - Value = value; - } - /// Gets the pointer of the async context. - public IntPtr Value { get; } - } -} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 8634447ae471aa..d6442299edfcd5 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -12628,10 +12628,6 @@ public partial class CallConvThiscall { public CallConvThiscall() { } } - public partial class CallConvSwift - { - public CallConvSwift() { } - } [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple=false, Inherited=false)] public sealed partial class CallerArgumentExpressionAttribute : System.Attribute { diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 62d9bfbff7e0c4..5d887d48640185 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -3771,7 +3771,6 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) g_assert_not_reached (); break; } - return code; } diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 70ed23fdda8279..998468de48ab64 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -20,7 +20,7 @@ public class ErrorHandlingTests public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4from13messageLengthSPys6UInt16VGSgs0B0_p_s5Int32VztF")] - public static extern IntPtr GetErrorMessage(IntPtr handle, out int length); + public unsafe static extern void* GetErrorMessage(void* handle, out int length); [Fact] public unsafe static void TestSwiftErrorThrown() @@ -32,7 +32,7 @@ public unsafe static void TestSwiftErrorThrown() // This will throw an error conditionallyThrowError(true, &error); - Assert.True(error.Value != IntPtr.Zero, "A Swift error was expected to be thrown."); + Assert.True(error.Value != null, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: {0}, Actual: {1}", expectedErrorMessage, errorMessage)); @@ -49,7 +49,7 @@ public unsafe static void TestSwiftErrorNotThrown() // This will not throw an error int result = (int)conditionallyThrowError(false, &error); - Assert.True(error.Value == IntPtr.Zero, "No Swift error was expected to be thrown."); + Assert.True(error.Value == null, "No Swift error was expected to be thrown."); Assert.True(result == 42, "The result from Swift does not match the expected value."); } @@ -60,8 +60,8 @@ private static void SetErrorMessageForSwift(string message) private unsafe static string GetErrorMessageFromSwift(SwiftError error) { - IntPtr pointer = GetErrorMessage(error.Value, out int messageLength); - string errorMessage = Marshal.PtrToStringUni(pointer, messageLength); + void* pointer = GetErrorMessage(error.Value, out int messageLength); + string errorMessage = Marshal.PtrToStringUni((IntPtr)pointer, messageLength); NativeMemory.Free((void*)pointer); return errorMessage; } diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs index 96337eaf7d3d84..c37c7eea45f5c4 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs @@ -12,18 +12,18 @@ public class SelfContextTests private const string SwiftLib = "libSwiftSelfContext.dylib"; [DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC11getInstanceSvyFZ")] - public static extern IntPtr getInstance(); + public unsafe static extern void* getInstance(); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyF")] public static extern nint getMagicNumber(SwiftSelf self); [Fact] - public static void TestSwiftSelfContext() + public unsafe static void TestSwiftSelfContext() { - IntPtr pointer = getInstance(); + void* pointer = getInstance(); SwiftSelf self = new SwiftSelf(pointer); - Assert.True(self.Value != IntPtr.Zero, "Failed to obtain an instance of SwiftSelf from the Swift library."); + Assert.True(self.Value != null, "Failed to obtain an instance of SwiftSelf from the Swift library."); int result = (int)getMagicNumber(self); Assert.True(result == 42, "The result from Swift does not match the expected value."); From dfc5de6f316b21515bf071f8b96bf0a075cb552b Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 11 Jan 2024 19:11:27 +0100 Subject: [PATCH 105/137] [mono] Copy ext_callconv property --- src/mono/mono/metadata/loader.c | 1 + src/mono/mono/metadata/metadata.c | 2 ++ src/mono/mono/metadata/sre.c | 1 + src/mono/mono/mini/aot-compiler.c | 1 + 4 files changed, 5 insertions(+) diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index 5f21d3371c3c1f..67c613b9631ae0 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -634,6 +634,7 @@ inflate_generic_signature_checked (MonoImage *image, MonoMethodSignature *sig, M res->explicit_this = sig->explicit_this; res->call_convention = sig->call_convention; res->pinvoke = sig->pinvoke; + res->ext_callconv = sig->ext_callconv; res->generic_param_count = sig->generic_param_count; res->sentinelpos = sig->sentinelpos; res->has_type_parameters = is_open; diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 05b6166d8bf946..6cf899543da915 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -2654,6 +2654,8 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c if (*ptr & 0x40) explicit_this = 1; call_convention = *ptr & 0x0F; + // TODO: Decode ext_callconv + ptr++; if (gen_param_count) gen_param_count = mono_metadata_decode_value (ptr, &ptr); diff --git a/src/mono/mono/metadata/sre.c b/src/mono/mono/metadata/sre.c index 3f47f9e84d008e..47c086595af068 100644 --- a/src/mono/mono/metadata/sre.c +++ b/src/mono/mono/metadata/sre.c @@ -976,6 +976,7 @@ create_method_token (MonoDynamicImage *assembly, MonoMethod *method, MonoArrayHa sig->hasthis = old->hasthis; sig->explicit_this = old->explicit_this; sig->call_convention = old->call_convention; + sig->ext_callconv = old->ext_callconv; sig->generic_param_count = old->generic_param_count; sig->param_count = old->param_count + GINT_TO_UINT16 (nargs); sig->sentinelpos = old->param_count; diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 42c122d98371bc..b0dfab0851e797 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -3764,6 +3764,7 @@ encode_signature (MonoAotCompile *acfg, MonoMethodSignature *sig, guint8 *buf, g if (sig->pinvoke) flags |= 0x80; flags |= (sig->call_convention & 0x0F); + // TODO: Encode ext_callconv *p = flags; ++p; From 0984ffc4a3cfe56724d58fc641a23a64699acb0b Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 11 Jan 2024 19:22:50 +0100 Subject: [PATCH 106/137] Refactor mono_marshal_get_native_wrapper to add non-primitive arguments check Refactor the mono_marshal_get_native_wrapper function to remove redundant code and add check for non-primitive arguments in the CallConvSwift. The function first checks the cache for a wrapper, then emits an exception if an error is thrown, handles specific cases, and finally emits wrappers. These changes shouldn't affect the functionality. --- src/mono/mono/metadata/marshal.c | 246 ++++++++++-------- src/mono/mono/mini/interp/transform.c | 31 +-- src/mono/mono/mini/method-to-ir.c | 35 +-- .../SwiftInvalidCallConv.cs | 26 +- 4 files changed, 159 insertions(+), 179 deletions(-) diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 88cf8afd71dc93..2e57ad8500f284 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -127,6 +127,10 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "Sys static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callconv_attribute, "System.Runtime.InteropServices", "UnmanagedCallConvAttribute") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + static gboolean type_is_blittable (MonoType *type); static IlgenCallbacksToMono ilgenCallbacksToMono = { @@ -3360,6 +3364,8 @@ mono_marshal_set_signature_callconv_from_attribute(MonoMethodSignature *sig, Mon sig->call_convention = MONO_CALL_THISCALL; else if (!strcmp (name, "Fastcall")) sig->call_convention = MONO_CALL_FASTCALL; + else if (!strcmp (name, "Swift")) + sig->ext_callconv |= MONO_EXT_CALLCONV_SWIFTCALL; else if (!strcmp (name, "SuppressGCTransition")) sig->ext_callconv |= MONO_EXT_CALLCONV_SUPPRESS_GC_TRANSITION; // TODO: Support CallConvMemberFunction? @@ -3429,23 +3435,31 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, MonoMethodSignature *sig, *csig; MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; MonoMethodBuilder *mb; - MonoMarshalSpec **mspecs; + MonoMarshalSpec **mspecs = NULL; MonoMethod *res; GHashTable *cache; gboolean pinvoke = FALSE; gboolean skip_gc_trans = FALSE; - gboolean pinvoke_not_found = FALSE; gpointer iter; - ERROR_DECL (emitted_error); WrapperInfo *info; + MonoType *string_type; + GHashTable **cache_ptr; + ERROR_DECL (emitted_error); g_assert (method != NULL); g_assertf (mono_method_signature_internal (method)->pinvoke, "%s flags:%X iflags:%X param_count:%X", method->name, method->flags, method->iflags, mono_method_signature_internal (method)->param_count); - GHashTable **cache_ptr; - - MonoType *string_type = m_class_get_byval_arg (mono_defaults.string_class); + if (MONO_CLASS_IS_IMPORT (method->klass)) { + /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */ + if (aot) + return method; +#ifndef DISABLE_COM + return mono_cominterop_get_native_wrapper (method); +#else + g_assert_not_reached (); +#endif + } if (aot) { if (check_exceptions) @@ -3472,17 +3486,6 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, } } - if (MONO_CLASS_IS_IMPORT (method->klass)) { - /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */ - if (aot) - return method; -#ifndef DISABLE_COM - return mono_cominterop_get_native_wrapper (method); -#else - g_assert_not_reached (); -#endif - } - sig = mono_method_signature_internal (method); if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && @@ -3495,12 +3498,30 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, mono_error_set_generic_error (emitted_error, "System", "MissingMethodException", "Method contains unsupported native code"); else if (!aot) mono_lookup_pinvoke_call_internal (method, emitted_error); - } else { - if (!aot || (method->klass == mono_defaults.string_class)) - piinfo->addr = mono_lookup_internal_call (method); + } else if (!aot || (method->klass == mono_defaults.string_class)) { + piinfo->addr = mono_lookup_internal_call (method); } } + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE); + mb->method->save_lmf = 1; + + if (G_UNLIKELY (pinvoke && mono_method_has_unmanaged_callers_only_attribute (method))) { + /* + * In AOT mode and embedding scenarios, it is possible that the icall is not registered in the runtime doing the AOT compilation. + * Emit a wrapper that throws a NotSupportedException. + */ + get_marshal_cb ()->mb_emit_exception (mb, "System", "NotSupportedException", "Method canot be marked with both DllImportAttribute and UnmanagedCallersOnlyAttribute"); + goto emit_exception_for_error; + } else if (!pinvoke && !piinfo->addr && !aot) { + /* if there's no code but the error isn't set, just use a fairly generic exception. */ + if (is_ok (emitted_error)) + mono_error_set_generic_error (emitted_error, "System", "MissingMethodException", ""); + get_marshal_cb ()->mb_emit_exception_for_error (mb, emitted_error); + goto emit_exception_for_error; + } + + string_type = m_class_get_byval_arg (mono_defaults.string_class); /* hack - redirect certain string constructors to CreateString */ if (piinfo->addr == ves_icall_System_String_ctor_RedirectToCreateString) { MonoMethod *m; @@ -3557,51 +3578,6 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, return res; } - mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE); - - mb->method->save_lmf = 1; - - if (G_UNLIKELY (pinvoke && mono_method_has_unmanaged_callers_only_attribute (method))) { - /* emit a wrapper that throws a NotSupportedException */ - get_marshal_cb ()->mb_emit_exception (mb, "System", "NotSupportedException", "Method canot be marked with both DllImportAttribute and UnmanagedCallersOnlyAttribute"); - - info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE); - info->d.managed_to_native.method = method; - - csig = mono_metadata_signature_dup_full (get_method_image (method), sig); - csig->pinvoke = 0; - res = mono_mb_create_and_cache_full (cache, method, mb, csig, - csig->param_count + 16, info, NULL); - mono_mb_free (mb); - - return res; - } - - /* - * In AOT mode and embedding scenarios, it is possible that the icall is not - * registered in the runtime doing the AOT compilation. - */ - /* Handled at runtime */ - pinvoke_not_found = !pinvoke && !piinfo->addr && !aot; - if (pinvoke_not_found) { - /* if there's no code but the error isn't set, just use a fairly generic exception. */ - if (is_ok (emitted_error)) - mono_error_set_generic_error (emitted_error, "System", "MissingMethodException", ""); - get_marshal_cb ()->mb_emit_exception_for_error (mb, emitted_error); - mono_error_cleanup (emitted_error); - - info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE); - info->d.managed_to_native.method = method; - - csig = mono_metadata_signature_dup_full (get_method_image (method), sig); - csig->pinvoke = 0; - res = mono_mb_create_and_cache_full (cache, method, mb, csig, - csig->param_count + 16, info, NULL); - mono_mb_free (mb); - - return res; - } - /* internal calls: we simply push all arguments and call the method (no conversions) */ if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) { if (sig->hasthis) @@ -3609,81 +3585,123 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, else csig = mono_metadata_signature_dup_full (get_method_image (method), sig); - //printf ("%s\n", mono_method_full_name (method, 1)); - /* hack - string constructors returns a value */ if (method->string_ctor) csig->ret = string_type; get_marshal_cb ()->emit_native_icall_wrapper (mb, method, csig, check_exceptions, aot, piinfo); + } else { + g_assert(pinvoke); - info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE); - info->d.managed_to_native.method = method; + csig = mono_metadata_signature_dup_full (get_method_image (method), sig); + mono_marshal_set_callconv_from_modopt (method, csig, FALSE); - csig = mono_metadata_signature_dup_full (get_method_image (method), csig); - csig->pinvoke = 0; - res = mono_mb_create_and_cache_full (cache, method, mb, csig, csig->param_count + 16, - info, NULL); + mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1); + mono_method_get_marshal_info (method, mspecs); - mono_mb_free (mb); - return res; - } + if (mono_class_try_get_suppress_gc_transition_attribute_class ()) { + MonoCustomAttrInfo *cinfo; + ERROR_DECL (error); - g_assert (pinvoke); + cinfo = mono_custom_attrs_from_method_checked (method, error); + mono_error_assert_ok (error); + gboolean found = FALSE; + if (cinfo) { + for (int i = 0; i < cinfo->num_attrs; ++i) { + MonoClass *ctor_class = cinfo->attrs [i].ctor->klass; + if (ctor_class == mono_class_try_get_suppress_gc_transition_attribute_class ()) { + found = TRUE; + break; + } + } + } + if (found) + skip_gc_trans = TRUE; + if (cinfo && !cinfo->cached) + mono_custom_attrs_free (cinfo); + } - csig = mono_metadata_signature_dup_full (get_method_image (method), sig); - mono_marshal_set_callconv_from_modopt (method, csig, FALSE); + if (csig->call_convention == MONO_CALL_DEFAULT) { + /* If the calling convention has not been set, check the UnmanagedCallConv attribute */ + mono_marshal_set_callconv_from_unmanaged_callconv_attribute (method, csig, &skip_gc_trans); + } - mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1); - mono_method_get_marshal_info (method, mspecs); + if (mono_method_signature_has_ext_callconv (csig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + int swift_error_args = 0, swift_self_args = 0; + for (int i = 0; i < method->signature->param_count; ++i) { + MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); + if (param_klass) { + if (param_klass == swift_error) { + swift_error_args = swift_self_args = 0; + mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftError argument must be a pointer."); + break; + } else if (param_klass == swift_error_ptr) { + swift_error_args++; + } else if (param_klass == swift_self) { + swift_self_args++; + } else if (!m_class_is_enumtype (param_klass) && !m_class_is_primitive (param_klass)) { + swift_error_args = swift_self_args = 0; + mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Passing non-primitive value types to a P/Invoke with the Swift calling convention is unsupported."); + break; + } + } + } - if (mono_class_try_get_suppress_gc_transition_attribute_class ()) { - MonoCustomAttrInfo *cinfo; - ERROR_DECL (error); + if (swift_self_args > 1 || swift_error_args > 1) { + mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Method signature contains multiple SwiftSelf/SwiftError arguments."); + } - cinfo = mono_custom_attrs_from_method_checked (method, error); - mono_error_assert_ok (error); - gboolean found = FALSE; - if (cinfo) { - for (int i = 0; i < cinfo->num_attrs; ++i) { - MonoClass *ctor_class = cinfo->attrs [i].ctor->klass; - if (ctor_class == mono_class_try_get_suppress_gc_transition_attribute_class ()) { - found = TRUE; - break; - } + if (!is_ok (emitted_error)) { + get_marshal_cb ()->mb_emit_exception_for_error (mb, emitted_error); + goto emit_exception_for_error; } } - if (found) - skip_gc_trans = TRUE; - if (cinfo && !cinfo->cached) - mono_custom_attrs_free (cinfo); - } - if (csig->call_convention == MONO_CALL_DEFAULT) { - /* If the calling convention has not been set, check the UnmanagedCallConv attribute */ - mono_marshal_set_callconv_from_unmanaged_callconv_attribute (method, csig, &skip_gc_trans); + MonoNativeWrapperFlags flags = aot ? EMIT_NATIVE_WRAPPER_AOT : (MonoNativeWrapperFlags)0; + flags |= check_exceptions ? EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS : (MonoNativeWrapperFlags)0; + flags |= skip_gc_trans ? EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS : (MonoNativeWrapperFlags)0; + flags |= runtime_marshalling_enabled (get_method_image (method)) ? EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED : (MonoNativeWrapperFlags)0; + + mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, flags); } - MonoNativeWrapperFlags flags = aot ? EMIT_NATIVE_WRAPPER_AOT : (MonoNativeWrapperFlags)0; - flags |= check_exceptions ? EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS : (MonoNativeWrapperFlags)0; - flags |= skip_gc_trans ? EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS : (MonoNativeWrapperFlags)0; - flags |= runtime_marshalling_enabled (get_method_image (method)) ? EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED : (MonoNativeWrapperFlags)0; + info = mono_wrapper_info_create (mb, method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) + ? WRAPPER_SUBTYPE_NONE + : WRAPPER_SUBTYPE_PINVOKE); - mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, flags); - info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PINVOKE); info->d.managed_to_native.method = method; + if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) + csig = mono_metadata_signature_dup_full (get_method_image (method), sig); csig->pinvoke = 0; res = mono_mb_create_and_cache_full (cache, method, mb, csig, csig->param_count + 16, info, NULL); - mono_mb_free (mb); - for (int i = sig->param_count; i >= 0; i--) - if (mspecs [i]) - mono_metadata_free_marshal_spec (mspecs [i]); - g_free (mspecs); + if (mspecs) { + for (int i = sig->param_count; i >= 0; i--) + if (mspecs [i]) + mono_metadata_free_marshal_spec (mspecs [i]); + g_free (mspecs); + } - return res; + goto leave; + + emit_exception_for_error: + mono_error_cleanup (emitted_error); + info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE); + info->d.managed_to_native.method = method; + + csig = mono_metadata_signature_dup_full (get_method_image (method), sig); + csig->pinvoke = 0; + res = mono_mb_create_and_cache_full (cache, method, mb, csig, + csig->param_count + 16, info, NULL); + + leave: + mono_mb_free (mb); + return res; } /** diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 71473379d40a96..5180fa599b24a8 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -61,9 +61,6 @@ static int stack_type [] = { static GENERATE_TRY_GET_CLASS_WITH_CACHE (intrinsic_klass, "System.Runtime.CompilerServices", "IntrinsicAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (doesnotreturn_klass, "System.Diagnostics.CodeAnalysis", "DoesNotReturnAttribute") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error); @@ -3753,31 +3750,9 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int *call_args = create_call_args (td, num_args); if (mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SWIFTCALL)) { -#ifdef MONO_ARCH_HAVE_SWIFTCALL - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - int swift_error_args = 0, swift_self_args = 0; - for (int i = 0; i < csignature->param_count; ++i) { - MonoClass *klass = mono_class_from_mono_type_internal (csignature->params [i]); - if (klass) { - if (klass == swift_error) { - swift_error_args = swift_self_args = 0; - mono_error_set_invalid_program (error, "SwiftError argument must be a reference."); - return FALSE; - } else if (klass == swift_error_ptr) { - swift_error_args++; - } else if (klass == swift_self) { - swift_self_args++; - } - } - } - if (swift_self_args > 1 || swift_error_args > 1) { - mono_error_set_invalid_program (error, "Method signature contains multiple SwiftSelf/SwiftError arguments."); - return FALSE; - } -#else - mono_error_set_not_implemented (error, "CallConvSwift is not supported on this platform."); +#ifndef MONO_ARCH_HAVE_SWIFTCALL + // Swift calling convention is not supported on this platform. + mono_error_set_not_supported (error, "CallConvSwift is not supported on this platform."); return FALSE; #endif } diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 1fe126f9d534b0..b71705c17a35a2 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -226,10 +226,6 @@ const gint8 mini_ins_sreg_counts[] = { #undef MINI_OP #undef MINI_OP3 -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - guint32 mono_alloc_ireg (MonoCompile *cfg) { @@ -11176,35 +11172,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoJitICallInfo * const jit_icall_info = mono_find_jit_icall_info (jit_icall_id); if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { -#ifdef MONO_ARCH_HAVE_SWIFTCALL - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - int swift_error_args = 0, swift_self_args = 0; - ERROR_DECL (swiftcall_error); - for (int i = 0; i < method->signature->param_count; ++i) { - MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); - if (param_klass) { - if (param_klass == swift_error) { - swift_error_args = swift_self_args = 0; - mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("SwiftError argument must be a pointer."), mono_method_full_name (method, TRUE)); - break; - } else if (param_klass == swift_error_ptr) { - swift_error_args++; - } else if (param_klass == swift_self) { - swift_self_args++; - } - } - } - if (swift_self_args > 1 || swift_error_args > 1) { - mono_error_set_invalid_program (swiftcall_error, g_strdup_printf ("Method signature contains multiple SwiftSelf/SwiftError arguments."), mono_method_full_name (method, TRUE)); - } - - if (!is_ok (swiftcall_error)) { - emit_invalid_program_with_msg (cfg, swiftcall_error, method, cmethod); - mono_error_cleanup (swiftcall_error); - } -#else +#ifndef MONO_ARCH_HAVE_SWIFTCALL + // Swift calling convention is not supported on this platform. emit_not_supported_failure (cfg); #endif } diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs index b23213764ca710..db725f83d263ca 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -9,23 +9,32 @@ public class InvalidCallingConvTests { + // Dummy class with a dummy attribute + public class StringClass + { + public string value { get; set; } + } private const string SwiftLib = "libSwiftInvalidCallConv.dylib"; [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public static extern nint FuncWithTwoSelfParameters(SwiftSelf self1, SwiftSelf self2); + public static extern void FuncWithTwoSelfParameters(SwiftSelf self1, SwiftSelf self2); + + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] + public unsafe static extern void FuncWithTwoErrorParameters(SwiftError* error1, SwiftError* error2); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public unsafe static extern nint FuncWithTwoErrorParameters(SwiftError* error1, SwiftError* error2); + public unsafe static extern void FuncWithMixedParameters(SwiftSelf self1, SwiftSelf self2, SwiftError* error1, SwiftError* error2); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public unsafe static extern nint FuncWithMixedParameters(SwiftSelf self1, SwiftSelf self2, SwiftError* error1, SwiftError* error2); + public static extern void FuncWithSwiftErrorAsArg(SwiftError error1); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public static extern nint FuncWithSwiftErrorAsArg(SwiftError error1); + public static extern void FuncWithNonPrimitiveArg(StringClass arg1); [Fact] public static void TestFuncWithTwoSelfParameters() @@ -61,4 +70,13 @@ public unsafe static void TestFuncWithSwiftErrorAsArg() SwiftError error = new SwiftError(); Assert.Throws(() => FuncWithSwiftErrorAsArg(error)); } + + [Fact] + public unsafe static void TestFuncWithNonPrimitiveArg() + { + // Invalid due to a non-primitive argument. + StringClass arg1 = new StringClass(); + arg1.value = "fail"; + Assert.Throws(() => FuncWithNonPrimitiveArg(arg1)); + } } From eaf9aa20a01d8914de65868f38580f49574b77f4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 15 Jan 2024 12:15:30 +0100 Subject: [PATCH 107/137] [mono] Implement sig->ext_callconv encoding and decoding --- src/mono/mono/metadata/metadata.c | 1 - src/mono/mono/mini/aot-compiler.c | 6 ++++-- src/mono/mono/mini/aot-runtime.c | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 6cf899543da915..17e0abfac27b18 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -2654,7 +2654,6 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c if (*ptr & 0x40) explicit_this = 1; call_convention = *ptr & 0x0F; - // TODO: Decode ext_callconv ptr++; if (gen_param_count) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index b0dfab0851e797..9a01499e343438 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -3764,9 +3764,11 @@ encode_signature (MonoAotCompile *acfg, MonoMethodSignature *sig, guint8 *buf, g if (sig->pinvoke) flags |= 0x80; flags |= (sig->call_convention & 0x0F); - // TODO: Encode ext_callconv - *p = flags; + + ++p; + *p = sig->ext_callconv & 0x0F; + ++p; if (sig->generic_param_count) encode_value (sig->generic_param_count, p, &p); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 96b8cb58dad488..d4c490c3ff6e06 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -857,6 +857,8 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target guint16 param_count; unsigned int gen_param_count = 0; int call_conv; + uint8_t ext_callconv; + guint8 *p = buf; gboolean hasthis, explicit_this, has_gen_params, pinvoke; @@ -868,6 +870,9 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target pinvoke = (flags & 0x80) != 0; call_conv = flags & 0x0F; + ext_callconv = *p; + p ++; + if (has_gen_params) gen_param_count = decode_value (p, &p); param_count = GINT32_TO_UINT16 (decode_value (p, &p)); @@ -880,6 +885,7 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target sig->explicit_this = explicit_this; sig->pinvoke = pinvoke; sig->call_convention = call_conv; + sig->ext_callconv = ext_callconv; sig->generic_param_count = gen_param_count; sig->ret = decode_type (module, p, &p, error); if (!sig->ret) From fe19a0954f04aa2d3b8a0e2051982c69a2ef352e Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 15 Jan 2024 12:24:05 +0100 Subject: [PATCH 108/137] [mini] Use MONO_ARCH_HAVE_SWIFTCALL to condition ctx regs on supported platforms. --- src/mono/mono/mini/interp/transform.c | 5 ++--- src/mono/mono/mini/method-to-ir.c | 4 ++-- src/mono/mono/mini/mini-amd64.h | 2 +- src/mono/mono/mini/mini-arm64.h | 2 +- src/mono/mono/mini/tramp-amd64.c | 6 ++++++ src/mono/mono/mini/tramp-arm64.c | 6 ++++++ 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 5180fa599b24a8..d0cab3c4e004df 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3749,13 +3749,12 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int *call_args = create_call_args (td, num_args); - if (mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SWIFTCALL)) { #ifndef MONO_ARCH_HAVE_SWIFTCALL - // Swift calling convention is not supported on this platform. + if (mono_method_signature_has_ext_callconv (csignature, MONO_EXT_CALLCONV_SWIFTCALL)) { mono_error_set_not_supported (error, "CallConvSwift is not supported on this platform."); return FALSE; -#endif } +#endif // We overwrite it with the return local, save it for future use if (csignature->param_count || csignature->hasthis) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index b71705c17a35a2..0e5326ec8f281d 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -11171,12 +11171,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b const MonoJitICallId jit_icall_id = (MonoJitICallId)token; MonoJitICallInfo * const jit_icall_info = mono_find_jit_icall_info (jit_icall_id); - if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { #ifndef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { // Swift calling convention is not supported on this platform. emit_not_supported_failure (cfg); -#endif } +#endif CHECK_STACK (jit_icall_info->sig->param_count); sp -= jit_icall_info->sig->param_count; diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index bd19b8c288090f..d8e1764e76f8eb 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -492,7 +492,7 @@ typedef struct { // can pass context to generics or interfaces? #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 -#if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) #define MONO_ARCH_HAVE_SWIFTCALL 1 #endif diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index 2a730c800e3679..eaa5ed731a3b4a 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -206,7 +206,7 @@ typedef struct { #define MONO_ARCH_EXPLICIT_NULL_CHECKS 1 #endif -#if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) #define MONO_ARCH_HAVE_SWIFTCALL 1 #endif diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 322372d8ed5f92..38c5733782ccb1 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1056,8 +1056,10 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) mono_add_unwind_op_fp_alloc (unwind_ops, code, start, AMD64_RBP, 0); /* allocate space for saving the target addr, call context, and context registers */ +#ifdef MONO_ARCH_HAVE_SWIFTCALL off_ctxregs = -framesize; framesize += CTX_REGS * sizeof (host_mgreg_t); +#endif off_methodargs = -framesize; framesize += sizeof (host_mgreg_t); @@ -1104,11 +1106,13 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_PARAM_REGS; ++i) amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); +#ifdef MONO_ARCH_HAVE_SWIFTCALL /* store the values of context registers onto the stack and set the context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) { amd64_mov_membase_reg (code, AMD64_RBP, off_ctxregs - i * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); } +#endif /* load target addr */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (target_mgreg_t)); @@ -1125,11 +1129,13 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FLOAT_RETURN_REGS; i++) amd64_sse_movsd_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double), i); +#ifdef MONO_ARCH_HAVE_SWIFTCALL /* set context registers to CallContext and load context registers from the stack */ for (i = 0; i < CTX_REGS; i++) { amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + CTX_REGS_OFFSET) * sizeof (target_mgreg_t), i + CTX_REGS_OFFSET, sizeof (target_mgreg_t)); amd64_mov_reg_membase (code, i + CTX_REGS_OFFSET, AMD64_RBP, off_ctxregs - i * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); } +#endif #if TARGET_WIN32 amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0); diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index 9c52f33f054ec2..ecd9955fd435e3 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -668,8 +668,10 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* allocate frame */ framesize += 2 * sizeof (host_mgreg_t); +#ifdef MONO_ARCH_HAVE_SWIFTCALL off_ctxregs = framesize; framesize += CTX_REGS * sizeof (host_mgreg_t); +#endif off_methodargs = framesize; framesize += sizeof (host_mgreg_t); @@ -725,11 +727,13 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); +#ifdef MONO_ARCH_HAVE_SWIFTCALL /* store the values of context registers onto the stack and set the context registers from CallContext */ for (i = 0; i < CTX_REGS; i++) { arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_FP, off_ctxregs + i * sizeof (host_mgreg_t)); arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); } +#endif /* load target addr */ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_targetaddr); @@ -748,11 +752,13 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) for (i = 0; i < FP_PARAM_REGS; i++) arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); +#ifdef MONO_ARCH_HAVE_SWIFTCALL /* set context registers to CallContext and load context registers from the stack */ for (i = 0; i < CTX_REGS; i++) { arm_strx (code, i + CTX_REGS_OFFSET, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + (i + PARAM_REGS + 1) * sizeof (host_mgreg_t)); arm_ldrx (code, i + CTX_REGS_OFFSET, ARMREG_FP, off_ctxregs + i * sizeof (host_mgreg_t)); } +#endif arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); From f93e23164969207381bc800457695cbd77d3a1f9 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 15 Jan 2024 12:42:44 +0100 Subject: [PATCH 109/137] [mono] Resolve tramp warnings --- src/mono/mono/mini/tramp-amd64.c | 4 ++-- src/mono/mono/mini/tramp-arm64.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 38c5733782ccb1..6d90837169956c 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -1035,7 +1035,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) guint8 *label_start_copy, *label_exit_copy; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; - int buf_len, i, cfa_offset, framesize = 8, off_ctxregs, off_methodargs, off_targetaddr; + int buf_len, i, cfa_offset, framesize = 8, off_methodargs, off_targetaddr; buf_len = 512; start = code = (guint8 *) mono_global_codeman_reserve (buf_len + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE); @@ -1057,7 +1057,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) /* allocate space for saving the target addr, call context, and context registers */ #ifdef MONO_ARCH_HAVE_SWIFTCALL - off_ctxregs = -framesize; + int off_ctxregs = -framesize; framesize += CTX_REGS * sizeof (host_mgreg_t); #endif diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index ecd9955fd435e3..05567d2a0e4e1d 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -660,7 +660,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) guint8 *label_start_copy, *label_exit_copy; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; - int buf_len, i, framesize = 0, off_ctxregs, off_methodargs, off_targetaddr; + int buf_len, i, framesize = 0, off_methodargs, off_targetaddr; buf_len = 512 + 1024; start = code = (guint8 *) mono_global_codeman_reserve (buf_len); @@ -669,7 +669,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) framesize += 2 * sizeof (host_mgreg_t); #ifdef MONO_ARCH_HAVE_SWIFTCALL - off_ctxregs = framesize; + int off_ctxregs = framesize; framesize += CTX_REGS * sizeof (host_mgreg_t); #endif From 2d5b9f5d4e7464167ed7db1fdfdcb592ba21c90c Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 15 Jan 2024 14:11:26 +0100 Subject: [PATCH 110/137] [mini] Remove unused func --- src/mono/mono/mini/mini-amd64.c | 1 - src/mono/mono/mini/mini-arm64.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 7e8f8a9abfa152..7ab47f2cd96818 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -53,7 +53,6 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 5d887d48640185..22a79504ce9850 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -125,7 +125,6 @@ static WARN_UNUSED_RESULT guint8* emit_load_regset (guint8 *code, guint64 regs, static guint8* emit_brx (guint8 *code, int reg); static guint8* emit_blrx (guint8 *code, int reg); -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") From 60749f41122c8acea1e79997bd4a003d0d00a94c Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 15 Jan 2024 19:16:49 +0100 Subject: [PATCH 111/137] [mono] Add ext_callconv flag for encoding and decoding --- src/mono/mono/mini/aot-compiler.c | 15 ++++++++------- src/mono/mono/mini/aot-runtime.c | 11 +++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 9a01499e343438..424b966a5d0041 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -3751,7 +3751,7 @@ static void encode_signature (MonoAotCompile *acfg, MonoMethodSignature *sig, guint8 *buf, guint8 **endbuf) { guint8 *p = buf; - guint8 flags = 0; + guint32 flags = 0; int i; /* Similar to the metadata encoding */ @@ -3759,17 +3759,18 @@ encode_signature (MonoAotCompile *acfg, MonoMethodSignature *sig, guint8 *buf, g flags |= 0x10; if (sig->hasthis) flags |= 0x20; - if (sig->explicit_this) - flags |= 0x40; if (sig->pinvoke) + flags |= 0x40; + if (sig->explicit_this) flags |= 0x80; + if (sig->ext_callconv) + flags |= 0x100; flags |= (sig->call_convention & 0x0F); - *p = flags; - ++p; - *p = sig->ext_callconv & 0x0F; + encode_value (flags, p, &p); + if (sig->ext_callconv) + encode_value (sig->ext_callconv, p, &p); - ++p; if (sig->generic_param_count) encode_value (sig->generic_param_count, p, &p); encode_value (sig->param_count, p, &p); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index d4c490c3ff6e06..3f7c09b49a083c 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -862,16 +862,15 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target guint8 *p = buf; gboolean hasthis, explicit_this, has_gen_params, pinvoke; - flags = *p; - p ++; + flags = decode_value (p, &p); has_gen_params = (flags & 0x10) != 0; hasthis = (flags & 0x20) != 0; - explicit_this = (flags & 0x40) != 0; - pinvoke = (flags & 0x80) != 0; + pinvoke = (flags & 0x40) != 0; + explicit_this = (flags & 0x80) != 0; call_conv = flags & 0x0F; - ext_callconv = *p; - p ++; + if ((flags & 0x100) != 0) + ext_callconv = GINT32_TO_UINT8 (decode_value (p, &p)); if (has_gen_params) gen_param_count = decode_value (p, &p); From fa085d965061f91fc600fd3425fff7dcc7528d9c Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 16 Jan 2024 06:51:22 +0100 Subject: [PATCH 112/137] move swift defines and macros to mini.h --- src/mono/mono/mini/mini-amd64.c | 3 --- src/mono/mono/mini/mini-amd64.h | 4 ---- src/mono/mono/mini/mini-arm64.c | 3 --- src/mono/mono/mini/mini-arm64.h | 4 ---- src/mono/mono/mini/mini.h | 8 ++++++++ 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 7ab47f2cd96818..d2e8be5fc3a6bd 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -53,9 +53,6 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - #define IS_IMM32(val) ((((guint64)val) >> 32) == 0) diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index d8e1764e76f8eb..eca965b936ce81 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -492,10 +492,6 @@ typedef struct { // can pass context to generics or interfaces? #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 -#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) -#define MONO_ARCH_HAVE_SWIFTCALL 1 -#endif - void mono_amd64_patch (unsigned char* code, gpointer target); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 22a79504ce9850..b052d9294ab437 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -125,9 +125,6 @@ static WARN_UNUSED_RESULT guint8* emit_load_regset (guint8 *code, guint64 regs, static guint8* emit_brx (guint8 *code, int reg); static guint8* emit_blrx (guint8 *code, int reg); -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - const char* mono_arch_regname (int reg) { diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index eaa5ed731a3b4a..b4cf593fd3f2da 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -206,10 +206,6 @@ typedef struct { #define MONO_ARCH_EXPLICIT_NULL_CHECKS 1 #endif -#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) -#define MONO_ARCH_HAVE_SWIFTCALL 1 -#endif - /* Relocations */ #define MONO_R_ARM64_B 1 #define MONO_R_ARM64_BCC 2 diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 622717a6ef5658..e0f28ef632ca89 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -133,6 +133,9 @@ typedef struct SeqPointInfo SeqPointInfo; //XXX this ignores if t is byref #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U))))) +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#define MONO_ARCH_HAVE_SWIFTCALL 1 +#endif typedef struct { MonoClass *klass; @@ -3025,4 +3028,9 @@ MonoMemoryManager* mini_get_default_mem_manager (void); MONO_COMPONENT_API int mono_wasm_get_debug_level (void); +#ifdef MONO_ARCH_HAVE_SWIFTCALL +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") +#endif + #endif /* __MONO_MINI_H__ */ From 5309a58c26978aa748219ff73258fd045da8f595 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 16 Jan 2024 07:02:37 +0100 Subject: [PATCH 113/137] Revert "move swift defines and macros to mini.h" This reverts commit fa085d965061f91fc600fd3425fff7dcc7528d9c. --- src/mono/mono/mini/mini-amd64.c | 3 +++ src/mono/mono/mini/mini-amd64.h | 4 ++++ src/mono/mono/mini/mini-arm64.c | 3 +++ src/mono/mono/mini/mini-arm64.h | 4 ++++ src/mono/mono/mini/mini.h | 8 -------- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index d2e8be5fc3a6bd..7ab47f2cd96818 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -53,6 +53,9 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + #define IS_IMM32(val) ((((guint64)val) >> 32) == 0) diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 5e59669d12ce6e..57de5b6ea3d75a 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -493,6 +493,10 @@ typedef struct { // can pass context to generics or interfaces? #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#define MONO_ARCH_HAVE_SWIFTCALL 1 +#endif + void mono_amd64_patch (unsigned char* code, gpointer target); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index b052d9294ab437..22a79504ce9850 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -125,6 +125,9 @@ static WARN_UNUSED_RESULT guint8* emit_load_regset (guint8 *code, guint64 regs, static guint8* emit_brx (guint8 *code, int reg); static guint8* emit_blrx (guint8 *code, int reg); +static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + const char* mono_arch_regname (int reg) { diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index 0dbdc9ef9204df..d61936e9535068 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -207,6 +207,10 @@ typedef struct { #define MONO_ARCH_EXPLICIT_NULL_CHECKS 1 #endif +#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) +#define MONO_ARCH_HAVE_SWIFTCALL 1 +#endif + /* Relocations */ #define MONO_R_ARM64_B 1 #define MONO_R_ARM64_BCC 2 diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 06d7260a249637..77ef60a4405413 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -133,9 +133,6 @@ typedef struct SeqPointInfo SeqPointInfo; //XXX this ignores if t is byref #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U))))) -#if defined(TARGET_OSX) || defined(TARGET_APPLE_MOBILE) -#define MONO_ARCH_HAVE_SWIFTCALL 1 -#endif typedef struct { MonoClass *klass; @@ -3029,9 +3026,4 @@ MonoMemoryManager* mini_get_default_mem_manager (void); MONO_COMPONENT_API int mono_wasm_get_debug_level (void); -#ifdef MONO_ARCH_HAVE_SWIFTCALL -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") -#endif - #endif /* __MONO_MINI_H__ */ From 735b84e481144496b170639236c6f72ea03b68cd Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 16 Jan 2024 08:46:01 +0100 Subject: [PATCH 114/137] initialize ext_callconv --- src/mono/mono/mini/aot-runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 3f7c09b49a083c..e88b6965bb6bdb 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -857,7 +857,7 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target guint16 param_count; unsigned int gen_param_count = 0; int call_conv; - uint8_t ext_callconv; + uint8_t ext_callconv = 0; guint8 *p = buf; gboolean hasthis, explicit_this, has_gen_params, pinvoke; From f444eae4f999e0050bebc2e47cabc84b1332c326 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 16 Jan 2024 09:43:15 +0000 Subject: [PATCH 115/137] ifdef mono_arch_get_swift_error --- src/mono/mono/mini/mini-amd64.c | 2 ++ src/mono/mono/mini/mini-arm64.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 7ab47f2cd96818..2a3244c0ee541c 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1383,6 +1383,7 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +#ifdef MONO_ARCH_HAVE_SWIFTCALL /** * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. * @@ -1405,6 +1406,7 @@ mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpoi return NULL; } +#endif /* * mono_arch_get_argument_info: diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 22a79504ce9850..f235c326e3723e 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2132,6 +2132,7 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo } } +#ifdef MONO_ARCH_HAVE_SWIFTCALL /** * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. * @@ -2154,6 +2155,7 @@ mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpoi return NULL; } +#endif typedef struct { MonoMethodSignature *sig; From fe6e270a12a73e8c0a2586918e197f9ce84c0e47 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Tue, 16 Jan 2024 18:43:44 +0100 Subject: [PATCH 116/137] refactor swift error and self class getters --- src/mono/mono/metadata/class-internals.h | 3 +++ src/mono/mono/metadata/marshal.c | 8 ++++---- src/mono/mono/metadata/marshal.h | 5 +++++ src/mono/mono/mini/mini-amd64.c | 5 ++--- src/mono/mono/mini/mini-arm64.c | 5 ++--- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 49b2b746c9fdb5..3ef0b56ee5a212 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -927,6 +927,9 @@ MonoClass* mono_class_get_##shortname##_class (void); #define GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL(shortname) \ MonoClass* mono_class_try_get_##shortname##_class (void); +#define GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE_DECL(shortname) \ +MonoClass* mono_class_try_get_##shortname##_ptr_class (void); + static inline MonoImage * mono_class_generate_get_corlib_impl (void) { diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 2e57ad8500f284..f32378e036202c 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -126,10 +126,10 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callconv_attribute, "System.Runtime.InteropServices", "UnmanagedCallConvAttribute") - -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") +// used for Swift interop +GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") static gboolean type_is_blittable (MonoType *type); diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index eaef14bf7bdcf1..2785b542860d10 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -771,4 +772,8 @@ mono_mb_create_and_cache_full (GHashTable *cache, gpointer key, IlgenCallbacksToMono* mono_marshal_get_mono_callbacks_for_ilgen (void); +GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_error) +GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE_DECL (swift_error) +GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_self) + #endif /* __MONO_MARSHAL_H__ */ diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 7ab47f2cd96818..2fe7e6377fedfe 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -53,9 +53,6 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - #define IS_IMM32(val) ((((guint64)val) >> 32) == 0) @@ -1080,6 +1077,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) g_assert_not_reached (); } +#ifdef MONO_ARCH_HAVE_SWIFTCALL if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); @@ -1092,6 +1090,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } } } +#endif } if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) { diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 22a79504ce9850..0b04032fed043b 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -125,9 +125,6 @@ static WARN_UNUSED_RESULT guint8* emit_load_regset (guint8 *code, guint64 regs, static guint8* emit_brx (guint8 *code, int reg); static guint8* emit_blrx (guint8 *code, int reg); -static GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -static GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - const char* mono_arch_regname (int reg) { @@ -1874,6 +1871,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } } +#ifdef MONO_ARCH_HAVE_SWIFTCALL if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); @@ -1886,6 +1884,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } } } +#endif } /* Handle the case where there are no implicit arguments */ From 39b8bd0605648df3bd0c7bf80099e48f2e7a0307 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 17 Jan 2024 19:44:31 +0100 Subject: [PATCH 117/137] make cmake architecture specific --- .../Interop/Swift/SwiftErrorHandling/CMakeLists.txt | 9 ++++++++- .../Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt | 9 ++++++++- src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt | 9 ++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt b/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt index 32dd8687a85158..2d07bd3bf745c5 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt +++ b/src/tests/Interop/Swift/SwiftErrorHandling/CMakeLists.txt @@ -3,8 +3,15 @@ include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") set(SOURCE SwiftErrorHandling) +if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) + set(SWIFT_PLATFORM "macosx") + set(SWIFT_PLATFORM_SUFFIX "") + set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) + set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}") +endif() + add_custom_target(${SOURCE} ALL - COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift COMMENT "Generating ${SOURCE} library" ) diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt b/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt index 67eca68857f1d1..dea341f587c159 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/CMakeLists.txt @@ -3,8 +3,15 @@ include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") set(SOURCE SwiftInvalidCallConv) +if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) + set(SWIFT_PLATFORM "macosx") + set(SWIFT_PLATFORM_SUFFIX "") + set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) + set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}") +endif() + add_custom_target(${SOURCE} ALL - COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift COMMENT "Generating ${SOURCE} library" ) diff --git a/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt b/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt index 874cd5501498db..8d7efa1eea6757 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt +++ b/src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt @@ -3,8 +3,15 @@ include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") set(SOURCE SwiftSelfContext) +if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) + set(SWIFT_PLATFORM "macosx") + set(SWIFT_PLATFORM_SUFFIX "") + set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) + set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}") +endif() + add_custom_target(${SOURCE} ALL - COMMAND xcrun swiftc -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib + COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift COMMENT "Generating ${SOURCE} library" ) From eccc6a32bf63df5ae21f38beac7bd653d82b4eae Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 18 Jan 2024 14:45:41 +0100 Subject: [PATCH 118/137] [mono] Use SwiftError as a ref argument instead of raw pointer --- src/mono/mono/metadata/class-internals.h | 22 ------------- src/mono/mono/metadata/marshal.c | 13 +++----- src/mono/mono/metadata/marshal.h | 3 +- src/mono/mono/mini/mini.c | 4 +++ .../SwiftErrorHandling/SwiftErrorHandling.cs | 10 +++--- .../SwiftInvalidCallConv.cs | 31 +++++++++++++------ 6 files changed, 35 insertions(+), 48 deletions(-) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 3ef0b56ee5a212..0015177d5c2c33 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -927,9 +927,6 @@ MonoClass* mono_class_get_##shortname##_class (void); #define GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL(shortname) \ MonoClass* mono_class_try_get_##shortname##_class (void); -#define GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE_DECL(shortname) \ -MonoClass* mono_class_try_get_##shortname##_ptr_class (void); - static inline MonoImage * mono_class_generate_get_corlib_impl (void) { @@ -981,25 +978,6 @@ mono_class_try_get_##shortname##_class (void) \ return klass; \ } - -#define GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE(shortname,name_space,name) \ -MonoClass* \ -mono_class_try_get_##shortname##_ptr_class (void) \ -{ \ - static volatile MonoClass *tmp_class; \ - static volatile gboolean inited; \ - MonoClass *klass = (MonoClass *)tmp_class; \ - mono_memory_barrier (); \ - if (!inited) { \ - klass = mono_class_try_load_from_name (mono_class_generate_get_corlib_impl (), name_space, name); \ - klass = mono_class_create_ptr (m_class_get_byval_arg (klass)); \ - tmp_class = klass; \ - mono_memory_barrier (); \ - inited = TRUE; \ - } \ - return klass; \ -} - GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (safehandle) #ifndef DISABLE_COM diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index f32378e036202c..541baa7ff3524d 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -126,10 +126,6 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callconv_attribute, "System.Runtime.InteropServices", "UnmanagedCallConvAttribute") -// used for Swift interop -GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") static gboolean type_is_blittable (MonoType *type); @@ -3628,17 +3624,16 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, if (mono_method_signature_has_ext_callconv (csig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); int swift_error_args = 0, swift_self_args = 0; for (int i = 0; i < method->signature->param_count; ++i) { MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); if (param_klass) { - if (param_klass == swift_error) { + if (param_klass == swift_error && method->signature->params [i]->byref__ == 0) { swift_error_args = swift_self_args = 0; - mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftError argument must be a pointer."); + mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftError argument must be passed by reference."); break; - } else if (param_klass == swift_error_ptr) { + } else if (param_klass == swift_error) { swift_error_args++; } else if (param_klass == swift_self) { swift_self_args++; @@ -3651,7 +3646,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, } if (swift_self_args > 1 || swift_error_args > 1) { - mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Method signature contains multiple SwiftSelf/SwiftError arguments."); + mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Method signature contains multiple SwiftSelf or SwiftError arguments."); } if (!is_ok (emitted_error)) { diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index 2785b542860d10..7f8e3876b3f047 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -772,8 +772,7 @@ mono_mb_create_and_cache_full (GHashTable *cache, gpointer key, IlgenCallbacksToMono* mono_marshal_get_mono_callbacks_for_ilgen (void); -GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_error) -GENERATE_TRY_GET_CLASS_PTR_WITH_CACHE_DECL (swift_error) GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_self) +GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_error) #endif /* __MONO_MARSHAL_H__ */ diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index b6935d312c6ee8..c9f97f83080418 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -92,6 +92,10 @@ static gint64 discarded_jit_time; #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex) static mono_mutex_t jit_mutex; +// used for Swift interop +GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + #ifndef DISABLE_JIT static guint32 jinfo_try_holes_size; static MonoBackend *current_backend; diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index 998468de48ab64..afb2bf5357af47 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -17,7 +17,7 @@ public class ErrorHandlingTests [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] - public unsafe static extern nint conditionallyThrowError(bool willThrow, SwiftError* error); + public static extern nint conditionallyThrowError(bool willThrow, ref SwiftError error); [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4from13messageLengthSPys6UInt16VGSgs0B0_p_s5Int32VztF")] public unsafe static extern void* GetErrorMessage(void* handle, out int length); @@ -28,10 +28,10 @@ public unsafe static void TestSwiftErrorThrown() const string expectedErrorMessage = "Catch me if you can!"; SetErrorMessageForSwift(expectedErrorMessage); - SwiftError error; + SwiftError error = new SwiftError(); // This will throw an error - conditionallyThrowError(true, &error); + conditionallyThrowError(true, ref error); Assert.True(error.Value != null, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); @@ -44,10 +44,10 @@ public unsafe static void TestSwiftErrorNotThrown() const string expectedErrorMessage = "Catch me if you can!"; SetErrorMessageForSwift(expectedErrorMessage); - SwiftError error; + SwiftError error = new SwiftError(); // This will not throw an error - int result = (int)conditionallyThrowError(false, &error); + int result = (int)conditionallyThrowError(false, ref error); Assert.True(error.Value == null, "No Swift error was expected to be thrown."); Assert.True(result == 42, "The result from Swift does not match the expected value."); diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs index db725f83d263ca..faec2bdc35a4b9 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -22,16 +22,20 @@ public class StringClass [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public unsafe static extern void FuncWithTwoErrorParameters(SwiftError* error1, SwiftError* error2); + public static extern void FuncWithTwoErrorParameters(ref SwiftError error1, ref SwiftError error2); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public unsafe static extern void FuncWithMixedParameters(SwiftSelf self1, SwiftSelf self2, SwiftError* error1, SwiftError* error2); + public static extern void FuncWithMixedParameters(SwiftSelf self1, SwiftSelf self2, ref SwiftError error1, ref SwiftError error2); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] public static extern void FuncWithSwiftErrorAsArg(SwiftError error1); + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] + public unsafe static extern void FuncWithSwiftErrorAsUnsafeArg(SwiftError* error1); + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] public static extern void FuncWithNonPrimitiveArg(StringClass arg1); @@ -45,26 +49,24 @@ public static void TestFuncWithTwoSelfParameters() } [Fact] - public unsafe static void TestFuncWithTwoErrorParameters() + public static void TestFuncWithTwoErrorParameters() { // Invalid due to multiple SwiftError arguments. SwiftError error = new SwiftError(); - SwiftError* errorPtr = &error; - Assert.Throws(() => FuncWithTwoErrorParameters(errorPtr, errorPtr)); + Assert.Throws(() => FuncWithTwoErrorParameters(ref error, ref error)); } [Fact] - public unsafe static void TestFuncWithMixedParameters() + public static void TestFuncWithMixedParameters() { // Invalid due to multiple SwiftSelf/SwiftError arguments. SwiftSelf self = new SwiftSelf(); SwiftError error = new SwiftError(); - SwiftError* errorPtr = &error; - Assert.Throws(() => FuncWithMixedParameters(self, self, errorPtr, errorPtr)); + Assert.Throws(() => FuncWithMixedParameters(self, self, ref error, ref error)); } [Fact] - public unsafe static void TestFuncWithSwiftErrorAsArg() + public static void TestFuncWithSwiftErrorAsArg() { // Invalid due to SwiftError not passed as a pointer. SwiftError error = new SwiftError(); @@ -72,7 +74,16 @@ public unsafe static void TestFuncWithSwiftErrorAsArg() } [Fact] - public unsafe static void TestFuncWithNonPrimitiveArg() + public unsafe static void TestFuncWithSwiftErrorAsUnsafeArg() + { + // Invalid due to SwiftError not passed as an unsafe pointer. + SwiftError error = new SwiftError(); + SwiftError *errorPtr = &error; + Assert.Throws(() => FuncWithSwiftErrorAsUnsafeArg(errorPtr)); + } + + [Fact] + public static void TestFuncWithNonPrimitiveArg() { // Invalid due to a non-primitive argument. StringClass arg1 = new StringClass(); From a6f3369b3bd0ea1b99a2c4e68ed7e846fc844272 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 18 Jan 2024 15:03:26 +0100 Subject: [PATCH 119/137] [mono] Refactor mini to store and load Swift context regs directly in calling code Initially, Swift types were added as new argument types in ArgInfo, which lacked information on arg storage (param regs or stack). This change directly uses context registers during the call_emit function. Additionally, the code is moved the method prolog and epilog to the IR to reduce complexity and prevent errors. --- src/mono/mono/mini/interp/interp.c | 7 +- src/mono/mono/mini/mini-amd64.c | 126 +++++++++++++---------------- src/mono/mono/mini/mini-amd64.h | 3 +- src/mono/mono/mini/mini-arm64.c | 122 +++++++++++++--------------- src/mono/mono/mini/mini-arm64.h | 5 +- src/mono/mono/mini/mini-codegen.c | 3 + src/mono/mono/mini/mini.h | 2 +- 7 files changed, 123 insertions(+), 145 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index df787735f07686..b5e775cd4fa26f 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1763,11 +1763,12 @@ ves_pinvoke_method ( #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP #ifdef MONO_ARCH_HAVE_SWIFTCALL if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - int arg_index; - gpointer data = mono_arch_get_swift_error (&ccontext, sig, call_info, &arg_index); + int arg_index = -1; + gpointer data = mono_arch_get_swift_error (&ccontext, sig, &arg_index); // Perform an indirect store at arg_index stack location - if (data != NULL) { + if (arg_index >= 0) { + g_assert (data); stackval *result = (stackval*) STACK_ADD_BYTES (frame.stack, get_arg_offset (frame.imethod, sig, arg_index)); *(gpointer*)result->data.p = *(gpointer*)data; } diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 2fe7e6377fedfe..c7ccc23b2f572e 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1076,21 +1076,6 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) default: g_assert_not_reached (); } - -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_error_ptr) { - ainfo->storage = ArgSwiftError; - } else if (klass == swift_self) { - ainfo->storage = ArgSwiftSelf; - } - } - } -#endif } if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) { @@ -1122,10 +1107,6 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) switch (ainfo->storage) { case ArgInIReg: return &ccontext->gregs [ainfo->reg]; - case ArgSwiftSelf: - return &ccontext->gregs [AMD64_R13]; - case ArgSwiftError: - return &ccontext->gregs [AMD64_R12]; case ArgInFloatSSEReg: case ArgInDoubleSSEReg: return &ccontext->fregs [ainfo->reg]; @@ -1258,10 +1239,6 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M storage = arg_get_storage (ccontext, ainfo); *(gpointer *)storage = interp_cb->frame_arg_to_storage (frame, sig, i); continue; - } else if (ainfo->storage == ArgSwiftError) { - storage = arg_get_storage (ccontext, ainfo); - *(gpointer*)storage = 0; - continue; } int temp_size = arg_need_temp (ainfo); @@ -1271,6 +1248,23 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M else storage = arg_get_storage (ccontext, ainfo); +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + if (klass == swift_self) { + storage = &ccontext->gregs [AMD64_R13]; + } else if (klass == swift_error) { + storage = &ccontext->gregs [AMD64_R12]; + *(gpointer*)storage = 0; + continue; + } + } + } +#endif + interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage); if (temp_size) arg_set_val (ccontext, ainfo, storage); @@ -1385,20 +1379,18 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo /** * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. * - * The function searches for an argument with the storage type `ArgSwiftError`. + * The function searches for an argument with SwiftError type. * If found, it retrieves the value from `ccontext`. */ gpointer -mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, int *arg_index) { - CallInfo *cinfo = (CallInfo*)call_info; - ArgInfo *ainfo; - + MonoClass *swift_error = mono_class_try_get_swift_error_class (); for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { - ainfo = &cinfo->args [i]; - if (ainfo->storage == ArgSwiftError) { + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass && klass == swift_error) { *arg_index = i; - return arg_get_storage (ccontext, ainfo); + return &ccontext->gregs [AMD64_R12]; } } @@ -1918,8 +1910,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) for (guint i = 0; i < sig->param_count + sig->hasthis; ++i) { ins = cfg->args [i]; - /* We force the ArgSwiftError to be allocated to the stack slot because we need to retrieve it after the call */ - if (ins->opcode != OP_REGVAR || cinfo->args [i].storage == ArgSwiftError) { + if (ins->opcode != OP_REGVAR) { ArgInfo *ainfo = &cinfo->args [i]; gboolean inreg = TRUE; @@ -1932,7 +1923,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) * are volatile across calls. * FIXME: Optimize this. */ - if ((ainfo->storage == ArgInIReg) || (ainfo->storage == ArgInFloatSSEReg) || (ainfo->storage == ArgInDoubleSSEReg) || (ainfo->storage == ArgValuetypeInReg) || (ainfo->storage == ArgGSharedVtInReg) || (ainfo->storage == ArgSwiftError) || (ainfo->storage == ArgSwiftSelf)) + if ((ainfo->storage == ArgInIReg) || (ainfo->storage == ArgInFloatSSEReg) || (ainfo->storage == ArgInDoubleSSEReg) || (ainfo->storage == ArgValuetypeInReg) || (ainfo->storage == ArgGSharedVtInReg)) inreg = FALSE; ins->opcode = OP_REGOFFSET; @@ -1942,7 +1933,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInFloatSSEReg: case ArgInDoubleSSEReg: case ArgGSharedVtInReg: - case ArgSwiftError: if (inreg) { ins->opcode = OP_REGVAR; ins->dreg = ainfo->reg; @@ -1956,7 +1946,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->inst_offset = ainfo->offset + ARGS_OFFSET; break; case ArgValuetypeInReg: - case ArgSwiftSelf: break; case ArgValuetypeAddrInIReg: case ArgValuetypeAddrOnStack: { @@ -2063,7 +2052,6 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int re switch (storage) { case ArgInIReg: - case ArgSwiftError: MONO_INST_NEW (cfg, ins, OP_MOVE); ins->dreg = mono_alloc_ireg_copy (cfg, tree->dreg); ins->sreg1 = tree->dreg; @@ -2317,6 +2305,26 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) ainfo = cinfo->args + i; in = call->args [i]; +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + if (klass == swift_self) { + if (ainfo->storage == ArgInIReg) + ainfo->reg = GINT32_TO_UINT8 (AMD64_R13); + else if (ainfo->storage == ArgValuetypeInReg) + ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); + else + g_assert_not_reached (); + } else if (klass == swift_error) { + cfg->arch.swift_error_var = in; + MONO_EMIT_NEW_ICONST (cfg, AMD64_R12, 0); + } + } + } +#endif if (sig->hasthis && i == 0) t = mono_get_object_type (); @@ -2353,7 +2361,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) in = call->args [i]; - if (ainfo->storage == ArgInIReg || ainfo->storage == ArgSwiftError) + if (ainfo->storage == ArgInIReg) add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, in); } @@ -2372,7 +2380,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) switch (ainfo->storage) { case ArgInIReg: - case ArgSwiftError: /* Already done */ break; case ArgInFloatSSEReg: @@ -2384,8 +2391,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgValuetypeAddrInIReg: case ArgValuetypeAddrOnStack: case ArgGSharedVtInReg: - case ArgGSharedVtOnStack: - case ArgSwiftSelf: { + case ArgGSharedVtOnStack: { if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t)) /* Already emitted above */ break; @@ -2501,8 +2507,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) int size = ins->backend.size; switch (ainfo->storage) { - case ArgValuetypeInReg: - case ArgSwiftSelf: { + case ArgValuetypeInReg: { MonoInst *load; int part; @@ -2601,6 +2606,15 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) { MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret); +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + if (cfg->arch.swift_error_var) { + MonoInst *arg = cfg->arch.swift_error_var; + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, arg->inst_basereg, arg->inst_offset, AMD64_R12); + } + } +#endif + if (ret->type == MONO_TYPE_R4) { if (COMPILE_LLVM (cfg)) MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg); @@ -8146,8 +8160,7 @@ MONO_RESTORE_WARNING /* Save volatile arguments to the stack */ if (ins->opcode != OP_REGVAR) { switch (ainfo->storage) { - case ArgInIReg: - case ArgSwiftError: { + case ArgInIReg: { guint32 size = 8; /* FIXME: I1 etc */ @@ -8172,10 +8185,6 @@ MONO_RESTORE_WARNING mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, GPTRDIFF_TO_INT (code - cfg->native_code)); mono_add_var_location (cfg, ins, FALSE, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset), GPTRDIFF_TO_INT (code - cfg->native_code), 0); } - - if (ainfo->storage == ArgSwiftError) { - amd64_mov_reg_imm (code, AMD64_R12, 0); - } break; } case ArgInFloatSSEReg: @@ -8185,7 +8194,6 @@ MONO_RESTORE_WARNING amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset, ainfo->reg); break; case ArgValuetypeInReg: - case ArgSwiftSelf: for (quad = 0; quad < 2; quad ++) { switch (ainfo->pair_storage [quad]) { case ArgInIReg: @@ -8203,10 +8211,6 @@ MONO_RESTORE_WARNING g_assert_not_reached (); } } - - if (ainfo->storage == ArgSwiftSelf) { - amd64_mov_reg_membase (code, AMD64_R13, ins->inst_basereg, ins->inst_offset, sizeof(gpointer)); - } break; case ArgValuetypeAddrInIReg: if (ainfo->pair_storage [0] == ArgInIReg) @@ -8224,7 +8228,6 @@ MONO_RESTORE_WARNING /* Argument allocated to (non-volatile) register */ switch (ainfo->storage) { case ArgInIReg: - case ArgSwiftError: amd64_mov_reg_reg (code, ins->dreg, ainfo->reg, 8); break; case ArgOnStack: @@ -8372,19 +8375,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) code = realloc_code (cfg, max_epilog_size); cinfo = cfg->arch.cinfo; - for (int i = 0; i < cinfo->nargs; ++i) { - ArgInfo* ainfo = cinfo->args + i; - MonoInst* arg = cfg->args [i]; - - switch (ainfo->storage) { - case ArgSwiftError: - amd64_mov_reg_membase (code, AMD64_R11, arg->inst_basereg, arg->inst_offset, 8); - amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, 8); - break; - default: - break; - } - } cfg->has_unwind_info_for_epilog = TRUE; diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 57de5b6ea3d75a..c3f91b19f3d4e1 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -211,6 +211,7 @@ typedef struct MonoCompileArch { MonoInst *ss_tramp_var; MonoInst *bp_tramp_var; MonoInst *lmf_var; + MonoInst *swift_error_var; #ifdef HOST_WIN32 struct _UNWIND_INFO* unwindinfo; #endif @@ -301,8 +302,6 @@ typedef enum { ArgGSharedVtOnStack, /* Variable sized gsharedvt argument passed/returned by addr */ ArgGsharedvtVariableInReg, - ArgSwiftError, - ArgSwiftSelf, ArgNone /* only in pair_storage */ } ArgStorage; diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 0b04032fed043b..1b244f6d7e7366 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1870,21 +1870,6 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->gr ++; } } - -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_error_ptr = mono_class_try_get_swift_error_ptr_class (); - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); - if (klass) { - if (klass == swift_error_ptr) { - ainfo->storage = ArgSwiftError; - } else if (klass == swift_self) { - ainfo->storage = ArgSwiftSelf; - } - } - } -#endif } /* Handle the case where there are no implicit arguments */ @@ -1917,10 +1902,6 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgVtypeInIRegs: case ArgInIReg: return &ccontext->gregs [ainfo->reg]; - case ArgSwiftSelf: - return &ccontext->gregs [PARAM_REGS + 1 + ARMREG_R20 - CTX_REGS_OFFSET]; - case ArgSwiftError: - return &ccontext->gregs [PARAM_REGS + 1 + ARMREG_R21 - CTX_REGS_OFFSET]; case ArgInFReg: case ArgInFRegR4: case ArgHFA: @@ -2012,7 +1993,7 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M for (int i = 0; i < sig->param_count; i++) { ainfo = &cinfo->args [i]; - + if (ainfo->storage == ArgVtypeByRef) { ccontext->gregs [ainfo->reg] = (host_mgreg_t)interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, i); continue; @@ -2020,10 +2001,6 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M storage = ccontext->stack + ainfo->offset; *(gpointer*)storage = interp_cb->frame_arg_to_storage (frame, sig, i); continue; - } else if (ainfo->storage == ArgSwiftError) { - storage = arg_get_storage (ccontext, ainfo); - *(gpointer*)storage = 0; - continue; } int temp_size = arg_need_temp (ainfo); @@ -2033,6 +2010,23 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M else storage = arg_get_storage (ccontext, ainfo); +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + if (klass == swift_self) { + storage = &ccontext->gregs [PARAM_REGS + 1]; + } else if (klass == swift_error) { + storage = &ccontext->gregs [PARAM_REGS + 2]; + *(gpointer*)storage = 0; + continue; + } + } + } +#endif + interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage); if (temp_size) arg_set_val (ccontext, ainfo, storage); @@ -2134,20 +2128,18 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo /** * Gets error context from `ccontext` registers by indirectly storing the value onto the stack. * - * The function searches for an argument with the storage type `ArgSwiftError`. + * The function searches for an argument with SwiftError type * If found, it retrieves the value from `ccontext`. */ gpointer -mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index) +mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, int *arg_index) { - CallInfo *cinfo = (CallInfo*)call_info; - ArgInfo *ainfo; - + MonoClass *swift_error = mono_class_try_get_swift_error_class (); for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { - ainfo = &cinfo->args [i]; - if (ainfo->storage == ArgSwiftError) { + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass && klass == swift_error) { *arg_index = i; - return arg_get_storage (ccontext, ainfo); + return &ccontext->gregs [PARAM_REGS + 2]; } } @@ -2781,8 +2773,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) ainfo = cinfo->args + i; ins = cfg->args [i]; - /* We force the ArgSwiftError to be allocated to the stack slot because we need to retrieve it after the call */ - if (ins->opcode == OP_REGVAR && ainfo->storage != ArgSwiftError) + if (ins->opcode == OP_REGVAR) continue; ins->opcode = OP_REGOFFSET; @@ -2792,7 +2783,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInIReg: case ArgInFReg: case ArgInFRegR4: - case ArgSwiftError: // FIXME: Use nregs/size /* These will be copied to the stack in the prolog */ ins->inst_offset = offset; @@ -2810,7 +2800,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgVtypeInIRegs: case ArgHFA: case ArgInSIMDReg: - case ArgSwiftSelf: ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; /* These arguments are saved to the stack in the prolog */ @@ -3054,7 +3043,6 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int re switch (storage) { case ArgInIReg: - case ArgSwiftError: MONO_INST_NEW (cfg, ins, OP_MOVE); ins->dreg = mono_alloc_ireg_copy (cfg, arg->dreg); ins->sreg1 = arg->dreg; @@ -3165,11 +3153,26 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) emit_sig_cookie (cfg, call, cinfo); } +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + if (klass == swift_self) { + ainfo->reg = ARMREG_R20; + } else if (klass == swift_error) { + cfg->arch.swift_error_var = arg; + MONO_EMIT_NEW_ICONST (cfg, ARMREG_R21, 0); + } + } + } +#endif + switch (ainfo->storage) { case ArgInIReg: case ArgInFReg: case ArgInFRegR4: - case ArgSwiftError: add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, arg); break; case ArgOnStack: @@ -3202,8 +3205,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgVtypeByRefOnStack: case ArgVtypeOnStack: case ArgInSIMDReg: - case ArgHFA: - case ArgSwiftSelf: { + case ArgHFA: { MonoInst *ins; guint32 align; guint32 size; @@ -3247,7 +3249,6 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) switch (ainfo->storage) { case ArgVtypeInIRegs: - case ArgSwiftSelf: for (i = 0; i < ainfo->nregs; ++i) { // FIXME: Smaller sizes MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE); @@ -3364,10 +3365,19 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) void mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) { - MonoMethodSignature *sig; + MonoMethodSignature *sig = mono_method_signature_internal (cfg->method); CallInfo *cinfo; - sig = mono_method_signature_internal (cfg->method); +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + if (cfg->arch.swift_error_var) { + MonoInst *arg = cfg->arch.swift_error_var; + MonoInst *store; + EMIT_NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, arg->inst_basereg, arg->inst_offset, ARMREG_R21); + } + } +#endif + if (!cfg->arch.cinfo) cfg->arch.cinfo = get_call_info (cfg->mempool, sig); cinfo = cfg->arch.cinfo; @@ -5848,17 +5858,12 @@ emit_move_args (MonoCompile *cfg, guint8 *code) switch (ainfo->storage) { case ArgInIReg: - case ArgSwiftError: /* Stack slots for arguments have size 8 */ code = emit_strx (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); if (i == 0 && sig->hasthis) { mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, GPTRDIFF_TO_INT (code - cfg->native_code)); mono_add_var_location (cfg, ins, FALSE, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset), GPTRDIFF_TO_INT (code - cfg->native_code), 0); } - - if (ainfo->storage == ArgSwiftError) { - code = emit_imm (code, ARMREG_R21, 0); - } break; case ArgInFReg: code = emit_strfpx (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); @@ -5886,7 +5891,6 @@ emit_move_args (MonoCompile *cfg, guint8 *code) break; } case ArgVtypeInIRegs: - case ArgSwiftSelf: for (part = 0; part < ainfo->nregs; part ++) { int offs = GTMREG_TO_INT (ins->inst_offset + (part * 8)); if (part + 1 < ainfo->nregs && IS_VALID_STPX_OFFSET (offs)) { @@ -5895,10 +5899,6 @@ emit_move_args (MonoCompile *cfg, guint8 *code) continue; } code = emit_strx (code, ainfo->reg + part, ins->inst_basereg, offs); - - if (ainfo->storage == ArgSwiftSelf) { - code = emit_ldrx (code, ARMREG_R20, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); - } } break; case ArgHFA: @@ -6273,21 +6273,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) max_epilog_size = 16 + 20*4; code = realloc_code (cfg, max_epilog_size); - cinfo = cfg->arch.cinfo; - for (i = 0; i < cinfo->nargs; ++i) { - ArgInfo* ainfo = cinfo->args + i; - MonoInst* arg = cfg->args [i]; - - switch (ainfo->storage) { - case ArgSwiftError: - code = emit_ldrx (code, ARMREG_IP0, arg->inst_basereg, GTMREG_TO_INT (arg->inst_offset)); - arm_strx (code, ARMREG_R21, ARMREG_IP0, 0); - break; - default: - break; - } - } - if (cfg->method->save_lmf) { code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, GTMREG_TO_INT (cfg->lmf_var->inst_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs) - (MONO_ARCH_FIRST_LMF_REG * 8))); } else { @@ -6296,6 +6281,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) } /* Load returned vtypes into registers if needed */ + cinfo = cfg->arch.cinfo; switch (cinfo->ret.storage) { case ArgVtypeInIRegs: { MonoInst *ins = cfg->ret; diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index d61936e9535068..27ea7788195613 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -121,6 +121,7 @@ typedef struct { MonoInst *seq_point_info_var; MonoInst *ss_tramp_var; MonoInst *bp_tramp_var; + MonoInst *swift_error_var; guint8 *thunks; int thunks_size; } MonoCompileArch; @@ -240,8 +241,6 @@ typedef enum { ArgVtypeByRefOnStack, ArgVtypeOnStack, ArgHFA, - ArgSwiftError, - ArgSwiftSelf, ArgNone } ArgStorage; @@ -276,7 +275,7 @@ struct CallInfo { }; typedef struct { - /* General registers + context registers + ARMREG_R8 for indirect returns */ + /* General registers + ARMREG_R8 for indirect returns + context registers */ host_mgreg_t gregs [PARAM_REGS + CTX_REGS + 1]; /* Floating registers */ double fregs [FP_PARAM_REGS]; diff --git a/src/mono/mono/mini/mini-codegen.c b/src/mono/mono/mini/mini-codegen.c index efcf9c2564ac66..21b03a98ee7e08 100644 --- a/src/mono/mono/mini/mini-codegen.c +++ b/src/mono/mono/mini/mini-codegen.c @@ -1095,6 +1095,9 @@ assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, int bank) #if !defined(TARGET_ARM) && !defined(TARGET_ARM64) /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */ /* On arm64, rgctx_reg is a global hreg, and it is used to pass an argument */ +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && (hreg == AMD64_R12 || hreg == AMD64_R13))) +#endif g_assert (! is_global_ireg (hreg)); #endif diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 77ef60a4405413..61605862169646 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2567,7 +2567,7 @@ gpointer mono_arch_get_native_call_context_args (CallContext *ccontext, gpoi void mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig, gpointer call_info); #ifdef MONO_ARCH_HAVE_SWIFTCALL // After the pinvoke call is done, this return an error context value from the ccontext. -gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, gpointer call_info, int *arg_index); +gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, int *arg_index); #endif /* Free the structure returned by mono_arch_get_interp_native_call_info (NULL, sig) */ void mono_arch_free_interp_native_call_info (gpointer call_info); From 0b3920e17e58aeb0aacd0a0e9a558830900d376f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 18 Jan 2024 15:12:55 +0100 Subject: [PATCH 120/137] Revert unnecessary changes --- src/mono/mono/metadata/metadata.c | 1 - src/mono/mono/mini/mini-amd64.c | 3 +-- src/mono/mono/mini/mini-arm64.c | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 17e0abfac27b18..05b6166d8bf946 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -2654,7 +2654,6 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c if (*ptr & 0x40) explicit_this = 1; call_convention = *ptr & 0x0F; - ptr++; if (gen_param_count) gen_param_count = mono_metadata_decode_value (ptr, &ptr); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index c7ccc23b2f572e..6f91e9bad351ba 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -8374,8 +8374,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) code = realloc_code (cfg, max_epilog_size); - cinfo = cfg->arch.cinfo; - cfg->has_unwind_info_for_epilog = TRUE; /* Mark the start of the epilog */ @@ -8412,6 +8410,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) } /* Load returned vtypes into registers if needed */ + cinfo = cfg->arch.cinfo; if (cinfo->ret.storage == ArgValuetypeInReg) { ArgInfo *ainfo = &cinfo->ret; MonoInst *inst = cfg->ret; diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 1b244f6d7e7366..f6d9522ad53221 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1993,7 +1993,7 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M for (int i = 0; i < sig->param_count; i++) { ainfo = &cinfo->args [i]; - + if (ainfo->storage == ArgVtypeByRef) { ccontext->gregs [ainfo->reg] = (host_mgreg_t)interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, i); continue; From 0e4a48c3047f82ced67697a7d01a0b37bcbb74bf Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 18 Jan 2024 17:28:45 +0100 Subject: [PATCH 121/137] [mini] Always pass SwiftSelf as ArgVtypeInIRegs via dedicated ctx reg --- src/mono/mono/mini/mini-amd64.c | 14 ++++--- src/mono/mono/mini/mini-arm64.c | 8 ++++ .../SwiftErrorHandling/SwiftErrorHandling.cs | 37 +++++++++++++++++++ .../SwiftSelfContext/SwiftSelfContext.cs | 16 ++++++++ 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 6f91e9bad351ba..3a391c27d74868 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -2312,12 +2312,14 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass) { if (klass == swift_self) { - if (ainfo->storage == ArgInIReg) - ainfo->reg = GINT32_TO_UINT8 (AMD64_R13); - else if (ainfo->storage == ArgValuetypeInReg) - ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); - else - g_assert_not_reached (); + guint32 size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); + g_assert (size == sizeof (target_mgreg_t)); + ainfo->storage = ArgValuetypeInReg; + ainfo->pair_storage [0] = ArgInIReg; + ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); + ainfo->nregs = 1; + ainfo->arg_size = 0; + ainfo->offset = 0; } else if (klass == swift_error) { cfg->arch.swift_error_var = in; MONO_EMIT_NEW_ICONST (cfg, AMD64_R12, 0); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index f6d9522ad53221..855315d9a0f437 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -3160,7 +3160,15 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass) { if (klass == swift_self) { + guint32 align; + MonoType *t = mini_get_underlying_type (sig->params [i]); + int size = mini_type_stack_size_full (t, &align, cinfo->pinvoke); + guint32 align_size = ALIGN_TO (size, 8); + + ainfo->storage = ArgVtypeInIRegs; ainfo->reg = ARMREG_R20; + ainfo->nregs = align_size / 8; + ainfo->size = size; } else if (klass == swift_error) { cfg->arch.swift_error_var = arg; MONO_EMIT_NEW_ICONST (cfg, ARMREG_R21, 0); diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index afb2bf5357af47..ac724b3c2dd731 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -19,6 +19,10 @@ public class ErrorHandlingTests [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] public static extern nint conditionallyThrowError(bool willThrow, ref SwiftError error); + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] + public static extern nint conditionallyThrowErrorOnStack(bool willThrow, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, int dummy8, int dummy9, ref SwiftError error); + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4from13messageLengthSPys6UInt16VGSgs0B0_p_s5Int32VztF")] public unsafe static extern void* GetErrorMessage(void* handle, out int length); @@ -52,6 +56,39 @@ public unsafe static void TestSwiftErrorNotThrown() Assert.True(error.Value == null, "No Swift error was expected to be thrown."); Assert.True(result == 42, "The result from Swift does not match the expected value."); } + + [Fact] + public unsafe static void TestSwiftErrorOnStackThrown() + { + const string expectedErrorMessage = "Catch me if you can!"; + SetErrorMessageForSwift(expectedErrorMessage); + + SwiftError error = new SwiftError(); + + int i = 0; + // This will throw an error + conditionallyThrowErrorOnStack(true, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, ref error); + Assert.True(error.Value != null, "A Swift error was expected to be thrown."); + + string errorMessage = GetErrorMessageFromSwift(error); + Assert.True(errorMessage == expectedErrorMessage, string.Format("The error message retrieved from Swift does not match the expected message. Expected: {0}, Actual: {1}", expectedErrorMessage, errorMessage)); + } + + [Fact] + public unsafe static void TestSwiftErrorOnStackNotThrown() + { + const string expectedErrorMessage = "Catch me if you can!"; + SetErrorMessageForSwift(expectedErrorMessage); + + SwiftError error = new SwiftError(); + + int i = 0; + // This will not throw an error + int result = (int)conditionallyThrowErrorOnStack(false, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, ref error); + + Assert.True(error.Value == null, "No Swift error was expected to be thrown."); + Assert.True(result == 42, "The result from Swift does not match the expected value."); + } private static void SetErrorMessageForSwift(string message) { diff --git a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs index c37c7eea45f5c4..bbd234639cc9e9 100644 --- a/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs +++ b/src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs @@ -18,6 +18,10 @@ public class SelfContextTests [DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyF")] public static extern nint getMagicNumber(SwiftSelf self); + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] + [DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyF")] + public static extern nint getMagicNumberOnStack(int dummy0, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, int dummy8, int dummy9, SwiftSelf self); + [Fact] public unsafe static void TestSwiftSelfContext() { @@ -28,4 +32,16 @@ public unsafe static void TestSwiftSelfContext() int result = (int)getMagicNumber(self); Assert.True(result == 42, "The result from Swift does not match the expected value."); } + + [Fact] + public unsafe static void TestSwiftSelfContextOnStack() + { + void* pointer = getInstance(); + SwiftSelf self = new SwiftSelf(pointer); + Assert.True(self.Value != null, "Failed to obtain an instance of SwiftSelf from the Swift library."); + + int i = 0; + int result = (int)getMagicNumberOnStack(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, self); + Assert.True(result == 42, "The result from Swift does not match the expected value."); + } } From 2b3d6ff77bc2a9dd0305844e532b77338aff9113 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 22 Jan 2024 17:31:01 +0100 Subject: [PATCH 122/137] [mono] Update Swift context registers allocation for P/Invoke This commit adds context registers allocation for SwiftSelf and SwiftError. SwiftSelf is considered a standard argument for P/Invoke, where the register allocator always utilizes the dedicated context register. SwiftError is introduced as a new arg storage type ArgSwiftError and passed to the managed-to-native wrapper, but it is not passed to the native function. Instead, in the method prolog, the dedicated context register is set to 0. In the method epilog, the context register is stored into SwiftError. Here is an example for arm64: managed_to_native_wrapper(swiftself, swifterror) str &swifterror, [sp, #swift_error_var] // Store the address of swifterror on the stack ldr R20, swiftself // Swiftself is always passed through the dedicated register ldr R21, 0x0 // Set SwiftError register to 0 call native function ldr IP0, [sp, #swift_error_var] // Load &swifterror str R21, IP0 // Store R21 into swifterror --- src/mono/mono/mini/mini-amd64.c | 107 +++++++++++++++++++++----------- src/mono/mono/mini/mini-amd64.h | 1 + src/mono/mono/mini/mini-arm64.c | 106 +++++++++++++++++++------------ src/mono/mono/mini/mini-arm64.h | 1 + 4 files changed, 139 insertions(+), 76 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 3a391c27d74868..ba66de3d031722 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1007,6 +1007,34 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } ptype = mini_get_underlying_type (sig->params [i]); + +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); + if (klass) { + if (klass == swift_self && sig->pinvoke) { + guint32 old_gr = gr; + if (gr >= PARAM_REGS) + gr--; + add_valuetype (sig, ainfo, ptype, FALSE, &gr, &fr, &stack_size); + ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); + if (old_gr < PARAM_REGS) + gr--; + continue; + } else if (klass == swift_error) { + if (sig->pinvoke) + ainfo->reg = GINT32_TO_UINT8 (AMD64_R12); + else + add_general (&gr, &stack_size, ainfo); + ainfo->storage = ArgSwiftError; + continue; + } + } + } +#endif + switch (ptype->type) { case MONO_TYPE_I1: ainfo->is_signed = 1; @@ -1132,6 +1160,8 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) case ArgValuetypeAddrInIReg: g_assert (ainfo->pair_storage [0] == ArgInIReg && ainfo->pair_storage [1] == ArgNone); return &ccontext->gregs [ainfo->pair_regs [0]]; + case ArgSwiftError: + return &ccontext->gregs [AMD64_R12]; default: g_error ("Arg storage type not yet supported"); } @@ -1257,7 +1287,6 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M if (klass == swift_self) { storage = &ccontext->gregs [AMD64_R13]; } else if (klass == swift_error) { - storage = &ccontext->gregs [AMD64_R12]; *(gpointer*)storage = 0; continue; } @@ -1662,8 +1691,8 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) regs = g_list_prepend (regs, (gpointer)AMD64_RBX); if (!mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { regs = g_list_prepend (regs, (gpointer)AMD64_R12); - regs = g_list_prepend (regs, (gpointer)AMD64_R13); } + regs = g_list_prepend (regs, (gpointer)AMD64_R13); regs = g_list_prepend (regs, (gpointer)AMD64_R14); regs = g_list_prepend (regs, (gpointer)AMD64_R15); #ifdef TARGET_WIN32 @@ -1814,12 +1843,12 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->arch.saved_iregs |= iregs_to_save; } +#ifdef MONO_ARCH_HAVE_SWIFTCALL if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - cfg->arch.saved_iregs |= (size_t)(1 << AMD64_R12) ; + cfg->arch.saved_iregs |= (size_t)(1 << AMD64_R12); cfg->used_int_regs |= (size_t)(1 << AMD64_R12); - cfg->arch.saved_iregs |= (size_t)(1 << AMD64_R13); - cfg->used_int_regs |= (size_t)(1 << AMD64_R13); } +#endif if (cfg->arch.omit_fp) cfg->arch.reg_save_area_offset = offset; @@ -1971,6 +2000,11 @@ mono_arch_allocate_vars (MonoCompile *cfg) break; } + case ArgSwiftError: { + ins->flags &= ~MONO_INST_IS_DEAD; + cfg->arch.swift_error_var->flags |= MONO_INST_IS_DEAD; + } + break; default: NOT_IMPLEMENTED; } @@ -2043,6 +2077,15 @@ mono_arch_create_vars (MonoCompile *cfg) if (cfg->method->save_lmf) { cfg->lmf_ir = TRUE; } + +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoInst *ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); + ins->flags |= MONO_INST_VOLATILE; + cfg->arch.swift_error_var = ins; + } +#endif + } static void @@ -2305,29 +2348,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) ainfo = cinfo->args + i; in = call->args [i]; -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_self) { - guint32 size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); - g_assert (size == sizeof (target_mgreg_t)); - ainfo->storage = ArgValuetypeInReg; - ainfo->pair_storage [0] = ArgInIReg; - ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); - ainfo->nregs = 1; - ainfo->arg_size = 0; - ainfo->offset = 0; - } else if (klass == swift_error) { - cfg->arch.swift_error_var = in; - MONO_EMIT_NEW_ICONST (cfg, AMD64_R12, 0); - } - } - } -#endif - if (sig->hasthis && i == 0) t = mono_get_object_type (); else @@ -2432,6 +2452,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } break; } + case ArgSwiftError: { + MONO_EMIT_NEW_I8CONST (cfg, ainfo->reg, 0); + break; + } default: g_assert_not_reached (); } @@ -2608,15 +2632,6 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) { MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret); -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - if (cfg->arch.swift_error_var) { - MonoInst *arg = cfg->arch.swift_error_var; - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, arg->inst_basereg, arg->inst_offset, AMD64_R12); - } - } -#endif - if (ret->type == MONO_TYPE_R4) { if (COMPILE_LLVM (cfg)) MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg); @@ -8223,6 +8238,14 @@ MONO_RESTORE_WARNING case ArgGSharedVtInReg: amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset, ainfo->reg, 8); break; + case ArgSwiftError: + if (ainfo->offset) { + amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, ARGS_OFFSET + ainfo->offset, 8); + amd64_mov_membase_reg (code, cfg->arch.swift_error_var->inst_basereg, cfg->arch.swift_error_var->inst_offset, AMD64_R11, sizeof (target_mgreg_t)); + } else { + amd64_mov_membase_reg (code, cfg->arch.swift_error_var->inst_basereg, cfg->arch.swift_error_var->inst_offset, ainfo->reg, sizeof (target_mgreg_t)); + } + break; default: break; } @@ -8381,6 +8404,16 @@ mono_arch_emit_epilog (MonoCompile *cfg) /* Mark the start of the epilog */ mono_emit_unwind_op_mark_loc (cfg, code, 0); +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + if (cfg->arch.swift_error_var && (cfg->arch.swift_error_var->flags & MONO_INST_IS_DEAD)) { + MonoInst *ins = cfg->arch.swift_error_var; + amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); + } + } +#endif + /* Save the uwind state which is needed by the out-of-line code */ mono_emit_unwind_op_remember_state (cfg, code); diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index c3f91b19f3d4e1..bb49e9a50676e5 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -302,6 +302,7 @@ typedef enum { ArgGSharedVtOnStack, /* Variable sized gsharedvt argument passed/returned by addr */ ArgGsharedvtVariableInReg, + ArgSwiftError, ArgNone /* only in pair_storage */ } ArgStorage; diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 855315d9a0f437..d99a976415e822 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1857,6 +1857,29 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) add_param (cinfo, &cinfo->sig_cookie, mono_get_int_type (), FALSE); } +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { + MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); + if (klass) { + if (klass == swift_self && sig->pinvoke) { + cinfo->gr--; + add_param (cinfo, ainfo, sig->params [pindex], FALSE); + ainfo->reg = ARMREG_R20; + continue; + } else if (klass == swift_error) { + if (sig->pinvoke) + ainfo->reg = ARMREG_R21; + else + add_param (cinfo, ainfo, sig->params [pindex], FALSE); + ainfo->storage = ArgSwiftError; + continue; + } + } + } +#endif + add_param (cinfo, ainfo, sig->params [pindex], FALSE); if (ainfo->storage == ArgVtypeByRef) { /* Pass the argument address in the next register */ @@ -1915,6 +1938,8 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) return *(gpointer*)(ccontext->stack + ainfo->offset); case ArgVtypeByRef: return (gpointer) ccontext->gregs [ainfo->reg]; + case ArgSwiftError: + return &ccontext->gregs [PARAM_REGS + 2]; default: g_error ("Arg storage type not yet supported"); } @@ -2019,7 +2044,6 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M if (klass == swift_self) { storage = &ccontext->gregs [PARAM_REGS + 1]; } else if (klass == swift_error) { - storage = &ccontext->gregs [PARAM_REGS + 2]; *(gpointer*)storage = 0; continue; } @@ -2598,8 +2622,9 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* r28 is reserved for cfg->arch.args_reg */ /* r27 is reserved for the imt argument */ for (i = ARMREG_R19; i <= ARMREG_R26; ++i) { - if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && (i == ARMREG_R20 || i == ARMREG_R21))) - regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); + if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && i == ARMREG_R21)) + + regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); } return regs; @@ -2705,12 +2730,12 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->used_int_regs |= 1 << ARMREG_R28; } +#ifdef MONO_ARCH_HAVE_SWIFTCALL if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - g_assert (!(cfg->used_int_regs & (1 << ARMREG_R20))); - cfg->used_int_regs |= 1 << ARMREG_R20; g_assert (!(cfg->used_int_regs & (1 << ARMREG_R21))); cfg->used_int_regs |= 1 << ARMREG_R21; } +#endif if (cfg->method->save_lmf) { /* The LMF var is allocated normally */ @@ -2857,6 +2882,21 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->inst_left = vtaddr; break; } + case ArgSwiftError: { + MonoInst *ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); + ins->flags |= MONO_INST_VOLATILE; + size = 8; + align = 8; + offset += align - 1; + offset &= ~(align - 1); + ins->opcode = OP_REGOFFSET; + ins->inst_basereg = cfg->frame_reg; + ins->inst_offset = offset; + offset += size; + + cfg->arch.swift_error_var = ins; + break; + } default: g_assert_not_reached (); break; @@ -3153,30 +3193,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) emit_sig_cookie (cfg, call, cinfo); } -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_self) { - guint32 align; - MonoType *t = mini_get_underlying_type (sig->params [i]); - int size = mini_type_stack_size_full (t, &align, cinfo->pinvoke); - guint32 align_size = ALIGN_TO (size, 8); - - ainfo->storage = ArgVtypeInIRegs; - ainfo->reg = ARMREG_R20; - ainfo->nregs = align_size / 8; - ainfo->size = size; - } else if (klass == swift_error) { - cfg->arch.swift_error_var = arg; - MONO_EMIT_NEW_ICONST (cfg, ARMREG_R21, 0); - } - } - } -#endif - switch (ainfo->storage) { case ArgInIReg: case ArgInFReg: @@ -3230,6 +3246,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) MONO_ADD_INS (cfg->cbb, ins); break; } + case ArgSwiftError: { + MONO_EMIT_NEW_I8CONST (cfg, ainfo->reg, 0); + break; + } default: g_assert_not_reached (); break; @@ -3376,16 +3396,6 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) MonoMethodSignature *sig = mono_method_signature_internal (cfg->method); CallInfo *cinfo; -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - if (cfg->arch.swift_error_var) { - MonoInst *arg = cfg->arch.swift_error_var; - MonoInst *store; - EMIT_NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, arg->inst_basereg, arg->inst_offset, ARMREG_R21); - } - } -#endif - if (!cfg->arch.cinfo) cfg->arch.cinfo = get_call_info (cfg->mempool, sig); cinfo = cfg->arch.cinfo; @@ -5920,6 +5930,14 @@ emit_move_args (MonoCompile *cfg, guint8 *code) case ArgInSIMDReg: code = emit_strfpq (code, ainfo->reg, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); break; + case ArgSwiftError: + if (ainfo->offset) { + code = emit_ldrx (code, ARMREG_IP0, cfg->arch.args_reg, ainfo->offset); + code = emit_strx (code, ARMREG_IP0, cfg->arch.swift_error_var->inst_basereg, GTMREG_TO_INT (cfg->arch.swift_error_var->inst_offset)); + } else { + code = emit_strx (code, ainfo->reg, cfg->arch.swift_error_var->inst_basereg, GTMREG_TO_INT (cfg->arch.swift_error_var->inst_offset)); + } + break; default: g_assert_not_reached (); break; @@ -6320,6 +6338,16 @@ mono_arch_emit_epilog (MonoCompile *cfg) break; } +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + if (cfg->arch.swift_error_var) { + MonoInst *ins = cfg->arch.swift_error_var; + code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); + code = emit_strx (code, ARMREG_R21, ARMREG_IP0, 0); + } + } +#endif + /* Destroy frame */ code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, (1 << ARMREG_IP0) | (1 << ARMREG_IP1)); diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index 27ea7788195613..99fbc7d2235e59 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -241,6 +241,7 @@ typedef enum { ArgVtypeByRefOnStack, ArgVtypeOnStack, ArgHFA, + ArgSwiftError, ArgNone } ArgStorage; From f7528f84c072e9bab78e1e92deab54c02c58cf54 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 23 Jan 2024 10:20:58 +0100 Subject: [PATCH 123/137] [mini] Fix formatting and remove unnecessary code --- src/mono/mono/mini/mini-arm64.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index d99a976415e822..5f4e4d58b7d0ce 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2622,8 +2622,6 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* r28 is reserved for cfg->arch.args_reg */ /* r27 is reserved for the imt argument */ for (i = ARMREG_R19; i <= ARMREG_R26; ++i) { - if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && i == ARMREG_R21)) - regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); } @@ -2730,13 +2728,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->used_int_regs |= 1 << ARMREG_R28; } -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - g_assert (!(cfg->used_int_regs & (1 << ARMREG_R21))); - cfg->used_int_regs |= 1 << ARMREG_R21; - } -#endif - if (cfg->method->save_lmf) { /* The LMF var is allocated normally */ } else { @@ -2883,7 +2874,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) break; } case ArgSwiftError: { - MonoInst *ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); + ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); ins->flags |= MONO_INST_VOLATILE; size = 8; align = 8; From 2a1b7c27251d02b1f68ff044edf949704b8a5e60 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 23 Jan 2024 15:42:09 +0100 Subject: [PATCH 124/137] [mini] Resolve feedback and remove unnecessary code --- src/mono/mono/mini/method-to-ir.c | 1 - src/mono/mono/mini/mini-amd64.c | 58 +++++++++++++------------------ src/mono/mono/mini/mini-arm64.c | 48 +++++++++++-------------- 3 files changed, 45 insertions(+), 62 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 0e5326ec8f281d..66a8bb80d7c52e 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7656,7 +7656,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b goto calli_end; } } - /* Some wrappers use calli with ftndesc-es */ if (cfg->llvm_only && !(cfg->method->wrapper_type && cfg->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index ba66de3d031722..38f35edfa8a21b 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1013,24 +1013,22 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_self && sig->pinvoke) { - guint32 old_gr = gr; - if (gr >= PARAM_REGS) - gr--; - add_valuetype (sig, ainfo, ptype, FALSE, &gr, &fr, &stack_size); - ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); - if (old_gr < PARAM_REGS) - gr--; - continue; - } else if (klass == swift_error) { - if (sig->pinvoke) - ainfo->reg = GINT32_TO_UINT8 (AMD64_R12); - else - add_general (&gr, &stack_size, ainfo); - ainfo->storage = ArgSwiftError; - continue; - } + if (klass == swift_self && sig->pinvoke) { + guint32 old_gr = gr; + if (gr >= PARAM_REGS) + gr--; + add_valuetype (sig, ainfo, ptype, FALSE, &gr, &fr, &stack_size); + ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); + if (old_gr < PARAM_REGS) + gr--; + continue; + } else if (klass == swift_error) { + if (sig->pinvoke) + ainfo->reg = GINT32_TO_UINT8 (AMD64_R12); + else + add_general (&gr, &stack_size, ainfo); + ainfo->storage = ArgSwiftError; + continue; } } #endif @@ -1283,13 +1281,11 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_self) { - storage = &ccontext->gregs [AMD64_R13]; - } else if (klass == swift_error) { - *(gpointer*)storage = 0; - continue; - } + if (klass == swift_self) { + storage = &ccontext->gregs [AMD64_R13]; + } else if (klass == swift_error) { + *(gpointer*)storage = 0; + continue; } } #endif @@ -8404,15 +8400,11 @@ mono_arch_emit_epilog (MonoCompile *cfg) /* Mark the start of the epilog */ mono_emit_unwind_op_mark_loc (cfg, code, 0); -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - if (cfg->arch.swift_error_var && (cfg->arch.swift_error_var->flags & MONO_INST_IS_DEAD)) { - MonoInst *ins = cfg->arch.swift_error_var; - amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); - amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); - } + if (cfg->arch.swift_error_var && (cfg->arch.swift_error_var->flags & MONO_INST_IS_DEAD)) { + MonoInst *ins = cfg->arch.swift_error_var; + amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); } -#endif /* Save the uwind state which is needed by the out-of-line code */ mono_emit_unwind_op_remember_state (cfg, code); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 5f4e4d58b7d0ce..9a1867d465ed1e 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1862,20 +1862,18 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); - if (klass) { - if (klass == swift_self && sig->pinvoke) { - cinfo->gr--; + if (klass == swift_self && sig->pinvoke) { + cinfo->gr--; + add_param (cinfo, ainfo, sig->params [pindex], FALSE); + ainfo->reg = ARMREG_R20; + continue; + } else if (klass == swift_error) { + if (sig->pinvoke) + ainfo->reg = ARMREG_R21; + else add_param (cinfo, ainfo, sig->params [pindex], FALSE); - ainfo->reg = ARMREG_R20; - continue; - } else if (klass == swift_error) { - if (sig->pinvoke) - ainfo->reg = ARMREG_R21; - else - add_param (cinfo, ainfo, sig->params [pindex], FALSE); - ainfo->storage = ArgSwiftError; - continue; - } + ainfo->storage = ArgSwiftError; + continue; } } #endif @@ -2040,13 +2038,11 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass) { - if (klass == swift_self) { - storage = &ccontext->gregs [PARAM_REGS + 1]; - } else if (klass == swift_error) { - *(gpointer*)storage = 0; - continue; - } + if (klass == swift_self) { + storage = &ccontext->gregs [PARAM_REGS + 1]; + } else if (klass == swift_error) { + *(gpointer*)storage = 0; + continue; } } #endif @@ -6329,15 +6325,11 @@ mono_arch_emit_epilog (MonoCompile *cfg) break; } -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - if (cfg->arch.swift_error_var) { - MonoInst *ins = cfg->arch.swift_error_var; - code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); - code = emit_strx (code, ARMREG_R21, ARMREG_IP0, 0); - } + if (cfg->arch.swift_error_var) { + MonoInst *ins = cfg->arch.swift_error_var; + code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); + code = emit_strx (code, ARMREG_R21, ARMREG_IP0, 0); } -#endif /* Destroy frame */ code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, (1 << ARMREG_IP0) | (1 << ARMREG_IP1)); From cdaff6ca9fa7accb6f3a61ce89dfb72c41304b51 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 23 Jan 2024 15:58:07 +0100 Subject: [PATCH 125/137] [mini] Align arm64 and amd64 implementation to use the existing arg inst for SwiftError --- src/mono/mono/mini/mini-amd64.c | 19 ++++++++----------- src/mono/mono/mini/mini-arm64.c | 1 - 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 38f35edfa8a21b..d0a49574aca9f6 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1997,8 +1997,14 @@ mono_arch_allocate_vars (MonoCompile *cfg) break; } case ArgSwiftError: { + ins->flags |= MONO_INST_VOLATILE; ins->flags &= ~MONO_INST_IS_DEAD; - cfg->arch.swift_error_var->flags |= MONO_INST_IS_DEAD; + ins->opcode = OP_REGOFFSET; + ins->inst_basereg = cfg->frame_reg; + ins->inst_offset = ainfo->offset + ARGS_OFFSET; + offset += sizeof (target_mgreg_t);; + + cfg->arch.swift_error_var = ins; } break; default: @@ -2073,15 +2079,6 @@ mono_arch_create_vars (MonoCompile *cfg) if (cfg->method->save_lmf) { cfg->lmf_ir = TRUE; } - -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoInst *ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); - ins->flags |= MONO_INST_VOLATILE; - cfg->arch.swift_error_var = ins; - } -#endif - } static void @@ -8400,7 +8397,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) /* Mark the start of the epilog */ mono_emit_unwind_op_mark_loc (cfg, code, 0); - if (cfg->arch.swift_error_var && (cfg->arch.swift_error_var->flags & MONO_INST_IS_DEAD)) { + if (cfg->arch.swift_error_var) { MonoInst *ins = cfg->arch.swift_error_var; amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 9a1867d465ed1e..8bc5daf6835e02 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2870,7 +2870,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) break; } case ArgSwiftError: { - ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); ins->flags |= MONO_INST_VOLATILE; size = 8; align = 8; From 1af3d21bfd629c2ef9304f3204e2bc1f0822d839 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 23 Jan 2024 17:50:27 +0100 Subject: [PATCH 126/137] [mini] Add swift_error_index to the CallInfo to mark the arg ins as volatile --- src/mono/mono/mini/mini-amd64.c | 7 +++++-- src/mono/mono/mini/mini-amd64.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index d0a49574aca9f6..d180c2f7941afa 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -874,6 +874,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->nargs = n; cinfo->gsharedvt = mini_is_gsharedvt_variable_signature (sig); + cinfo->swift_error_index = -1; gr = 0; fr = 0; @@ -1028,6 +1029,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) else add_general (&gr, &stack_size, ainfo); ainfo->storage = ArgSwiftError; + cinfo->swift_error_index = i; continue; } } @@ -1997,8 +1999,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) break; } case ArgSwiftError: { - ins->flags |= MONO_INST_VOLATILE; - ins->flags &= ~MONO_INST_IS_DEAD; ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; ins->inst_offset = ainfo->offset + ARGS_OFFSET; @@ -2079,6 +2079,9 @@ mono_arch_create_vars (MonoCompile *cfg) if (cfg->method->save_lmf) { cfg->lmf_ir = TRUE; } + + if (cinfo->swift_error_index >= 0) + cfg->args [cinfo->swift_error_index]->flags |= MONO_INST_VOLATILE; } static void diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index bb49e9a50676e5..57a60a930b6b4e 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -330,6 +330,7 @@ struct CallInfo { guint32 stack_usage; guint32 reg_usage; guint32 freg_usage; + gint32 swift_error_index; gboolean need_stack_align; gboolean gsharedvt; /* The index of the vret arg in the argument list */ From d2434626cc189f46ea896f8312fdbf58e23ab366 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 24 Jan 2024 12:25:45 +0100 Subject: [PATCH 127/137] [mini] Move selferror store ins to emit_move_return_value --- src/mono/mono/mini/mini-amd64.c | 22 +++++++--------------- src/mono/mono/mini/mini-arm64.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index d180c2f7941afa..2bc28977c62a0a 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1687,9 +1687,8 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* We use the callee saved registers for global allocation */ regs = g_list_prepend (regs, (gpointer)AMD64_RBX); - if (!mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { + if (!mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) regs = g_list_prepend (regs, (gpointer)AMD64_R12); - } regs = g_list_prepend (regs, (gpointer)AMD64_R13); regs = g_list_prepend (regs, (gpointer)AMD64_R14); regs = g_list_prepend (regs, (gpointer)AMD64_R15); @@ -1841,13 +1840,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->arch.saved_iregs |= iregs_to_save; } -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL)) { - cfg->arch.saved_iregs |= (size_t)(1 << AMD64_R12); - cfg->used_int_regs |= (size_t)(1 << AMD64_R12); - } -#endif - if (cfg->arch.omit_fp) cfg->arch.reg_save_area_offset = offset; /* Reserve space for callee saved registers */ @@ -4288,6 +4280,12 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code) CallInfo *cinfo; guint32 quad; + if (cfg->arch.swift_error_var) { + MonoInst *ins = cfg->arch.swift_error_var; + amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); + amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); + } + /* Move return value to the target register */ /* FIXME: do this in the local reg allocator */ switch (ins->opcode) { @@ -8400,12 +8398,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) /* Mark the start of the epilog */ mono_emit_unwind_op_mark_loc (cfg, code, 0); - if (cfg->arch.swift_error_var) { - MonoInst *ins = cfg->arch.swift_error_var; - amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); - amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); - } - /* Save the uwind state which is needed by the out-of-line code */ mono_emit_unwind_op_remember_state (cfg, code); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 8bc5daf6835e02..5006f55c283ef7 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2618,7 +2618,8 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* r28 is reserved for cfg->arch.args_reg */ /* r27 is reserved for the imt argument */ for (i = ARMREG_R19; i <= ARMREG_R26; ++i) { - regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); + if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && i == ARMREG_R21)) + regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); } return regs; @@ -3723,6 +3724,12 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) CallInfo *cinfo; MonoCallInst *call; + if (cfg->arch.swift_error_var) { + MonoInst *ins = cfg->arch.swift_error_var; + code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); + code = emit_strx (code, ARMREG_R21, ARMREG_IP0, 0); + } + call = (MonoCallInst*)ins; cinfo = call->call_info; g_assert (cinfo); @@ -6324,12 +6331,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) break; } - if (cfg->arch.swift_error_var) { - MonoInst *ins = cfg->arch.swift_error_var; - code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); - code = emit_strx (code, ARMREG_R21, ARMREG_IP0, 0); - } - /* Destroy frame */ code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, (1 << ARMREG_IP0) | (1 << ARMREG_IP1)); From 6f36c21bd5da07d7f6fe1b937ef15afdb826332f Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 24 Jan 2024 17:20:04 +0100 Subject: [PATCH 128/137] Fix lint --- src/mono/mono/mini/mini-amd64.c | 3 +-- src/mono/mono/mini/mini-arm64.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 2bc28977c62a0a..703cf734797f9b 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -4281,8 +4281,7 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code) guint32 quad; if (cfg->arch.swift_error_var) { - MonoInst *ins = cfg->arch.swift_error_var; - amd64_mov_reg_membase (code, AMD64_R11, ins->inst_basereg, ins->inst_offset, sizeof (target_mgreg_t)); + amd64_mov_reg_membase (code, AMD64_R11, cfg->arch.swift_error_var->inst_basereg, cfg->arch.swift_error_var->inst_offset, sizeof (target_mgreg_t)); amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_R12, sizeof (target_mgreg_t)); } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 5006f55c283ef7..8e7ccfebd67659 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -3725,8 +3725,7 @@ emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins) MonoCallInst *call; if (cfg->arch.swift_error_var) { - MonoInst *ins = cfg->arch.swift_error_var; - code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, GTMREG_TO_INT (ins->inst_offset)); + code = emit_ldrx (code, ARMREG_IP0, cfg->arch.swift_error_var->inst_basereg, GTMREG_TO_INT (cfg->arch.swift_error_var->inst_offset)); code = emit_strx (code, ARMREG_R21, ARMREG_IP0, 0); } From a60f39251813b8241aa7ff16029fb58d9a0aef81 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 25 Jan 2024 15:35:09 +0100 Subject: [PATCH 129/137] [mini] Preserve Swift error register value during the P/Invoke call The Swift error argument is not present in the P/Invoke signature, but the context register value can be changed by Swift. Therefore, it must be preserved during the P/Invoke call by updating the used_int_regs. --- src/mono/mono/mini/mini-amd64.c | 1 + src/mono/mono/mini/mini-arm64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 703cf734797f9b..b119e546be1064 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1997,6 +1997,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset += sizeof (target_mgreg_t);; cfg->arch.swift_error_var = ins; + cfg->used_int_regs |= (size_t)(1 << AMD64_R12); } break; default: diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 8e7ccfebd67659..b1c28866529ad0 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -2882,6 +2882,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset += size; cfg->arch.swift_error_var = ins; + cfg->used_int_regs |= 1 << ARMREG_R21; break; } default: From 2b2b75e926fe560dfc61ee3bbc49cac6a4d5a04e Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 26 Jan 2024 12:20:27 +0100 Subject: [PATCH 130/137] [mono] Allow SwiftError*, ref SwiftError, and function pointers in CallConvSwift signature --- src/mono/mono/metadata/marshal.c | 7 ++++--- src/mono/mono/mini/mini-amd64.c | 9 ++++++--- src/mono/mono/mini/mini-arm64.c | 9 ++++++--- .../SwiftInvalidCallConv/SwiftInvalidCallConv.cs | 13 ------------- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 541baa7ff3524d..0f84b3818b7df2 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3623,8 +3623,9 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, } if (mono_method_signature_has_ext_callconv (csig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_error = mono_class_try_get_swift_error_class (); MonoClass *swift_self = mono_class_try_get_swift_self_class (); + MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); int swift_error_args = 0, swift_self_args = 0; for (int i = 0; i < method->signature->param_count; ++i) { MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); @@ -3633,11 +3634,11 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, swift_error_args = swift_self_args = 0; mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftError argument must be passed by reference."); break; - } else if (param_klass == swift_error) { + } else if (param_klass == swift_error || param_klass == swift_error_ptr) { swift_error_args++; } else if (param_klass == swift_self) { swift_self_args++; - } else if (!m_class_is_enumtype (param_klass) && !m_class_is_primitive (param_klass)) { + } else if (!m_class_is_enumtype (param_klass) && !m_class_is_primitive (param_klass) && m_class_get_this_arg (param_klass)->type != MONO_TYPE_FNPTR) { swift_error_args = swift_self_args = 0; mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Passing non-primitive value types to a P/Invoke with the Swift calling convention is unsupported."); break; diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 0f6fd45bf04453..98e2f4a8f9eaf7 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1013,6 +1013,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass == swift_self && sig->pinvoke) { guint32 old_gr = gr; @@ -1023,7 +1024,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (old_gr < PARAM_REGS) gr--; continue; - } else if (klass == swift_error) { + } else if (klass == swift_error || klass == swift_error_ptr) { if (sig->pinvoke) ainfo->reg = GINT32_TO_UINT8 (AMD64_R12); else @@ -1282,10 +1283,11 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass == swift_self) { storage = &ccontext->gregs [AMD64_R13]; - } else if (klass == swift_error) { + } else if (klass == swift_error || klass == swift_error_ptr) { *(gpointer*)storage = 0; continue; } @@ -1413,9 +1415,10 @@ gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, int *arg_index) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass && klass == swift_error) { + if (klass && (klass == swift_error || klass == swift_error_ptr)) { *arg_index = i; return &ccontext->gregs [AMD64_R12]; } diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index b1c28866529ad0..ced5967555c621 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1861,13 +1861,14 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); if (klass == swift_self && sig->pinvoke) { cinfo->gr--; add_param (cinfo, ainfo, sig->params [pindex], FALSE); ainfo->reg = ARMREG_R20; continue; - } else if (klass == swift_error) { + } else if (klass == swift_error || klass == swift_error_ptr) { if (sig->pinvoke) ainfo->reg = ARMREG_R21; else @@ -2037,10 +2038,11 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { MonoClass *swift_self = mono_class_try_get_swift_self_class (); MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass == swift_self) { storage = &ccontext->gregs [PARAM_REGS + 1]; - } else if (klass == swift_error) { + } else if (klass == swift_error || klass == swift_error_ptr) { *(gpointer*)storage = 0; continue; } @@ -2155,9 +2157,10 @@ gpointer mono_arch_get_swift_error (CallContext *ccontext, MonoMethodSignature *sig, int *arg_index) { MonoClass *swift_error = mono_class_try_get_swift_error_class (); + MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); for (guint i = 0; i < sig->param_count + sig->hasthis; i++) { MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass && klass == swift_error) { + if (klass && (klass == swift_error || klass == swift_error_ptr)) { *arg_index = i; return &ccontext->gregs [PARAM_REGS + 2]; } diff --git a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs index faec2bdc35a4b9..41c98e3791f91c 100644 --- a/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs +++ b/src/tests/Interop/Swift/SwiftInvalidCallConv/SwiftInvalidCallConv.cs @@ -32,10 +32,6 @@ public class StringClass [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] public static extern void FuncWithSwiftErrorAsArg(SwiftError error1); - [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] - public unsafe static extern void FuncWithSwiftErrorAsUnsafeArg(SwiftError* error1); - [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] [DllImport(SwiftLib, EntryPoint = "$s20SwiftInvalidCallConv10simpleFuncyyF")] public static extern void FuncWithNonPrimitiveArg(StringClass arg1); @@ -73,15 +69,6 @@ public static void TestFuncWithSwiftErrorAsArg() Assert.Throws(() => FuncWithSwiftErrorAsArg(error)); } - [Fact] - public unsafe static void TestFuncWithSwiftErrorAsUnsafeArg() - { - // Invalid due to SwiftError not passed as an unsafe pointer. - SwiftError error = new SwiftError(); - SwiftError *errorPtr = &error; - Assert.Throws(() => FuncWithSwiftErrorAsUnsafeArg(errorPtr)); - } - [Fact] public static void TestFuncWithNonPrimitiveArg() { From 6e54b5bad3a1c0b14e311d26776a3903a7d3f564 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 30 Jan 2024 11:43:56 +0100 Subject: [PATCH 131/137] [mono] Remove unused code and fix lint --- src/mono/mono/mini/mini-amd64.c | 4 +++- src/mono/mono/mini/mini-amd64.h | 7 +++---- src/mono/mono/mini/mini-codegen.c | 3 --- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 98e2f4a8f9eaf7..1d63828689814f 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -54,6 +54,7 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") + #define IS_IMM32(val) ((((guint64)val) >> 32) == 0) #define IS_REX(inst) (((inst) >= 0x40) && ((inst) <= 0x4f)) @@ -1997,7 +1998,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; ins->inst_offset = ainfo->offset + ARGS_OFFSET; - offset += sizeof (target_mgreg_t);; + offset += sizeof (target_mgreg_t); cfg->arch.swift_error_var = ins; cfg->used_int_regs |= (size_t)(1 << AMD64_R12); @@ -2340,6 +2341,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) ainfo = cinfo->args + i; in = call->args [i]; + if (sig->hasthis && i == 0) t = mono_get_object_type (); else diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h index 57a60a930b6b4e..0dda406f95b8b3 100644 --- a/src/mono/mono/mini/mini-amd64.h +++ b/src/mono/mono/mini/mini-amd64.h @@ -231,16 +231,12 @@ static const AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 }; #define FLOAT_PARAM_REGS G_N_ELEMENTS(float_param_regs) #define RETURN_REGS G_N_ELEMENTS(return_regs) #define FLOAT_RETURN_REGS G_N_ELEMENTS(float_return_regs) -#define CTX_REGS 2 -#define CTX_REGS_OFFSET AMD64_R12 #else #define PARAM_REGS 6 #define FLOAT_PARAM_REGS 8 #define RETURN_REGS 2 #define FLOAT_RETURN_REGS 2 -#define CTX_REGS 2 -#define CTX_REGS_OFFSET AMD64_R12 static const AMD64_Reg_No param_regs [] = {AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9}; @@ -252,6 +248,9 @@ static const AMD64_XMM_Reg_No float_param_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD6 static const AMD64_Reg_No return_regs [] = {AMD64_RAX, AMD64_RDX}; #endif +#define CTX_REGS 2 +#define CTX_REGS_OFFSET AMD64_R12 + typedef struct { /* Method address to call */ gpointer addr; diff --git a/src/mono/mono/mini/mini-codegen.c b/src/mono/mono/mini/mini-codegen.c index 21b03a98ee7e08..efcf9c2564ac66 100644 --- a/src/mono/mono/mini/mini-codegen.c +++ b/src/mono/mono/mini/mini-codegen.c @@ -1095,9 +1095,6 @@ assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, int bank) #if !defined(TARGET_ARM) && !defined(TARGET_ARM64) /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */ /* On arm64, rgctx_reg is a global hreg, and it is used to pass an argument */ -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && (hreg == AMD64_R12 || hreg == AMD64_R13))) -#endif g_assert (! is_global_ireg (hreg)); #endif From 426802eae2d0a3ed8dc0b56a161c863bed88e9f4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 30 Jan 2024 13:16:23 +0100 Subject: [PATCH 132/137] [mono] Avoid g_assert for Swift ctx regs --- src/mono/mono/mini/mini-codegen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mono/mono/mini/mini-codegen.c b/src/mono/mono/mini/mini-codegen.c index efcf9c2564ac66..21b03a98ee7e08 100644 --- a/src/mono/mono/mini/mini-codegen.c +++ b/src/mono/mono/mini/mini-codegen.c @@ -1095,6 +1095,9 @@ assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, int bank) #if !defined(TARGET_ARM) && !defined(TARGET_ARM64) /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */ /* On arm64, rgctx_reg is a global hreg, and it is used to pass an argument */ +#ifdef MONO_ARCH_HAVE_SWIFTCALL + if (!(mono_method_signature_has_ext_callconv (cfg->method->signature, MONO_EXT_CALLCONV_SWIFTCALL) && (hreg == AMD64_R12 || hreg == AMD64_R13))) +#endif g_assert (! is_global_ireg (hreg)); #endif From 4e097850cd59ede89f23b2379a4ab41cf5f5b887 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 31 Jan 2024 12:18:20 +0100 Subject: [PATCH 133/137] Update src/mono/mono/metadata/marshal.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aleksey Kliger (λgeek) --- src/mono/mono/metadata/marshal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 0f84b3818b7df2..5e9076b1795386 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3630,7 +3630,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, for (int i = 0; i < method->signature->param_count; ++i) { MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]); if (param_klass) { - if (param_klass == swift_error && method->signature->params [i]->byref__ == 0) { + if (param_klass == swift_error && !m_type_is_byref (method->signature->params [i])) { swift_error_args = swift_self_args = 0; mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftError argument must be passed by reference."); break; From 89d211c3f824d2ec532dfd02e0e585039b4fdf23 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 31 Jan 2024 12:18:55 +0100 Subject: [PATCH 134/137] Update src/mono/mono/metadata/marshal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aleksey Kliger (λgeek) --- src/mono/mono/metadata/marshal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index 7f8e3876b3f047..91758b6ecf4313 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include From d450fb1b84f7204e40e7d375301f38d1e78fc68e Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 31 Jan 2024 19:45:23 +0100 Subject: [PATCH 135/137] Update Swift runtime tests to use blittable types --- src/mono/mono/metadata/marshal.c | 5 ++++- src/mono/mono/mini/mini.c | 4 ---- .../SwiftErrorHandling/SwiftErrorHandling.cs | 16 ++++++++-------- .../SwiftErrorHandling/SwiftErrorHandling.swift | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 5e9076b1795386..473f06fc9cac57 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -127,6 +127,9 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "Sys static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute") static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callconv_attribute, "System.Runtime.InteropServices", "UnmanagedCallConvAttribute") +GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") +GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") + static gboolean type_is_blittable (MonoType *type); static IlgenCallbacksToMono ilgenCallbacksToMono = { @@ -3638,7 +3641,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, swift_error_args++; } else if (param_klass == swift_self) { swift_self_args++; - } else if (!m_class_is_enumtype (param_klass) && !m_class_is_primitive (param_klass) && m_class_get_this_arg (param_klass)->type != MONO_TYPE_FNPTR) { + } else if (!m_class_is_blittable (param_klass) && m_class_get_this_arg (param_klass)->type != MONO_TYPE_FNPTR) { swift_error_args = swift_self_args = 0; mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Passing non-primitive value types to a P/Invoke with the Swift calling convention is unsupported."); break; diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index c9f97f83080418..b6935d312c6ee8 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -92,10 +92,6 @@ static gint64 discarded_jit_time; #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex) static mono_mutex_t jit_mutex; -// used for Swift interop -GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError") -GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf") - #ifndef DISABLE_JIT static guint32 jinfo_try_holes_size; static MonoBackend *current_backend; diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs index ac724b3c2dd731..67a398d357e113 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.cs @@ -16,12 +16,12 @@ public class ErrorHandlingTests public static extern void SetErrorMessage(string message, int length); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] - public static extern nint conditionallyThrowError(bool willThrow, ref SwiftError error); + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0s5Int32VAE_tKF")] + public static extern nint conditionallyThrowError(int willThrow, ref SwiftError error); [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })] - [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0SiSb_tKF")] - public static extern nint conditionallyThrowErrorOnStack(bool willThrow, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, int dummy8, int dummy9, ref SwiftError error); + [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling018conditionallyThrowB004willE0s5Int32VAE_tKF")] + public static extern nint conditionallyThrowErrorOnStack(int willThrow, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, int dummy8, int dummy9, ref SwiftError error); [DllImport(SwiftLib, EntryPoint = "$s18SwiftErrorHandling05getMyB7Message4from13messageLengthSPys6UInt16VGSgs0B0_p_s5Int32VztF")] public unsafe static extern void* GetErrorMessage(void* handle, out int length); @@ -35,7 +35,7 @@ public unsafe static void TestSwiftErrorThrown() SwiftError error = new SwiftError(); // This will throw an error - conditionallyThrowError(true, ref error); + conditionallyThrowError(1, ref error); Assert.True(error.Value != null, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); @@ -51,7 +51,7 @@ public unsafe static void TestSwiftErrorNotThrown() SwiftError error = new SwiftError(); // This will not throw an error - int result = (int)conditionallyThrowError(false, ref error); + int result = (int)conditionallyThrowError(0, ref error); Assert.True(error.Value == null, "No Swift error was expected to be thrown."); Assert.True(result == 42, "The result from Swift does not match the expected value."); @@ -67,7 +67,7 @@ public unsafe static void TestSwiftErrorOnStackThrown() int i = 0; // This will throw an error - conditionallyThrowErrorOnStack(true, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, ref error); + conditionallyThrowErrorOnStack(1, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, ref error); Assert.True(error.Value != null, "A Swift error was expected to be thrown."); string errorMessage = GetErrorMessageFromSwift(error); @@ -84,7 +84,7 @@ public unsafe static void TestSwiftErrorOnStackNotThrown() int i = 0; // This will not throw an error - int result = (int)conditionallyThrowErrorOnStack(false, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, ref error); + int result = (int)conditionallyThrowErrorOnStack(0, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, ref error); Assert.True(error.Value == null, "No Swift error was expected to be thrown."); Assert.True(result == 42, "The result from Swift does not match the expected value."); diff --git a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift index 2cdbae92783066..20022c0dba3e28 100644 --- a/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift +++ b/src/tests/Interop/Swift/SwiftErrorHandling/SwiftErrorHandling.swift @@ -13,8 +13,8 @@ public func setMyErrorMessage(message: UnsafePointer, length: Int32) { errorMessage = NSString(characters: message, length: Int(length)) } -public func conditionallyThrowError(willThrow: Bool) throws -> Int { - if willThrow { +public func conditionallyThrowError(willThrow: Int32) throws -> Int32 { + if willThrow != 0 { throw MyError.runtimeError(message: errorMessage) } else { return 42 From 1a39a88224966047e4a137c42071aacd74619238 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Fri, 2 Feb 2024 11:26:20 +0100 Subject: [PATCH 136/137] [mono] Simplify register allocation and interp native call context --- src/mono/mono/mini/mini-amd64.c | 30 +++++++++++------------------- src/mono/mono/mini/mini-arm64.c | 31 +++++++++++++++---------------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 1d63828689814f..5929031dc24553 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1017,13 +1017,15 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (klass == swift_self && sig->pinvoke) { - guint32 old_gr = gr; - if (gr >= PARAM_REGS) - gr--; - add_valuetype (sig, ainfo, ptype, FALSE, &gr, &fr, &stack_size); + guint32 size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); + g_assert (size == 8); + + ainfo->storage = ArgValuetypeInReg; + ainfo->pair_storage [0] = ArgInIReg; + ainfo->pair_storage [1] = ArgNone; + ainfo->nregs = 1; ainfo->pair_regs [0] = GINT32_TO_UINT8 (AMD64_R13); - if (old_gr < PARAM_REGS) - gr--; + ainfo->pair_size [0] = size; continue; } else if (klass == swift_error || klass == swift_error_ptr) { if (sig->pinvoke) @@ -1280,20 +1282,10 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M else storage = arg_get_storage (ccontext, ainfo); -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass == swift_self) { - storage = &ccontext->gregs [AMD64_R13]; - } else if (klass == swift_error || klass == swift_error_ptr) { - *(gpointer*)storage = 0; - continue; - } + if (ainfo->storage == ArgSwiftError) { + *(gpointer*)storage = 0; + continue; } -#endif interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage); if (temp_size) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index ced5967555c621..baf55b3774d8a5 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1864,9 +1864,15 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); MonoClass *klass = mono_class_from_mono_type_internal (sig->params [pindex]); if (klass == swift_self && sig->pinvoke) { - cinfo->gr--; - add_param (cinfo, ainfo, sig->params [pindex], FALSE); + guint32 align; + MonoType *ptype = mini_get_underlying_type (sig->params [pindex]); + int size = mini_type_stack_size_full (ptype, &align, cinfo->pinvoke); + g_assert (size == 8); + + ainfo->storage = ArgVtypeInIRegs; ainfo->reg = ARMREG_R20; + ainfo->nregs = 1; + ainfo->size = size; continue; } else if (klass == swift_error || klass == swift_error_ptr) { if (sig->pinvoke) @@ -1923,7 +1929,10 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) switch (ainfo->storage) { case ArgVtypeInIRegs: case ArgInIReg: - return &ccontext->gregs [ainfo->reg]; + if (ainfo->reg == ARMREG_R20) + return &ccontext->gregs [PARAM_REGS + 1]; + else + return &ccontext->gregs [ainfo->reg]; case ArgInFReg: case ArgInFRegR4: case ArgHFA: @@ -2034,20 +2043,10 @@ mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, M else storage = arg_get_storage (ccontext, ainfo); -#ifdef MONO_ARCH_HAVE_SWIFTCALL - if (mono_method_signature_has_ext_callconv (sig, MONO_EXT_CALLCONV_SWIFTCALL)) { - MonoClass *swift_self = mono_class_try_get_swift_self_class (); - MonoClass *swift_error = mono_class_try_get_swift_error_class (); - MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error)); - MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (klass == swift_self) { - storage = &ccontext->gregs [PARAM_REGS + 1]; - } else if (klass == swift_error || klass == swift_error_ptr) { - *(gpointer*)storage = 0; - continue; - } + if (ainfo->storage == ArgSwiftError) { + *(gpointer*)storage = 0; + continue; } -#endif interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage); if (temp_size) From 1405a98cbd79e2cb989574fcc97f4e8fd3479368 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 5 Feb 2024 13:38:11 +0000 Subject: [PATCH 137/137] align ArgSwiftError on x64 --- src/mono/mono/mini/mini-amd64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index e6d1d34dfef597..dd7a930c064cf5 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1992,6 +1992,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; ins->inst_offset = ainfo->offset + ARGS_OFFSET; + offset = ALIGN_TO (offset, sizeof (target_mgreg_t)); offset += sizeof (target_mgreg_t); cfg->arch.swift_error_var = ins; @@ -2002,7 +2003,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) NOT_IMPLEMENTED; } - if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg) && (ainfo->storage != ArgValuetypeAddrOnStack) && (ainfo->storage != ArgGSharedVtOnStack)) { + if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg) && (ainfo->storage != ArgValuetypeAddrOnStack) && (ainfo->storage != ArgGSharedVtOnStack) && (ainfo->storage != ArgSwiftError)) { ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; /* These arguments are saved to the stack in the prolog */