[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
// 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<NativeClass: AnyObject> {
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<NativeClass: AnyObject> {
@inlinable
@inline(__always)
internal init(taggedPayload: UInt) {
rawValue = _bridgeObject(taggingPayload: taggedPayload)
rawValue = Builtin.reinterpretCast(taggedPayload)
}
#endif
@@ -84,9 +93,13 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
@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<NativeClass: AnyObject> {
@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<NativeClass: AnyObject> {
internal var nativeInstance: Native {
@inline(__always) get {
_internalInvariant(isNative)
return Builtin.castReferenceFromBridgeObject(rawValue)
return rawValue
}
}
@@ -125,8 +142,10 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
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<NativeClass: AnyObject> {
Builtin.endCOWMutation(&rawValue)
}
#if _runtime(_ObjC)
@inlinable
internal var objCInstance: ObjC {
@inline(__always) get {
@@ -158,4 +178,5 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
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
// 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))

View File

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

View File

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

View File

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

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`.
///
/// `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.
@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
}

View File

@@ -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<Element: Hashable>: _AnyHashableBox {
internal let _value: Set<Element>
internal let _canonical: Set<AnyHashable>
@@ -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 {

View File

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

View File

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

View File

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

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 unmanaged2 = Unmanaged<MyClass>.fromOpaque(opaque)
let o = unmanaged2.takeUnretainedValue()
var s1: Set<Int> = [1, 2, 3]
}
test()