[embedded] Add Set to the embedded stdlib

This commit is contained in:
Kuba Mracek
2023-12-04 15:39:45 -08:00
parent 5e0bcabc8b
commit 2f0883ab24
15 changed files with 183 additions and 15 deletions

View File

@@ -31,9 +31,15 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
// rawValue is passed inout to _isUnique. Although its value // rawValue is passed inout to _isUnique. Although its value
// is unchanged, it must appear mutable to the optimizer. // is unchanged, it must appear mutable to the optimizer.
#if !$Embedded
@usableFromInline @usableFromInline
internal var rawValue: Builtin.BridgeObject internal var rawValue: Builtin.BridgeObject
#else
@usableFromInline
internal var rawValue: NativeClass
#endif
#if !$Embedded
@inlinable @inlinable
@inline(__always) @inline(__always)
internal init(native: Native, isFlagged flag: Bool) { internal init(native: Native, isFlagged flag: Bool) {
@@ -46,13 +52,16 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
native, native,
flag ? (1 as UInt) << _objectPointerLowSpareBitShift : 0) flag ? (1 as UInt) << _objectPointerLowSpareBitShift : 0)
} }
#endif
#if _runtime(_ObjC)
@inlinable @inlinable
@inline(__always) @inline(__always)
internal init(objC: ObjC) { internal init(objC: ObjC) {
_internalInvariant(_usesNativeSwiftReferenceCounting(NativeClass.self)) _internalInvariant(_usesNativeSwiftReferenceCounting(NativeClass.self))
rawValue = _makeObjCBridgeObject(objC) rawValue = _makeObjCBridgeObject(objC)
} }
#endif
@inlinable @inlinable
@inline(__always) @inline(__always)
@@ -65,7 +74,7 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
@inlinable @inlinable
@inline(__always) @inline(__always)
internal init(taggedPayload: UInt) { internal init(taggedPayload: UInt) {
rawValue = _bridgeObject(taggingPayload: taggedPayload) rawValue = Builtin.reinterpretCast(taggedPayload)
} }
#endif #endif
@@ -84,9 +93,13 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
@inlinable @inlinable
internal var isNative: Bool { internal var isNative: Bool {
@inline(__always) get { @inline(__always) get {
#if !$Embedded
let result = Builtin.classifyBridgeObject(rawValue) let result = Builtin.classifyBridgeObject(rawValue)
return !Bool(Builtin.or_Int1(result.isObjCObject, return !Bool(Builtin.or_Int1(result.isObjCObject,
result.isObjCTaggedPointer)) result.isObjCTaggedPointer))
#else
return true
#endif
} }
} }
@@ -100,9 +113,13 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
@inlinable @inlinable
internal var isUnflaggedNative: Bool { internal var isUnflaggedNative: Bool {
@inline(__always) get { @inline(__always) get {
#if !$Embedded
return (_bitPattern(rawValue) & return (_bitPattern(rawValue) &
(_bridgeObjectTaggedPointerBits | _objCTaggedPointerBits | (_bridgeObjectTaggedPointerBits | _objCTaggedPointerBits |
_objectPointerIsObjCBit | _BridgeStorage.flagMask)) == 0 _objectPointerIsObjCBit | _BridgeStorage.flagMask)) == 0
#else
return true
#endif
} }
} }
@@ -117,7 +134,7 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
internal var nativeInstance: Native { internal var nativeInstance: Native {
@inline(__always) get { @inline(__always) get {
_internalInvariant(isNative) _internalInvariant(isNative)
return Builtin.castReferenceFromBridgeObject(rawValue) return rawValue
} }
} }
@@ -125,8 +142,10 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
internal var unflaggedNativeInstance: Native { internal var unflaggedNativeInstance: Native {
@inline(__always) get { @inline(__always) get {
_internalInvariant(isNative) _internalInvariant(isNative)
#if !$Embedded
_internalInvariant(_nonPointerBits(rawValue) == 0) _internalInvariant(_nonPointerBits(rawValue) == 0)
return Builtin.reinterpretCast(rawValue) #endif
return rawValue
} }
} }
@@ -151,6 +170,7 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
Builtin.endCOWMutation(&rawValue) Builtin.endCOWMutation(&rawValue)
} }
#if _runtime(_ObjC)
@inlinable @inlinable
internal var objCInstance: ObjC { internal var objCInstance: ObjC {
@inline(__always) get { @inline(__always) get {
@@ -158,4 +178,5 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
return Builtin.castReferenceFromBridgeObject(rawValue) return Builtin.castReferenceFromBridgeObject(rawValue)
} }
} }
#endif
} }

View File

@@ -725,9 +725,11 @@ func _isUnique_native<T>(_ object: inout T) -> Bool {
// This could be a bridge object, single payload enum, or plain old // This could be a bridge object, single payload enum, or plain old
// reference. Any case it's non pointer bits must be zero, so // reference. Any case it's non pointer bits must be zero, so
// force cast it to BridgeObject and check the spare bits. // force cast it to BridgeObject and check the spare bits.
#if !$Embedded
_internalInvariant( _internalInvariant(
(_bitPattern(Builtin.reinterpretCast(object)) & _objectPointerSpareBits) (_bitPattern(Builtin.reinterpretCast(object)) & _objectPointerSpareBits)
== 0) == 0)
#endif
_internalInvariant(_usesNativeSwiftReferenceCounting( _internalInvariant(_usesNativeSwiftReferenceCounting(
type(of: Builtin.reinterpretCast(object) as AnyObject))) type(of: Builtin.reinterpretCast(object) as AnyObject)))
return Bool(Builtin.isUnique_native(&object)) return Bool(Builtin.isUnique_native(&object))

View File

@@ -43,10 +43,10 @@ split_embedded_sources(
EMBEDDED Assert.swift EMBEDDED Assert.swift
EMBEDDED AssertCommon.swift EMBEDDED AssertCommon.swift
EMBEDDED BidirectionalCollection.swift EMBEDDED BidirectionalCollection.swift
NORMAL Bitset.swift EMBEDDED Bitset.swift
EMBEDDED Bool.swift EMBEDDED Bool.swift
NORMAL BridgeObjectiveC.swift NORMAL BridgeObjectiveC.swift
NORMAL BridgeStorage.swift EMBEDDED BridgeStorage.swift
NORMAL BridgingBuffer.swift NORMAL BridgingBuffer.swift
EMBEDDED Builtin.swift EMBEDDED Builtin.swift
EMBEDDED BuiltinMath.swift EMBEDDED BuiltinMath.swift
@@ -89,7 +89,7 @@ split_embedded_sources(
# END WORKAROUND # END WORKAROUND
EMBEDDED Hasher.swift EMBEDDED Hasher.swift
NORMAL Hashing.swift NORMAL Hashing.swift
NORMAL HashTable.swift EMBEDDED HashTable.swift
EMBEDDED Identifiable.swift EMBEDDED Identifiable.swift
EMBEDDED Indices.swift EMBEDDED Indices.swift
NORMAL InputStream.swift NORMAL InputStream.swift
@@ -111,7 +111,7 @@ split_embedded_sources(
EMBEDDED Misc.swift EMBEDDED Misc.swift
EMBEDDED MutableCollection.swift EMBEDDED MutableCollection.swift
NORMAL NativeDictionary.swift NORMAL NativeDictionary.swift
NORMAL NativeSet.swift EMBEDDED NativeSet.swift
NORMAL NewtypeWrapper.swift NORMAL NewtypeWrapper.swift
NORMAL NFC.swift NORMAL NFC.swift
NORMAL NFD.swift NORMAL NFD.swift
@@ -139,15 +139,15 @@ split_embedded_sources(
EMBEDDED SipHash.swift EMBEDDED SipHash.swift
EMBEDDED Sequence.swift EMBEDDED Sequence.swift
EMBEDDED SequenceAlgorithms.swift EMBEDDED SequenceAlgorithms.swift
NORMAL Set.swift EMBEDDED Set.swift
EMBEDDED SetAlgebra.swift EMBEDDED SetAlgebra.swift
NORMAL SetAnyHashableExtensions.swift NORMAL SetAnyHashableExtensions.swift
NORMAL SetBridging.swift NORMAL SetBridging.swift
NORMAL SetBuilder.swift EMBEDDED SetBuilder.swift
NORMAL SetCasting.swift EMBEDDED SetCasting.swift
NORMAL SetStorage.swift EMBEDDED SetStorage.swift
NORMAL SetVariant.swift EMBEDDED SetVariant.swift
NORMAL ShadowProtocols.swift EMBEDDED ShadowProtocols.swift
NORMAL Shims.swift NORMAL Shims.swift
EMBEDDED Slice.swift EMBEDDED Slice.swift
NORMAL SmallString.swift NORMAL SmallString.swift

View File

@@ -275,3 +275,10 @@ public func swift_deletedMethodError() -> Never {
public func swift_willThrow() throws { 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)
}

View File

@@ -102,7 +102,7 @@ extension _HashTable {
} }
internal static func hashSeed( internal static func hashSeed(
for object: AnyObject, for object: Builtin.NativeObject,
scale: Int8 scale: Int8
) -> Int { ) -> Int {
// We generate a new hash seed whenever a new hash table is allocated and // We generate a new hash seed whenever a new hash table is allocated and

View File

@@ -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<UInt64>.size)
swift_stdlib_random(&seed1, MemoryLayout<UInt64>.size)
return .init(seed0: seed0, seed1: seed1, deterministic: false)
}()
#endif
/// The universal hash function used by `Set` and `Dictionary`. /// The universal hash function used by `Set` and `Dictionary`.
/// ///
/// `Hasher` can be used to map an arbitrary sequence of bytes to an integer /// `Hasher` can be used to map an arbitrary sequence of bytes to an integer

View File

@@ -351,6 +351,7 @@ extension _NativeSet: _SetBuffer {
// This function has a highly visible name to make it stand out in stack traces. // This function has a highly visible name to make it stand out in stack traces.
@usableFromInline @usableFromInline
@inline(never) @inline(never)
@_unavailableInEmbedded
internal func ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS( internal func ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(
_ elementType: Any.Type _ elementType: Any.Type
) -> Never { ) -> Never {
@@ -379,7 +380,11 @@ extension _NativeSet { // Insertions
// because we'll need to compare elements in case of hash collisions. // because we'll need to compare elements in case of hash collisions.
let (bucket, found) = find(element, hashValue: hashValue) let (bucket, found) = find(element, hashValue: hashValue)
guard !found else { guard !found else {
#if !$Embedded
ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self)
#else
fatalError("duplicate elements in a Set")
#endif
} }
hashTable.insert(bucket) hashTable.insert(bucket)
uncheckedInitialize(at: bucket, to: element) uncheckedInitialize(at: bucket, to: element)
@@ -418,7 +423,11 @@ extension _NativeSet { // Insertions
if rehashed { if rehashed {
let (b, f) = find(element) let (b, f) = find(element)
if f { if f {
#if !$Embedded
ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self)
#else
fatalError("duplicate elements in a Set")
#endif
} }
bucket = b bucket = b
} }
@@ -437,7 +446,11 @@ extension _NativeSet { // Insertions
if rehashed { if rehashed {
let (b, f) = find(element) let (b, f) = find(element)
if f != found { if f != found {
#if !$Embedded
ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self)
#else
fatalError("duplicate elements in a Set")
#endif
} }
bucket = b bucket = b
} }

View File

@@ -448,12 +448,14 @@ extension Set: Hashable {
} }
} }
@_unavailableInEmbedded
extension Set: _HasCustomAnyHashableRepresentation { extension Set: _HasCustomAnyHashableRepresentation {
public __consuming func _toCustomAnyHashable() -> AnyHashable? { public __consuming func _toCustomAnyHashable() -> AnyHashable? {
return AnyHashable(_box: _SetAnyHashableBox(self)) return AnyHashable(_box: _SetAnyHashableBox(self))
} }
} }
@_unavailableInEmbedded
internal struct _SetAnyHashableBox<Element: Hashable>: _AnyHashableBox { internal struct _SetAnyHashableBox<Element: Hashable>: _AnyHashableBox {
internal let _value: Set<Element> internal let _value: Set<Element>
internal let _canonical: Set<AnyHashable> internal let _canonical: Set<AnyHashable>
@@ -1034,6 +1036,7 @@ extension Set: SetAlgebra {
} }
} }
@_unavailableInEmbedded
extension Set: CustomStringConvertible, CustomDebugStringConvertible { extension Set: CustomStringConvertible, CustomDebugStringConvertible {
/// A string that represents the contents of the set. /// A string that represents the contents of the set.
public var description: String { public var description: String {

View File

@@ -41,6 +41,7 @@ extension Set {
/// - Precondition: `BaseValue` is a base class or base `@objc` /// - Precondition: `BaseValue` is a base class or base `@objc`
/// protocol (such as `AnyObject`) of `DerivedValue`. /// protocol (such as `AnyObject`) of `DerivedValue`.
@inlinable @inlinable
@_unavailableInEmbedded
public func _setUpCast<DerivedValue, BaseValue>( public func _setUpCast<DerivedValue, BaseValue>(
_ source: Set<DerivedValue> _ source: Set<DerivedValue>
) -> Set<BaseValue> { ) -> Set<BaseValue> {
@@ -57,6 +58,7 @@ public func _setUpCast<DerivedValue, BaseValue>(
/// Called by the casting machinery. /// Called by the casting machinery.
@_silgen_name("_swift_setDownCastIndirect") @_silgen_name("_swift_setDownCastIndirect")
@_unavailableInEmbedded
internal func _setDownCastIndirect<SourceValue, TargetValue>( internal func _setDownCastIndirect<SourceValue, TargetValue>(
_ source: UnsafePointer<Set<SourceValue>>, _ source: UnsafePointer<Set<SourceValue>>,
_ target: UnsafeMutablePointer<Set<TargetValue>>) { _ target: UnsafeMutablePointer<Set<TargetValue>>) {
@@ -71,6 +73,7 @@ internal func _setDownCastIndirect<SourceValue, TargetValue>(
/// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both /// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both
/// are reference types. /// are reference types.
@inlinable @inlinable
@_unavailableInEmbedded
public func _setDownCast<BaseValue, DerivedValue>(_ source: Set<BaseValue>) public func _setDownCast<BaseValue, DerivedValue>(_ source: Set<BaseValue>)
-> Set<DerivedValue> { -> Set<DerivedValue> {
@@ -99,6 +102,7 @@ public func _setDownCast<BaseValue, DerivedValue>(_ source: Set<BaseValue>)
/// Called by the casting machinery. /// Called by the casting machinery.
@_silgen_name("_swift_setDownCastConditionalIndirect") @_silgen_name("_swift_setDownCastConditionalIndirect")
@_unavailableInEmbedded
internal func _setDownCastConditionalIndirect<SourceValue, TargetValue>( internal func _setDownCastConditionalIndirect<SourceValue, TargetValue>(
_ source: UnsafePointer<Set<SourceValue>>, _ source: UnsafePointer<Set<SourceValue>>,
_ target: UnsafeMutablePointer<Set<TargetValue>> _ target: UnsafeMutablePointer<Set<TargetValue>>
@@ -118,6 +122,7 @@ internal func _setDownCastConditionalIndirect<SourceValue, TargetValue>(
/// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both /// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both
/// are reference types. /// are reference types.
@inlinable @inlinable
@_unavailableInEmbedded
public func _setDownCastConditional<BaseValue, DerivedValue>( public func _setDownCastConditional<BaseValue, DerivedValue>(
_ source: Set<BaseValue> _ source: Set<BaseValue>
) -> Set<DerivedValue>? { ) -> Set<DerivedValue>? {

View File

@@ -127,6 +127,22 @@ internal class __EmptySetSingleton: __RawSetStorage {
#endif #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 { extension __RawSetStorage {
/// The empty singleton that is used for every single Set that is created /// 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. /// without any elements. The contents of the storage must never be mutated.
@@ -364,7 +380,7 @@ extension _SetStorage {
truncatingIfNeeded: ObjectIdentifier(storage).hashValue) 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) storage._rawElements = UnsafeMutableRawPointer(elementsAddr)
// Initialize hash table metadata. // Initialize hash table metadata.

View File

@@ -88,6 +88,7 @@ internal func _isStackAllocationSafe(byteCount: Int, alignment: Int) -> Bool {
return true return true
} }
#if !$Embedded
// Finally, take a slow path through the standard library to see if the // Finally, take a slow path through the standard library to see if the
// current environment can accept a larger stack allocation. // 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 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 false
} }
return swift_stdlib_isStackAllocationSafe(byteCount, alignment) return swift_stdlib_isStackAllocationSafe(byteCount, alignment)
#else
return false
#endif
#else #else
fatalError("unsupported compiler") fatalError("unsupported compiler")
#endif #endif

View File

@@ -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<Int> = [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!

View File

@@ -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)

View File

@@ -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<Int> = [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)

View File

@@ -36,6 +36,7 @@ public func test() {
let opaque = unmanaged.toOpaque() let opaque = unmanaged.toOpaque()
let unmanaged2 = Unmanaged<MyClass>.fromOpaque(opaque) let unmanaged2 = Unmanaged<MyClass>.fromOpaque(opaque)
let o = unmanaged2.takeUnretainedValue() let o = unmanaged2.takeUnretainedValue()
var s1: Set<Int> = [1, 2, 3]
} }
test() test()