From 2f0883ab246ae2f2563a741e011952d0ba13b7ad Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 4 Dec 2023 15:39:45 -0800 Subject: [PATCH] [embedded] Add Set to the embedded stdlib --- stdlib/public/core/BridgeStorage.swift | 27 ++++++++++++++++-- stdlib/public/core/Builtin.swift | 2 ++ stdlib/public/core/CMakeLists.txt | 20 ++++++------- stdlib/public/core/EmbeddedRuntime.swift | 7 +++++ stdlib/public/core/HashTable.swift | 2 +- stdlib/public/core/Hasher.swift | 10 +++++++ stdlib/public/core/NativeSet.swift | 13 +++++++++ stdlib/public/core/Set.swift | 3 ++ stdlib/public/core/SetCasting.swift | 5 ++++ stdlib/public/core/SetStorage.swift | 18 +++++++++++- stdlib/public/core/TemporaryAllocation.swift | 5 ++++ test/embedded/set-runtime.swift | 30 ++++++++++++++++++++ test/embedded/stdlib-array.swift | 30 ++++++++++++++++++++ test/embedded/stdlib-set.swift | 25 ++++++++++++++++ test/embedded/stdlib-types.swift | 1 + 15 files changed, 183 insertions(+), 15 deletions(-) create mode 100644 test/embedded/set-runtime.swift create mode 100644 test/embedded/stdlib-array.swift create mode 100644 test/embedded/stdlib-set.swift diff --git a/stdlib/public/core/BridgeStorage.swift b/stdlib/public/core/BridgeStorage.swift index 05e101959f9..46572ba0314 100644 --- a/stdlib/public/core/BridgeStorage.swift +++ b/stdlib/public/core/BridgeStorage.swift @@ -31,9 +31,15 @@ internal struct _BridgeStorage { // rawValue is passed inout to _isUnique. Although its value // is unchanged, it must appear mutable to the optimizer. +#if !$Embedded @usableFromInline internal var rawValue: Builtin.BridgeObject +#else + @usableFromInline + internal var rawValue: NativeClass +#endif +#if !$Embedded @inlinable @inline(__always) internal init(native: Native, isFlagged flag: Bool) { @@ -46,13 +52,16 @@ internal struct _BridgeStorage { native, flag ? (1 as UInt) << _objectPointerLowSpareBitShift : 0) } +#endif +#if _runtime(_ObjC) @inlinable @inline(__always) internal init(objC: ObjC) { _internalInvariant(_usesNativeSwiftReferenceCounting(NativeClass.self)) rawValue = _makeObjCBridgeObject(objC) } +#endif @inlinable @inline(__always) @@ -65,7 +74,7 @@ internal struct _BridgeStorage { @inlinable @inline(__always) internal init(taggedPayload: UInt) { - rawValue = _bridgeObject(taggingPayload: taggedPayload) + rawValue = Builtin.reinterpretCast(taggedPayload) } #endif @@ -84,9 +93,13 @@ internal struct _BridgeStorage { @inlinable internal var isNative: Bool { @inline(__always) get { + #if !$Embedded let result = Builtin.classifyBridgeObject(rawValue) return !Bool(Builtin.or_Int1(result.isObjCObject, result.isObjCTaggedPointer)) + #else + return true + #endif } } @@ -100,9 +113,13 @@ internal struct _BridgeStorage { @inlinable internal var isUnflaggedNative: Bool { @inline(__always) get { + #if !$Embedded return (_bitPattern(rawValue) & (_bridgeObjectTaggedPointerBits | _objCTaggedPointerBits | _objectPointerIsObjCBit | _BridgeStorage.flagMask)) == 0 + #else + return true + #endif } } @@ -117,7 +134,7 @@ internal struct _BridgeStorage { internal var nativeInstance: Native { @inline(__always) get { _internalInvariant(isNative) - return Builtin.castReferenceFromBridgeObject(rawValue) + return rawValue } } @@ -125,8 +142,10 @@ internal struct _BridgeStorage { internal var unflaggedNativeInstance: Native { @inline(__always) get { _internalInvariant(isNative) + #if !$Embedded _internalInvariant(_nonPointerBits(rawValue) == 0) - return Builtin.reinterpretCast(rawValue) + #endif + return rawValue } } @@ -151,6 +170,7 @@ internal struct _BridgeStorage { Builtin.endCOWMutation(&rawValue) } +#if _runtime(_ObjC) @inlinable internal var objCInstance: ObjC { @inline(__always) get { @@ -158,4 +178,5 @@ internal struct _BridgeStorage { return Builtin.castReferenceFromBridgeObject(rawValue) } } +#endif } diff --git a/stdlib/public/core/Builtin.swift b/stdlib/public/core/Builtin.swift index d45ad6979b2..5634254b859 100644 --- a/stdlib/public/core/Builtin.swift +++ b/stdlib/public/core/Builtin.swift @@ -725,9 +725,11 @@ func _isUnique_native(_ object: inout T) -> Bool { // This could be a bridge object, single payload enum, or plain old // reference. Any case it's non pointer bits must be zero, so // force cast it to BridgeObject and check the spare bits. + #if !$Embedded _internalInvariant( (_bitPattern(Builtin.reinterpretCast(object)) & _objectPointerSpareBits) == 0) + #endif _internalInvariant(_usesNativeSwiftReferenceCounting( type(of: Builtin.reinterpretCast(object) as AnyObject))) return Bool(Builtin.isUnique_native(&object)) diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index eac774930b1..250684af77a 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -43,10 +43,10 @@ split_embedded_sources( EMBEDDED Assert.swift EMBEDDED AssertCommon.swift EMBEDDED BidirectionalCollection.swift - NORMAL Bitset.swift + EMBEDDED Bitset.swift EMBEDDED Bool.swift NORMAL BridgeObjectiveC.swift - NORMAL BridgeStorage.swift + EMBEDDED BridgeStorage.swift NORMAL BridgingBuffer.swift EMBEDDED Builtin.swift EMBEDDED BuiltinMath.swift @@ -89,7 +89,7 @@ split_embedded_sources( # END WORKAROUND EMBEDDED Hasher.swift NORMAL Hashing.swift - NORMAL HashTable.swift + EMBEDDED HashTable.swift EMBEDDED Identifiable.swift EMBEDDED Indices.swift NORMAL InputStream.swift @@ -111,7 +111,7 @@ split_embedded_sources( EMBEDDED Misc.swift EMBEDDED MutableCollection.swift NORMAL NativeDictionary.swift - NORMAL NativeSet.swift + EMBEDDED NativeSet.swift NORMAL NewtypeWrapper.swift NORMAL NFC.swift NORMAL NFD.swift @@ -139,15 +139,15 @@ split_embedded_sources( EMBEDDED SipHash.swift EMBEDDED Sequence.swift EMBEDDED SequenceAlgorithms.swift - NORMAL Set.swift + EMBEDDED Set.swift EMBEDDED SetAlgebra.swift NORMAL SetAnyHashableExtensions.swift NORMAL SetBridging.swift - NORMAL SetBuilder.swift - NORMAL SetCasting.swift - NORMAL SetStorage.swift - NORMAL SetVariant.swift - NORMAL ShadowProtocols.swift + EMBEDDED SetBuilder.swift + EMBEDDED SetCasting.swift + EMBEDDED SetStorage.swift + EMBEDDED SetVariant.swift + EMBEDDED ShadowProtocols.swift NORMAL Shims.swift EMBEDDED Slice.swift NORMAL SmallString.swift diff --git a/stdlib/public/core/EmbeddedRuntime.swift b/stdlib/public/core/EmbeddedRuntime.swift index 726ea5c027c..656375df614 100644 --- a/stdlib/public/core/EmbeddedRuntime.swift +++ b/stdlib/public/core/EmbeddedRuntime.swift @@ -275,3 +275,10 @@ public func swift_deletedMethodError() -> Never { public func swift_willThrow() throws { } +@_silgen_name("arc4random_buf") +public func arc4random_buf(buf: UnsafeMutableRawPointer, nbytes: Int) + +@_silgen_name("swift_stdlib_random") +public func swift_stdlib_random(_ buf: UnsafeMutableRawPointer, _ nbytes: Int) { + arc4random_buf(buf: buf, nbytes: nbytes) +} diff --git a/stdlib/public/core/HashTable.swift b/stdlib/public/core/HashTable.swift index 9534ed57d88..2f361ae7bb6 100644 --- a/stdlib/public/core/HashTable.swift +++ b/stdlib/public/core/HashTable.swift @@ -102,7 +102,7 @@ extension _HashTable { } internal static func hashSeed( - for object: AnyObject, + for object: Builtin.NativeObject, scale: Int8 ) -> Int { // We generate a new hash seed whenever a new hash table is allocated and diff --git a/stdlib/public/core/Hasher.swift b/stdlib/public/core/Hasher.swift index 1704d1acbb2..5b82708bc5c 100644 --- a/stdlib/public/core/Hasher.swift +++ b/stdlib/public/core/Hasher.swift @@ -251,6 +251,16 @@ extension Hasher { } } +#if $Embedded +@usableFromInline +var _swift_stdlib_Hashing_parameters: _SwiftHashingParameters = { + var seed0: UInt64 = 0, seed1: UInt64 = 0 + swift_stdlib_random(&seed0, MemoryLayout.size) + swift_stdlib_random(&seed1, MemoryLayout.size) + return .init(seed0: seed0, seed1: seed1, deterministic: false) +}() +#endif + /// The universal hash function used by `Set` and `Dictionary`. /// /// `Hasher` can be used to map an arbitrary sequence of bytes to an integer diff --git a/stdlib/public/core/NativeSet.swift b/stdlib/public/core/NativeSet.swift index 42d84ff9257..78238c90f57 100644 --- a/stdlib/public/core/NativeSet.swift +++ b/stdlib/public/core/NativeSet.swift @@ -351,6 +351,7 @@ extension _NativeSet: _SetBuffer { // This function has a highly visible name to make it stand out in stack traces. @usableFromInline @inline(never) +@_unavailableInEmbedded internal func ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS( _ elementType: Any.Type ) -> Never { @@ -379,7 +380,11 @@ extension _NativeSet { // Insertions // because we'll need to compare elements in case of hash collisions. let (bucket, found) = find(element, hashValue: hashValue) guard !found else { + #if !$Embedded ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) + #else + fatalError("duplicate elements in a Set") + #endif } hashTable.insert(bucket) uncheckedInitialize(at: bucket, to: element) @@ -418,7 +423,11 @@ extension _NativeSet { // Insertions if rehashed { let (b, f) = find(element) if f { + #if !$Embedded ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) + #else + fatalError("duplicate elements in a Set") + #endif } bucket = b } @@ -437,7 +446,11 @@ extension _NativeSet { // Insertions if rehashed { let (b, f) = find(element) if f != found { + #if !$Embedded ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) + #else + fatalError("duplicate elements in a Set") + #endif } bucket = b } diff --git a/stdlib/public/core/Set.swift b/stdlib/public/core/Set.swift index 953def9f995..694d4e9ee1b 100644 --- a/stdlib/public/core/Set.swift +++ b/stdlib/public/core/Set.swift @@ -448,12 +448,14 @@ extension Set: Hashable { } } +@_unavailableInEmbedded extension Set: _HasCustomAnyHashableRepresentation { public __consuming func _toCustomAnyHashable() -> AnyHashable? { return AnyHashable(_box: _SetAnyHashableBox(self)) } } +@_unavailableInEmbedded internal struct _SetAnyHashableBox: _AnyHashableBox { internal let _value: Set internal let _canonical: Set @@ -1034,6 +1036,7 @@ extension Set: SetAlgebra { } } +@_unavailableInEmbedded extension Set: CustomStringConvertible, CustomDebugStringConvertible { /// A string that represents the contents of the set. public var description: String { diff --git a/stdlib/public/core/SetCasting.swift b/stdlib/public/core/SetCasting.swift index 3a4082c866e..5dcca7adf15 100644 --- a/stdlib/public/core/SetCasting.swift +++ b/stdlib/public/core/SetCasting.swift @@ -41,6 +41,7 @@ extension Set { /// - Precondition: `BaseValue` is a base class or base `@objc` /// protocol (such as `AnyObject`) of `DerivedValue`. @inlinable +@_unavailableInEmbedded public func _setUpCast( _ source: Set ) -> Set { @@ -57,6 +58,7 @@ public func _setUpCast( /// Called by the casting machinery. @_silgen_name("_swift_setDownCastIndirect") +@_unavailableInEmbedded internal func _setDownCastIndirect( _ source: UnsafePointer>, _ target: UnsafeMutablePointer>) { @@ -71,6 +73,7 @@ internal func _setDownCastIndirect( /// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both /// are reference types. @inlinable +@_unavailableInEmbedded public func _setDownCast(_ source: Set) -> Set { @@ -99,6 +102,7 @@ public func _setDownCast(_ source: Set) /// Called by the casting machinery. @_silgen_name("_swift_setDownCastConditionalIndirect") +@_unavailableInEmbedded internal func _setDownCastConditionalIndirect( _ source: UnsafePointer>, _ target: UnsafeMutablePointer> @@ -118,6 +122,7 @@ internal func _setDownCastConditionalIndirect( /// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both /// are reference types. @inlinable +@_unavailableInEmbedded public func _setDownCastConditional( _ source: Set ) -> Set? { diff --git a/stdlib/public/core/SetStorage.swift b/stdlib/public/core/SetStorage.swift index f5c889ce93c..ca09f4b46af 100644 --- a/stdlib/public/core/SetStorage.swift +++ b/stdlib/public/core/SetStorage.swift @@ -127,6 +127,22 @@ internal class __EmptySetSingleton: __RawSetStorage { #endif } +#if $Embedded +public var _swiftEmptySetSingleton: (Int, Int, Int, Int, UInt8, UInt8, UInt16, UInt32, Int, Int, Int) = + ( + /*isa*/0, /*refcount*/-1, // HeapObject header + /*count*/0, + /*capacity*/0, + /*scale*/0, + /*reservedScale*/0, + /*extra*/0, + /*age*/0, + /*seed*/0, + /*rawElements*/1, + /*metadata*/-1 + ) +#endif + extension __RawSetStorage { /// The empty singleton that is used for every single Set that is created /// without any elements. The contents of the storage must never be mutated. @@ -364,7 +380,7 @@ extension _SetStorage { truncatingIfNeeded: ObjectIdentifier(storage).hashValue) } - storage._seed = seed ?? _HashTable.hashSeed(for: storage, scale: scale) + storage._seed = seed ?? _HashTable.hashSeed(for: Builtin.castToNativeObject(storage), scale: scale) storage._rawElements = UnsafeMutableRawPointer(elementsAddr) // Initialize hash table metadata. diff --git a/stdlib/public/core/TemporaryAllocation.swift b/stdlib/public/core/TemporaryAllocation.swift index a621880f6ad..b590a233350 100644 --- a/stdlib/public/core/TemporaryAllocation.swift +++ b/stdlib/public/core/TemporaryAllocation.swift @@ -88,6 +88,7 @@ internal func _isStackAllocationSafe(byteCount: Int, alignment: Int) -> Bool { return true } +#if !$Embedded // Finally, take a slow path through the standard library to see if the // current environment can accept a larger stack allocation. guard #available(macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4, *) //SwiftStdlib 5.6 @@ -95,6 +96,10 @@ internal func _isStackAllocationSafe(byteCount: Int, alignment: Int) -> Bool { return false } return swift_stdlib_isStackAllocationSafe(byteCount, alignment) +#else + return false +#endif + #else fatalError("unsupported compiler") #endif diff --git a/test/embedded/set-runtime.swift b/test/embedded/set-runtime.swift new file mode 100644 index 00000000000..69ef37aea12 --- /dev/null +++ b/test/embedded/set-runtime.swift @@ -0,0 +1,30 @@ +// RUN: %target-run-simple-swift(%S/Inputs/print.swift -enable-experimental-feature Embedded -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s +// RUN: %target-run-simple-swift(%S/Inputs/print.swift -O -enable-experimental-feature Embedded -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s +// RUN: %target-run-simple-swift(%S/Inputs/print.swift -Osize -enable-experimental-feature Embedded -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: optimized_stdlib +// REQUIRES: OS=macosx || OS=linux-gnu + +@main +struct Main { + static func main() { + var s: Set = [1, 2, 3] + s.insert(42) + s.sorted() + s.allSatisfy { $0 > 0 } + s.contains { $0 > 0 } + s.map { $0 * 2 } + s.filter { $0 > 0 } + s.firstIndex(of: 42) + s.min() + s.max() + s.reduce(0, +) + // s.shuffled() + // s.randomElement() + print("OK!") + } +} + +// CHECK: OK! diff --git a/test/embedded/stdlib-array.swift b/test/embedded/stdlib-array.swift new file mode 100644 index 00000000000..13de4c02ed1 --- /dev/null +++ b/test/embedded/stdlib-array.swift @@ -0,0 +1,30 @@ +// RUN: %target-swift-frontend -target armv7-apple-none-macho -Xcc -D__MACH__ -emit-ir %s -enable-experimental-feature Embedded | %FileCheck %s +// RUN: %target-swift-frontend -target arm64-apple-none-macho -Xcc -D__MACH__ -Xcc -D__arm64__ -Xcc -D__APPLE__ -emit-ir %s -enable-experimental-feature Embedded | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: optimized_stdlib + +public func test() { + var array: [Int] = [1, 2, 3] + array.append(42) + array.append(contentsOf: [4, 5, 6]) + array = array.sorted() + array.sort() + array.allSatisfy { $0 > 0 } + array.contains { $0 > 0 } + array.map { $0 * 2 } + array.filter { $0 > 0 } + array.dropFirst().dropLast().drop(while: { $0 < 0 }) + array.firstIndex(of: 42) + array.min() + array.max() + array.partition(by: { $0 > 0 }) + array.reduce(0, +) + // array.shuffle() + // array = array.shuffled() + // array.randomElement() +} + +test() + +// CHECK: define {{.*}}i32 @main(i32 %0, ptr %1) diff --git a/test/embedded/stdlib-set.swift b/test/embedded/stdlib-set.swift new file mode 100644 index 00000000000..25d60b9e2dd --- /dev/null +++ b/test/embedded/stdlib-set.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -target armv7-apple-none-macho -Xcc -D__MACH__ -emit-ir %s -enable-experimental-feature Embedded | %FileCheck %s +// RUN: %target-swift-frontend -target arm64-apple-none-macho -Xcc -D__MACH__ -Xcc -D__arm64__ -Xcc -D__APPLE__ -emit-ir %s -enable-experimental-feature Embedded | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: optimized_stdlib + +public func test() { + var s: Set = [1, 2, 3] + s.insert(42) + s.sorted() + s.allSatisfy { $0 > 0 } + s.contains { $0 > 0 } + s.map { $0 * 2 } + s.filter { $0 > 0 } + s.firstIndex(of: 42) + s.min() + s.max() + s.reduce(0, +) + // s.shuffled() + // s.randomElement() +} + +test() + +// CHECK: define {{.*}}i32 @main(i32 %0, ptr %1) diff --git a/test/embedded/stdlib-types.swift b/test/embedded/stdlib-types.swift index b284829c634..cc806ff7c53 100644 --- a/test/embedded/stdlib-types.swift +++ b/test/embedded/stdlib-types.swift @@ -36,6 +36,7 @@ public func test() { let opaque = unmanaged.toOpaque() let unmanaged2 = Unmanaged.fromOpaque(opaque) let o = unmanaged2.takeUnretainedValue() + var s1: Set = [1, 2, 3] } test()