├── .gitignore ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── Compute │ ├── Attribute │ │ ├── AnyAttribute.swift │ │ ├── Attribute.swift │ │ ├── AttributeType.swift │ │ ├── Body │ │ │ ├── AttributeBody.swift │ │ │ └── AttributeBodyVisitor.swift │ │ ├── External.swift │ │ ├── Focus.swift │ │ ├── Indirect │ │ │ └── IndirectAttribute.swift │ │ ├── Map.swift │ │ ├── Observed │ │ │ └── ObservedAttribute.swift │ │ ├── Optional │ │ │ ├── AnyOptionalAttribute.swift │ │ │ └── OptionalAttribute.swift │ │ ├── PointerOffset.swift │ │ ├── Rule │ │ │ ├── AnyRuleContext.swift │ │ │ ├── Rule.swift │ │ │ ├── RuleContext.swift │ │ │ └── StatefulRule.swift │ │ └── Weak │ │ │ ├── AnyWeakAttribute.swift │ │ │ └── WeakAttribute.swift │ ├── Compute.swift │ ├── Graph │ │ ├── Graph.swift │ │ ├── Subgraph.swift │ │ └── TreeElement.swift │ └── Runtime │ │ ├── CompareValues.swift │ │ ├── Enum.swift │ │ ├── Metadata.swift │ │ ├── Signature.swift │ │ └── Tuple.swift ├── ComputeCxx │ ├── AGSwiftSupport.h │ ├── Attribute │ │ ├── AttributeData │ │ │ └── Node │ │ │ │ ├── IndirectNode.cpp │ │ │ │ ├── IndirectNode.h │ │ │ │ ├── Node.cpp │ │ │ │ └── Node.h │ │ ├── AttributeID │ │ │ ├── AGAttribute.h │ │ │ ├── AttributeID.cpp │ │ │ ├── AttributeID.h │ │ │ ├── OffsetAttributeID.h │ │ │ ├── WeakAttributeID.cpp │ │ │ └── WeakAttributeID.h │ │ └── AttributeType │ │ │ ├── AGAttributeType.h │ │ │ └── AttributeType.h │ ├── Closure │ │ ├── AGClosure.h │ │ └── ClosureFunction.h │ ├── Comparison │ │ ├── AGComparison-Private.h │ │ ├── AGComparison.cpp │ │ ├── AGComparison.h │ │ ├── Builder.h │ │ ├── Compare.cpp │ │ ├── Compare.h │ │ ├── LayoutDescriptor.cpp │ │ ├── LayoutDescriptor.h │ │ └── ValueLayout.h │ ├── Data │ │ ├── Constants.h │ │ ├── Page.h │ │ ├── Pointer.h │ │ ├── Table.cpp │ │ ├── Table.h │ │ ├── Zone.cpp │ │ └── Zone.h │ ├── Errors │ │ ├── Errors.cpp │ │ └── Errors.h │ ├── Graph │ │ ├── AGDescription.h │ │ ├── AGDescription.mm │ │ ├── AGGraph-Private.h │ │ ├── AGGraph.cpp │ │ ├── AGGraph.h │ │ ├── AGGraph.mm │ │ ├── Context.cpp │ │ ├── Context.h │ │ ├── Graph.cpp │ │ ├── Graph.h │ │ ├── Graph.mm │ │ ├── KeyTable.cpp │ │ ├── KeyTable.h │ │ ├── TraceRecorder.cpp │ │ └── TraceRecorder.h │ ├── Log │ │ ├── Log.cpp │ │ └── Log.h │ ├── Private │ │ └── CFRuntime.h │ ├── Subgraph │ │ ├── AGSubgraph-Private.h │ │ ├── AGSubgraph.h │ │ ├── Subgraph.cpp │ │ └── Subgraph.h │ ├── Swift │ │ ├── AGTuple.cpp │ │ ├── AGTuple.h │ │ ├── AGType.cpp │ │ ├── AGType.h │ │ ├── ContextDescriptor.cpp │ │ ├── ContextDescriptor.h │ │ ├── Metadata.cpp │ │ ├── Metadata.h │ │ ├── MetadataVisitor.cpp │ │ ├── MetadataVisitor.h │ │ ├── SwiftShims.h │ │ ├── _SwiftStdlibCxxOverlay.h │ │ └── mach-o │ │ │ ├── MachOFile.cpp │ │ │ ├── MachOFile.h │ │ │ ├── dyld.cpp │ │ │ └── dyld.h │ ├── Time │ │ ├── Time.cpp │ │ └── Time.h │ ├── Trace │ │ ├── AGTrace.h │ │ ├── AGTraceFlags.h │ │ ├── ExternalTrace.cpp │ │ ├── ExternalTrace.h │ │ ├── Trace.cpp │ │ └── Trace.h │ ├── UniqueID │ │ ├── AGUniqueID.cpp │ │ └── AGUniqueID.h │ ├── Vector │ │ └── Vector.h │ └── include │ │ └── Compute.h ├── ComputeCxxSwiftSupport │ └── ComputeCxxSwiftSupport.swift └── Utilities │ ├── HashTable.cpp │ ├── Heap.cpp │ └── include │ └── Utilities │ ├── CFPointer.h │ ├── FreeDeleter.h │ ├── HashTable.h │ ├── Heap.h │ ├── List.h │ ├── ObjCPointer.h │ └── TaggedPointer.h └── Tests ├── ComputeCompatibilityTests ├── Shared └── Shims.swift ├── ComputeTests ├── Shared │ ├── Graph │ │ └── GraphTests.swift │ ├── Runtime │ │ ├── CompareValuesTests.swift │ │ ├── MetadataTests.swift │ │ ├── PrefetchCompareValuesTests.swift │ │ ├── ReflectionTests.swift │ │ └── TupleTypeTests.swift │ ├── TestTypes.swift │ └── reprinting.swift └── Shims.swift └── UtilitiesTests ├── HashTableTests.swift ├── HeapTests.swift └── ListTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Swift 5 | .build 6 | .swiftpm 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 James Moschou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "d5a74a2bc3e7341b5a26dd2a67cc7e3657b4adc4fec92d36cc0ae8cd14c0fa09", 3 | "pins" : [ 4 | { 5 | "identity" : "swift-algorithms", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/apple/swift-algorithms", 8 | "state" : { 9 | "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", 10 | "version" : "1.2.1" 11 | } 12 | }, 13 | { 14 | "identity" : "swift-numerics", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/apple/swift-numerics.git", 17 | "state" : { 18 | "revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8", 19 | "version" : "1.0.3" 20 | } 21 | } 22 | ], 23 | "version" : 3 24 | } 25 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | 3 | import PackageDescription 4 | 5 | let swiftProjectPath = "\(Context.packageDirectory)/../swift-project" 6 | 7 | extension Target { 8 | fileprivate static func swiftRuntimeTarget( 9 | name: String, 10 | dependencies: [Dependency] = [], 11 | path: String? = nil, 12 | sources: [String]? = nil, 13 | cxxSettings: [CXXSetting] = [] 14 | ) -> Target { 15 | .target( 16 | name: name, 17 | dependencies: dependencies, 18 | path: path ?? "Sources/\(name)", 19 | sources: sources, 20 | cxxSettings: [ 21 | .unsafeFlags([ 22 | "-static", 23 | "-DCOMPILED_WITH_SWIFT", 24 | "-DPURE_BRIDGING_MODE", 25 | "-UIBOutlet", "-UIBAction", "-UIBInspectable", 26 | "-isystem", "\(swiftProjectPath)/swift/include", 27 | "-isystem", "\(swiftProjectPath)/swift/stdlib/public/SwiftShims", 28 | "-isystem", "\(swiftProjectPath)/swift/stdlib/public/runtime", 29 | "-isystem", "\(swiftProjectPath)/llvm-project/llvm/include", 30 | "-isystem", "\(swiftProjectPath)/llvm-project/clang/include", 31 | "-isystem", "\(swiftProjectPath)/build/Default/swift/include", 32 | "-isystem", "\(swiftProjectPath)/build/Default/llvm/include", 33 | "-isystem", "\(swiftProjectPath)/build/Default/llvm/tools/clang/include", 34 | "-DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING", 35 | ]) 36 | ] + cxxSettings 37 | ) 38 | } 39 | } 40 | 41 | let package = Package( 42 | name: "Compute", 43 | platforms: [.macOS(.v15)], 44 | products: [ 45 | .library(name: "Compute", targets: ["Compute"]) 46 | ], 47 | dependencies: [ 48 | .package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"), 49 | .package(path: "../DarwinPrivateFrameworks"), 50 | ], 51 | targets: [ 52 | .target(name: "Utilities"), 53 | .testTarget( 54 | name: "UtilitiesTests", 55 | dependencies: ["Utilities"], 56 | cxxSettings: [.define("SWIFT_TESTING")], 57 | swiftSettings: [.interoperabilityMode(.Cxx)] 58 | ), 59 | .target( 60 | name: "Compute", 61 | dependencies: ["ComputeCxx"], 62 | cxxSettings: [.headerSearchPath("../ComputeCxx")], 63 | swiftSettings: [.interoperabilityMode(.Cxx), .enableExperimentalFeature("Extern")] 64 | ), 65 | .testTarget( 66 | name: "ComputeTests", 67 | dependencies: [ 68 | "Compute", 69 | .product(name: "Algorithms", package: "swift-algorithms"), 70 | ], 71 | swiftSettings: [ 72 | .interoperabilityMode(.Cxx) 73 | ], 74 | linkerSettings: [.linkedLibrary("swiftDemangle")] 75 | ), 76 | .testTarget( 77 | name: "ComputeCompatibilityTests", 78 | dependencies: [ 79 | .product(name: "AttributeGraph", package: "DarwinPrivateFrameworks"), 80 | .product(name: "Algorithms", package: "swift-algorithms"), 81 | ], 82 | swiftSettings: [ 83 | .interoperabilityMode(.Cxx) 84 | ], 85 | linkerSettings: [.linkedLibrary("swiftDemangle")] 86 | ), 87 | .swiftRuntimeTarget( 88 | name: "ComputeCxx", 89 | dependencies: ["Utilities", "ComputeCxxSwiftSupport"], 90 | cxxSettings: [.headerSearchPath("")] 91 | ), 92 | .target(name: "ComputeCxxSwiftSupport"), 93 | ], 94 | cxxLanguageStandard: .cxx20 95 | ) 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Compute 2 | 3 | An incremental computation library for Swift. 4 | 5 | Compute is a reimplementation of the AttributeGraph framework on Apple 6 | platforms. 7 | 8 | ## Acknowledgments 9 | 10 | Thank you to [OpenSwiftUIProject](https://github.com/OpenSwiftUIProject/OpenGraph/tree/main) 11 | for providing much insight into AttributeGraph and the Swift runtime. 12 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/AnyAttribute.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct InputOptions {} 4 | 5 | public struct SearchOptions {} 6 | 7 | public struct AttributeFlags {} 8 | 9 | extension AnyAttribute { 10 | 11 | public static var current: AnyAttribute? { 12 | fatalError("not implemented") 13 | } 14 | 15 | public init(_ attribute: Attribute) { 16 | fatalError("not implemented") 17 | } 18 | 19 | public func unsafeOffset(at offset: Int) -> AnyAttribute { 20 | fatalError("not implemented") 21 | } 22 | 23 | public func unsafeCast(to type: Value.Type) -> Attribute { 24 | fatalError("not implemented") 25 | } 26 | 27 | public var _bodyType: Any.Type { 28 | fatalError("not implemented") 29 | } 30 | 31 | public var _bodyPointer: UnsafeRawPointer { 32 | fatalError("not implemented") 33 | } 34 | 35 | public func visitBody(_ visitor: inout Visitor) { 36 | fatalError("not implemented") 37 | } 38 | 39 | public func mutateBody(as type: Body.Type, invalidating: Bool, _ mutator: (inout Body) -> Void) { 40 | fatalError("not implemented") 41 | } 42 | 43 | public func breadthFirstSearch(options: SearchOptions, _ predicate: (AnyAttribute) -> Bool) -> Bool { 44 | fatalError("not implemented") 45 | } 46 | 47 | public var valueType: Any.Type { 48 | fatalError("not implemented") 49 | } 50 | 51 | public func setFlags(_ newFlags: AttributeFlags, mask: AttributeFlags) { 52 | fatalError("not implemented") 53 | } 54 | 55 | public func addInput(_ input: AnyAttribute, options: InputOptions, token: Int) { 56 | fatalError("not implemented") 57 | } 58 | 59 | public func addInput(_ input: Attribute, options: InputOptions, token: Int) { 60 | fatalError("not implemented") 61 | } 62 | 63 | public var indirectDependency: AnyAttribute? { 64 | get { 65 | fatalError("not implemented") 66 | } 67 | set { 68 | fatalError("not implemented") 69 | } 70 | } 71 | 72 | } 73 | 74 | extension AnyAttribute: @retroactive CustomStringConvertible { 75 | 76 | public var description: String { 77 | fatalError("not implemented") 78 | } 79 | 80 | } 81 | 82 | extension AnyAttribute: @retroactive Equatable { 83 | 84 | public static func == (_ lhs: AnyAttribute, _ rhs: AnyAttribute) -> Bool { 85 | fatalError("not implemented") 86 | } 87 | 88 | } 89 | 90 | extension AnyAttribute: @retroactive Hashable { 91 | 92 | public func hash(into hasher: inout Hasher) { 93 | fatalError("not implemented") 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Attribute.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct ValueState {} 4 | 5 | public struct ValueOptions {} 6 | 7 | public struct ChangedValueFlags {} 8 | 9 | @propertyWrapper 10 | @dynamicMemberLookup 11 | public struct Attribute { 12 | 13 | public var identifier: AnyAttribute 14 | 15 | public init(identifier: AnyAttribute) { 16 | self.identifier = identifier 17 | } 18 | 19 | public init(_ attribute: Attribute) { 20 | fatalError("not implemented") 21 | } 22 | 23 | public init(type: Value.Type) { 24 | fatalError("not implemented") 25 | } 26 | 27 | public init(value: Value) { 28 | fatalError("not implemented") 29 | } 30 | 31 | public init( 32 | body: UnsafePointer, value: UnsafePointer?, flags: AGAttributeTypeFlags, 33 | update: () -> (UnsafeMutableRawPointer, AnyAttribute) -> Void 34 | ) { 35 | fatalError("not implemented") 36 | } 37 | 38 | public func unsafeCast(to type: T.Type) -> Attribute { 39 | fatalError("not implemented") 40 | } 41 | 42 | public func unsafeOffset(at offset: Int, as type: T) -> Attribute { 43 | fatalError("not implemented") 44 | } 45 | 46 | public func applying(offset: PointerOffset) -> Attribute { 47 | fatalError("not implemented") 48 | } 49 | 50 | public func breadthFirstSearch(options: SearchOptions, _ predicate: (AnyAttribute) -> Bool) -> Bool { 51 | fatalError("not implemented") 52 | } 53 | 54 | public func visitBody(_ visitor: inout Visitor) { 55 | fatalError("not implemented") 56 | } 57 | 58 | public func mutateBody(as bodyType: Body.Type, invalidating: Bool, _ mutator: (inout Body) -> Void) { 59 | fatalError("not implemented") 60 | } 61 | 62 | public func validate() { 63 | fatalError("not implemented") 64 | } 65 | 66 | public var value: Value { 67 | unsafeAddress { 68 | fatalError("not implemented") 69 | } 70 | set { 71 | fatalError("not implemented") 72 | } 73 | } 74 | 75 | public func setValue(_ value: Value) -> Bool { 76 | fatalError("not implemented") 77 | } 78 | 79 | public var hasValue: Bool { 80 | fatalError("not implemented") 81 | } 82 | 83 | public var valueState: ValueState { 84 | fatalError("not implemented") 85 | } 86 | 87 | public func prefetchValue() { 88 | fatalError("not implemented") 89 | } 90 | 91 | public func updateValue() { 92 | fatalError("not implemented") 93 | } 94 | 95 | public func invalidateValue() { 96 | fatalError("not implemented") 97 | } 98 | 99 | public func changedValue(options: ValueOptions) -> (value: Value, changed: Bool) { 100 | fatalError("not implemented") 101 | } 102 | 103 | public var flags: AttributeFlags { 104 | get { 105 | fatalError("not implemented") 106 | } 107 | set { 108 | fatalError("not implemented") 109 | } 110 | } 111 | 112 | public func setFlags(_ flags: AttributeFlags, mask: AttributeFlags) { 113 | fatalError("not implemented") 114 | } 115 | 116 | public func valueAndFlags(options: ValueOptions) -> (value: Value, flags: ChangedValueFlags) { 117 | fatalError("not implemented") 118 | } 119 | 120 | public func addInput(_ input: Attribute, options: InputOptions, token: Int) { 121 | fatalError("not implemented") 122 | } 123 | 124 | public func addInput(_ input: AnyAttribute, options: InputOptions, token: Int) { 125 | fatalError("not implemented") 126 | } 127 | 128 | public var graph: Graph { 129 | fatalError("not implemented") 130 | } 131 | 132 | public var subgraph: Subgraph { 133 | fatalError("not implemented") 134 | } 135 | 136 | public var subgraphOrNil: Subgraph? { 137 | fatalError("not implemented") 138 | } 139 | 140 | public var wrappedValue: Value { 141 | unsafeAddress { 142 | fatalError("not implemented") 143 | } 144 | set { 145 | fatalError("not implemented") 146 | } 147 | } 148 | 149 | public var projectedValue: Attribute { 150 | get { 151 | fatalError("not implemented") 152 | } 153 | set { 154 | fatalError("not implemented") 155 | } 156 | } 157 | 158 | public subscript(offset: (inout Value) -> PointerOffset) -> Attribute { 159 | fatalError("not implemented") 160 | } 161 | 162 | public subscript(dynamicMember keyPath: KeyPath) -> Attribute { 163 | fatalError("not implemented") 164 | } 165 | 166 | } 167 | 168 | extension Attribute: CustomStringConvertible { 169 | 170 | public var description: String { 171 | fatalError("not implemented") 172 | } 173 | 174 | } 175 | 176 | extension Attribute: Equatable { 177 | 178 | public static func == (_ lhs: Attribute, _ rhs: Attribute) -> Bool { 179 | return lhs.identifier == rhs.identifier 180 | } 181 | 182 | } 183 | 184 | extension Attribute: Hashable { 185 | 186 | public func hash(into hasher: inout Hasher) { 187 | hasher.combine(identifier) 188 | } 189 | 190 | } 191 | 192 | extension Attribute { 193 | 194 | public init(_ body: Body, initialValue: Value? = nil) where Body.Value == Value { 195 | fatalError("not implemented") 196 | } 197 | 198 | public init(_ body: Body, initialValue: Value? = nil) where Body.Value == Value { 199 | fatalError("not implemented") 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/AttributeType.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | extension AGUnownedGraphRef { 4 | 5 | @_extern(c, "AGGraphInternAttributeType") 6 | fileprivate static func internAttributeType( 7 | _ graph: UnsafeRawPointer, 8 | type: Metadata, 9 | makeAttributeType: () -> UnsafePointer 10 | ) 11 | -> UInt32 12 | 13 | @inline(__always) 14 | func internAttributeType(type: Metadata, makeAttributeType: () -> UnsafePointer) -> UInt32 { 15 | return AGUnownedGraphRef.internAttributeType( 16 | unsafeBitCast(self, to: UnsafeRawPointer.self), 17 | type: type, 18 | makeAttributeType: makeAttributeType 19 | ) 20 | } 21 | 22 | } 23 | 24 | extension AGAttributeType { 25 | 26 | init( 27 | selfType: Any.Type, 28 | bodyType: _AttributeBody.Type, // witness table 29 | valueType: Any.Type, 30 | flags: AGAttributeTypeFlags, 31 | update: @escaping (UnsafeMutableRawPointer, AnyAttribute) -> Void, 32 | ) { 33 | self.init() 34 | 35 | var flags = flags 36 | flags.insert(bodyType.flags) 37 | flags.insert(AGAttributeTypeFlags(rawValue: UInt32(bodyType.comparisonMode.rawValue))) 38 | if bodyType._hasDestroySelf { 39 | flags.insert(.hasDestroySelf) 40 | } 41 | 42 | self.selfType = Metadata(selfType) 43 | self.valueType = Metadata(valueType) 44 | self.update = unsafeBitCast(update, to: AGClosureStorage.self) 45 | self.callbacks = nil 46 | self.flags = flags 47 | 48 | self.initialSelfType = Metadata(selfType) 49 | self.initialAttributeBodyWitnessTable = unsafeBitCast(bodyType, to: UnsafeRawPointer.self) // TODO: double check this 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Body/AttributeBody.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public protocol _AttributeBody { 4 | 5 | static func _destroySelf(_ self: UnsafeMutableRawPointer) 6 | static func _updateDefault(_ default: UnsafeMutableRawPointer) 7 | 8 | static var comparisonMode: AGComparisonMode { get } 9 | static var _hasDestroySelf: Bool { get } 10 | static var flags: AGAttributeTypeFlags { get } 11 | 12 | } 13 | 14 | extension _AttributeBody { 15 | 16 | public static func _destroySelf(_ self: UnsafeMutableRawPointer) { 17 | fatalError("not implemented") 18 | } 19 | 20 | public static func _updateDefault(_ default: UnsafeMutableRawPointer) { 21 | fatalError("not implemented") 22 | } 23 | 24 | public static var comparisonMode: AGComparisonMode { 25 | fatalError("not implemented") 26 | } 27 | 28 | public static var _hasDestroySelf: Bool { 29 | fatalError("not implemented") 30 | } 31 | 32 | public static var flags: AGAttributeTypeFlags { 33 | fatalError("not implemented") 34 | } 35 | 36 | } 37 | 38 | extension _AttributeBody { 39 | 40 | public var updateWasCancelled: Bool { 41 | fatalError("not implemented") 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Body/AttributeBodyVisitor.swift: -------------------------------------------------------------------------------- 1 | public protocol AttributeBodyVisitor { 2 | 3 | func visit(body: UnsafePointer) 4 | 5 | } 6 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/External.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct External { 4 | 5 | public init() {} 6 | 7 | public static func _update(_: UnsafeMutableRawPointer, attribute: AnyAttribute) { 8 | fatalError("not implemented") 9 | } 10 | 11 | } 12 | 13 | extension External: _AttributeBody { 14 | 15 | public static var comparisonMode: AGComparisonMode { 16 | fatalError("not implemented") 17 | } 18 | 19 | public static var flags: AGAttributeTypeFlags { 20 | fatalError("not implemented") 21 | } 22 | 23 | } 24 | 25 | extension External: CustomStringConvertible { 26 | 27 | public var description: String { 28 | fatalError("not implemented") 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Focus.swift: -------------------------------------------------------------------------------- 1 | public struct Focus { 2 | 3 | public var root: Attribute 4 | public var keyPath: KeyPath 5 | 6 | public init(root: Attribute, keyPath: KeyPath) { 7 | self.root = root 8 | self.keyPath = keyPath 9 | } 10 | 11 | } 12 | 13 | extension Focus: Rule { 14 | 15 | public var value: Value { 16 | return root.value[keyPath: keyPath] 17 | } 18 | 19 | public static var flags: AGAttributeTypeFlags { 20 | fatalError("not implemented") 21 | } 22 | 23 | } 24 | 25 | extension Focus: CustomStringConvertible { 26 | 27 | public var description: String { 28 | fatalError("not implemented") 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Indirect/IndirectAttribute.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | @propertyWrapper 4 | @dynamicMemberLookup 5 | public struct IndirectAttribute { 6 | 7 | public var identifier: AnyAttribute 8 | 9 | public init(source: Attribute) { 10 | fatalError("not implemented") 11 | } 12 | 13 | public var attribute: Attribute { 14 | fatalError("not implemented") 15 | } 16 | 17 | public var source: Attribute { 18 | get { 19 | fatalError("not implemented") 20 | } 21 | set { 22 | fatalError("not implemented") 23 | } 24 | } 25 | 26 | public func resetSource() { 27 | fatalError("not implemented") 28 | } 29 | 30 | public var dependency: AnyAttribute? { 31 | get { 32 | fatalError("not implemented") 33 | } 34 | set { 35 | fatalError("not implemented") 36 | } 37 | } 38 | 39 | public var value: Value { 40 | get { 41 | fatalError("not implemented") 42 | } 43 | set { 44 | fatalError("not implemented") 45 | } 46 | } 47 | 48 | public func changedValue(options: ValueOptions) -> (value: Value, changed: Bool) { 49 | fatalError("not implemented") 50 | } 51 | 52 | public var wrappedValue: Value { 53 | get { 54 | fatalError("not implemented") 55 | } 56 | set { 57 | fatalError("not implemented") 58 | } 59 | } 60 | 61 | public var projectedValue: Attribute { 62 | fatalError("not implemented") 63 | } 64 | 65 | public subscript(dynamicMember keyPath: KeyPath) -> Attribute { 66 | fatalError("not implemented") 67 | } 68 | 69 | } 70 | 71 | extension IndirectAttribute: Equatable { 72 | 73 | public static func == (_ lhs: IndirectAttribute, _ rhs: IndirectAttribute) -> Bool { 74 | return lhs.identifier == rhs.identifier 75 | } 76 | 77 | } 78 | 79 | extension IndirectAttribute: Hashable { 80 | 81 | public func hash(into hasher: inout Hasher) { 82 | hasher.combine(identifier) 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Map.swift: -------------------------------------------------------------------------------- 1 | public struct Map { 2 | 3 | public var arg: Attribute 4 | public var body: (Arg) -> Value 5 | 6 | public init(arg: Attribute, body: @escaping (Arg) -> Value) { 7 | self.arg = arg 8 | self.body = body 9 | } 10 | 11 | } 12 | 13 | extension Map: Rule { 14 | 15 | public var value: Value { 16 | return body(arg.value) 17 | } 18 | 19 | public static var flags: AGAttributeTypeFlags { 20 | fatalError("not implemented") 21 | } 22 | 23 | } 24 | 25 | extension Map: CustomStringConvertible { 26 | 27 | public var description: String { 28 | fatalError("not implemented") 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Observed/ObservedAttribute.swift: -------------------------------------------------------------------------------- 1 | public protocol ObservedAttribute: _AttributeBody { 2 | 3 | func destroy() 4 | } 5 | 6 | extension ObservedAttribute { 7 | 8 | public static func _destroySelf(_ self: UnsafeMutableRawPointer) { 9 | fatalError("not implemented") 10 | } 11 | 12 | public static var _hasDestroySelf: Bool { 13 | fatalError("not implemented") 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Optional/AnyOptionalAttribute.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct AnyOptionalAttribute { 4 | 5 | public static var current: AnyOptionalAttribute? { 6 | fatalError("not implemented") 7 | } 8 | 9 | public var identifier: AnyAttribute 10 | 11 | public init() { 12 | fatalError("not implemented") 13 | } 14 | 15 | public init(_ weakAttribute: AnyWeakAttribute) { 16 | fatalError("not implemented") 17 | } 18 | 19 | public init(_ attribute: AnyAttribute?) { 20 | fatalError("not implemented") 21 | } 22 | 23 | public init(_ attribute: AnyAttribute) { 24 | fatalError("not implemented") 25 | } 26 | 27 | public init(_ optionalAttribute: OptionalAttribute) { 28 | fatalError("not implemented") 29 | } 30 | 31 | public func unsafeCast(to _: Value.Type) -> OptionalAttribute { 32 | fatalError("not implemented") 33 | } 34 | 35 | public var attribute: AnyAttribute? { 36 | get { 37 | fatalError("not implemented") 38 | } 39 | set { 40 | fatalError("not implemented") 41 | } 42 | } 43 | 44 | public func map(_ transform: (AnyAttribute) -> T) -> T? { 45 | fatalError("not implemented") 46 | } 47 | 48 | } 49 | 50 | extension AnyOptionalAttribute: CustomStringConvertible { 51 | 52 | public var description: String { 53 | fatalError("not implemented") 54 | } 55 | 56 | } 57 | 58 | extension AnyOptionalAttribute: Equatable { 59 | 60 | public static func == (_ lhs: AnyOptionalAttribute, _ rhs: AnyOptionalAttribute) -> Bool { 61 | return lhs.identifier == rhs.identifier 62 | } 63 | 64 | } 65 | 66 | extension AnyOptionalAttribute: Hashable { 67 | 68 | public func hash(into hasher: inout Hasher) { 69 | hasher.combine(identifier) 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Optional/OptionalAttribute.swift: -------------------------------------------------------------------------------- 1 | @propertyWrapper 2 | @dynamicMemberLookup 3 | public struct OptionalAttribute { 4 | 5 | public var base: AnyOptionalAttribute 6 | 7 | public init(base: AnyOptionalAttribute) { 8 | self.base = base 9 | } 10 | 11 | public init() { 12 | fatalError("not implemented") 13 | } 14 | 15 | public init(_ weakAttribute: WeakAttribute) { 16 | fatalError("not implemented") 17 | } 18 | 19 | public init(_ attribute: Attribute) { 20 | fatalError("not implemented") 21 | } 22 | 23 | public init(_ attribute: Attribute?) { 24 | fatalError("not implemented") 25 | } 26 | 27 | public var attribute: Attribute? { 28 | get { 29 | fatalError("not implemented") 30 | } 31 | set { 32 | fatalError("not implemented") 33 | } 34 | } 35 | 36 | public var value: Value? { 37 | fatalError("not implemented") 38 | } 39 | 40 | public func changedValue() -> (value: Value, changed: Bool)? { 41 | fatalError("not implemented") 42 | } 43 | 44 | public func map(_ transform: (Attribute) -> T) -> T? { 45 | fatalError("not implemented") 46 | } 47 | 48 | public var wrappedValue: Value? { 49 | fatalError("not implemented") 50 | } 51 | 52 | public var projectedValue: Attribute? { 53 | get { 54 | fatalError("not implemented") 55 | } 56 | set { 57 | fatalError("not implemented") 58 | } 59 | } 60 | 61 | public subscript(dynamicMember keyPath: KeyPath) -> Attribute? { 62 | fatalError("not implemented") 63 | } 64 | 65 | } 66 | 67 | extension OptionalAttribute: CustomStringConvertible { 68 | 69 | public var description: String { 70 | fatalError("not implemented") 71 | } 72 | 73 | } 74 | 75 | extension OptionalAttribute: Equatable { 76 | 77 | public static func == (_ lhs: OptionalAttribute, _ rhs: OptionalAttribute) -> Bool { 78 | return lhs.base == rhs.base 79 | } 80 | 81 | } 82 | 83 | extension OptionalAttribute: Hashable { 84 | 85 | public func hash(into hasher: inout Hasher) { 86 | hasher.combine(base) 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/PointerOffset.swift: -------------------------------------------------------------------------------- 1 | public struct PointerOffset { 2 | 3 | public var byteOffset: Int 4 | 5 | public init(byteOffset: Int) { 6 | self.byteOffset = byteOffset 7 | } 8 | 9 | public static func of(_ member: inout Member) -> PointerOffset { 10 | fatalError("not implemented") 11 | } 12 | 13 | public static func offset(_ body: (inout Base) -> PointerOffset) -> PointerOffset { 14 | fatalError("not implemented") 15 | } 16 | 17 | public static func invalidScenePointer() -> UnsafeMutablePointer { 18 | fatalError("not implemented") 19 | } 20 | 21 | } 22 | 23 | extension PointerOffset where Base == Member { 24 | 25 | public init() { 26 | self.byteOffset = 0 27 | } 28 | 29 | } 30 | 31 | extension PointerOffset { 32 | 33 | public static func + (_ lhs: PointerOffset, _ rhs: PointerOffset) -> PointerOffset< 34 | Base, Member 35 | > { 36 | return PointerOffset(byteOffset: lhs.byteOffset + rhs.byteOffset) 37 | } 38 | 39 | } 40 | 41 | extension UnsafePointer { 42 | 43 | public static func + (_ lhs: UnsafePointer, _ rhs: PointerOffset) 44 | -> UnsafePointer< 45 | Member 46 | > 47 | { 48 | return UnsafeRawPointer(lhs) 49 | .advanced(by: rhs.byteOffset) 50 | .assumingMemoryBound(to: Member.self) 51 | } 52 | 53 | public subscript(offset: PointerOffset) -> Member { 54 | unsafeAddress { 55 | return UnsafeRawPointer(self) 56 | .advanced(by: offset.byteOffset) 57 | .assumingMemoryBound(to: Member.self) 58 | } 59 | } 60 | 61 | } 62 | 63 | extension UnsafeMutablePointer { 64 | 65 | public static func + ( 66 | _ lhs: UnsafeMutablePointer, 67 | _ rhs: PointerOffset 68 | ) -> UnsafeMutablePointer { 69 | return UnsafeMutableRawPointer(lhs) 70 | .advanced(by: rhs.byteOffset) 71 | .assumingMemoryBound(to: Member.self) 72 | } 73 | 74 | public subscript(offset offset: PointerOffset) -> Member { 75 | unsafeAddress { 76 | return UnsafeRawPointer(self) 77 | .advanced(by: offset.byteOffset) 78 | .assumingMemoryBound(to: Member.self) 79 | } 80 | unsafeMutableAddress { 81 | return UnsafeMutableRawPointer(self) 82 | .advanced(by: offset.byteOffset) 83 | .assumingMemoryBound(to: Member.self) 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Rule/AnyRuleContext.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct AnyRuleContext { 4 | 5 | public var attribute: AnyAttribute 6 | 7 | public init(attribute: AnyAttribute) { 8 | self.attribute = attribute 9 | } 10 | 11 | public init(_ ruleContext: RuleContext) { 12 | fatalError("not implemented") 13 | } 14 | 15 | public func unsafeCast(to type: Value.Type) -> RuleContext { 16 | fatalError("not implemented") 17 | } 18 | 19 | public func update(body: () -> Void) { 20 | fatalError("not implemented") 21 | } 22 | 23 | public func changedValue(of attribute: Attribute, options: ValueOptions) -> ( 24 | value: Value, changed: Bool 25 | ) { 26 | fatalError("not implemented") 27 | } 28 | 29 | public func valueAndFlags(of attribute: Attribute, options: ValueOptions) -> ( 30 | value: Value, flags: ChangedValueFlags 31 | ) { 32 | fatalError("not implemented") 33 | } 34 | 35 | public subscript(_ attribute: Attribute) -> Value { 36 | unsafeAddress { 37 | fatalError("not implemented") 38 | } 39 | } 40 | 41 | public subscript(_ weakAttribute: WeakAttribute) -> Value? { 42 | fatalError("not implemented") 43 | } 44 | 45 | public subscript(_ optionalAttribute: OptionalAttribute) -> Value? { 46 | fatalError("not implemented") 47 | } 48 | 49 | } 50 | 51 | extension AnyRuleContext: Equatable { 52 | 53 | public static func == (_ lhs: AnyRuleContext, _ rhs: AnyRuleContext) -> Bool { 54 | return lhs.attribute == rhs.attribute 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Rule/Rule.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public protocol Rule: _AttributeBody { 4 | 5 | associatedtype Value 6 | 7 | var value: Value { get } 8 | static var initialValue: Value? { get } 9 | 10 | } 11 | 12 | extension Rule { 13 | 14 | public static var initialValue: Value? { 15 | return nil 16 | } 17 | 18 | public static func _updateDefault(_ self: UnsafeMutableRawPointer) { 19 | fatalError("not implemented") 20 | 21 | } 22 | 23 | public static func _update(_ self: UnsafeMutableRawPointer, attribute: AnyAttribute) { 24 | fatalError("not implemented") 25 | } 26 | 27 | } 28 | 29 | extension Rule { 30 | 31 | public var bodyChanged: Bool { 32 | fatalError("not implemented") 33 | } 34 | 35 | public var attribute: Attribute { 36 | fatalError("not implemented") 37 | } 38 | 39 | public var context: RuleContext { 40 | fatalError("not implemented") 41 | } 42 | 43 | } 44 | 45 | public struct CachedValueOptions {} 46 | 47 | extension Rule where Value: Hashable { 48 | 49 | public func cachedValue(options: CachedValueOptions, owner: AnyAttribute?) -> Value { 50 | fatalError("not implemented") 51 | } 52 | 53 | public func cachedValueIfExists(options: CachedValueOptions, owner: AnyAttribute?) -> Value? { 54 | fatalError("not implemented") 55 | } 56 | 57 | public static func _cachedValue( 58 | options: CachedValueOptions, owner: AnyAttribute?, hashValue: Int, bodyPtr: UnsafeRawPointer, 59 | update: () -> (UnsafeMutableRawPointer, AnyAttribute) -> Void 60 | ) -> UnsafePointer { 61 | fatalError("not implemented") 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Rule/RuleContext.swift: -------------------------------------------------------------------------------- 1 | public struct RuleContext { 2 | 3 | public var attribute: Attribute 4 | 5 | public init(attribute: Attribute) { 6 | self.attribute = attribute 7 | } 8 | 9 | public func update(body: () -> Void) { 10 | fatalError("not implemented") 11 | } 12 | 13 | public var value: Value { 14 | unsafeAddress { 15 | fatalError("not implemented") 16 | } 17 | set { 18 | fatalError("not implemented") 19 | } 20 | } 21 | 22 | public var hasValue: Bool { 23 | fatalError("not implemented") 24 | } 25 | 26 | public func changedValue(of attribute: Attribute, options: ValueOptions) -> (value: Value, changed: Bool) { 27 | fatalError("not implemented") 28 | } 29 | 30 | public func valueAndFlags(of attribute: Attribute, options: ValueOptions) -> ( 31 | value: Value, flags: ChangedValueFlags 32 | ) { 33 | fatalError("not implemented") 34 | } 35 | 36 | public subscript(_ attribute: Attribute) -> T { 37 | unsafeAddress { 38 | fatalError("not implemented") 39 | } 40 | } 41 | 42 | public subscript(_ weakAttribute: WeakAttribute) -> T? { 43 | fatalError("not implemented") 44 | } 45 | 46 | public subscript(_ optionalAttribute: OptionalAttribute) -> T? { 47 | fatalError("not implemented") 48 | } 49 | 50 | } 51 | 52 | extension RuleContext: Equatable { 53 | 54 | public static func == (_ lhs: RuleContext, _ rhs: RuleContext) -> Bool { 55 | return lhs.attribute == rhs.attribute 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Rule/StatefulRule.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public protocol StatefulRule: _AttributeBody { 4 | 5 | associatedtype Value 6 | 7 | static var initialValue: Value? { get } 8 | func updateValue() 9 | 10 | } 11 | 12 | extension StatefulRule { 13 | 14 | public static var initialValue: Value? { 15 | return nil 16 | } 17 | 18 | public static func _updateDefault(_ default: UnsafeMutableRawPointer) { 19 | fatalError("not implemented") 20 | } 21 | } 22 | 23 | extension StatefulRule { 24 | 25 | public static func _update(_ body: UnsafeMutableRawPointer, attribute: AnyAttribute) { 26 | fatalError("not implemented") 27 | } 28 | 29 | public var bodyChanged: Bool { 30 | fatalError("not implemented") 31 | } 32 | 33 | public var value: Value { 34 | unsafeAddress { 35 | fatalError("not implemented") 36 | } 37 | set { 38 | fatalError("not implemented") 39 | } 40 | } 41 | 42 | public var hasValue: Bool { 43 | fatalError("not implemented") 44 | } 45 | 46 | public var attribute: Attribute { 47 | fatalError("not implemented") 48 | } 49 | 50 | public var context: RuleContext { 51 | fatalError("not implemented") 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Weak/AnyWeakAttribute.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct AnyWeakAttribute { 4 | 5 | public init(_ attribute: WeakAttribute) { 6 | fatalError("not implemented") 7 | } 8 | 9 | public init(_ attribute: AnyAttribute?) { 10 | fatalError("not implemented") 11 | } 12 | 13 | public func unsafeCast(to type: Value.Type) -> WeakAttribute { 14 | fatalError("not implemented") 15 | } 16 | 17 | public var attribute: AnyAttribute? { 18 | get { 19 | fatalError("not implemented") 20 | } 21 | set { 22 | fatalError("not implemented") 23 | } 24 | } 25 | 26 | } 27 | 28 | extension AnyWeakAttribute: CustomStringConvertible { 29 | 30 | public var description: String { 31 | fatalError("not implemented") 32 | } 33 | 34 | } 35 | 36 | extension AnyWeakAttribute: Equatable { 37 | 38 | public static func == (lhs: AnyWeakAttribute, rhs: AnyWeakAttribute) -> Bool { 39 | fatalError("not implemented") 40 | } 41 | 42 | } 43 | 44 | extension AnyWeakAttribute: Hashable { 45 | 46 | public func hash(into hasher: inout Hasher) { 47 | fatalError("not implemented") 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Compute/Attribute/Weak/WeakAttribute.swift: -------------------------------------------------------------------------------- 1 | @propertyWrapper 2 | @dynamicMemberLookup 3 | public struct WeakAttribute { 4 | 5 | public var base: AnyWeakAttribute 6 | 7 | public init(base: AnyWeakAttribute) { 8 | self.base = base 9 | } 10 | 11 | public init() { 12 | fatalError("not implemented") 13 | } 14 | 15 | public init(_ attribute: Attribute) { 16 | fatalError("not implemented") 17 | } 18 | 19 | public init(_ attribute: Attribute?) { 20 | fatalError("not implemented") 21 | } 22 | 23 | public func changedValue(options: ValueOptions) -> (value: Value, changed: Bool)? { 24 | fatalError("not implemented") 25 | } 26 | 27 | public var value: Value? { 28 | fatalError("not implemented") 29 | } 30 | 31 | public var attribute: Attribute? { 32 | get { 33 | fatalError("not implemented") 34 | } 35 | set { 36 | fatalError("not implemented") 37 | } 38 | } 39 | 40 | public var wrappedValue: Value? { 41 | fatalError("not implemented") 42 | } 43 | 44 | public var projectedValue: Attribute? { 45 | get { 46 | fatalError("not implemented") 47 | } 48 | set { 49 | fatalError("not implemented") 50 | } 51 | } 52 | 53 | public subscript(dynamicMember keyPath: KeyPath) -> Attribute? { 54 | fatalError("not implemented") 55 | } 56 | 57 | } 58 | 59 | extension WeakAttribute: CustomStringConvertible { 60 | 61 | public var description: String { 62 | fatalError("not implemented") 63 | } 64 | 65 | } 66 | 67 | extension WeakAttribute: Equatable { 68 | 69 | public static func == (_ lhs: WeakAttribute, _ rhs: WeakAttribute) -> Bool { 70 | return lhs.base == rhs.base 71 | } 72 | 73 | } 74 | 75 | extension WeakAttribute: Hashable { 76 | 77 | public func hash(into hasher: inout Hasher) { 78 | hasher.combine(base) 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /Sources/Compute/Compute.swift: -------------------------------------------------------------------------------- 1 | @_exported import ComputeCxx 2 | -------------------------------------------------------------------------------- /Sources/Compute/Graph/Graph.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | extension Graph { 4 | 5 | public func onUpdate(_ handler: () -> Void) { 6 | fatalError("not implemented") 7 | } 8 | 9 | public func onInvalidation(_ handler: (AnyAttribute) -> Void) { 10 | fatalError("not implemented") 11 | } 12 | 13 | public func withDeadline(_ deadline: UInt64, _ body: () -> T) -> T { 14 | fatalError("not implemented") 15 | } 16 | 17 | public func withoutUpdate(_ body: () -> T) -> T { 18 | fatalError("not implemented") 19 | } 20 | 21 | public func withoutSubgraphInvalidation(_ body: () -> T) -> T { 22 | fatalError("not implemented") 23 | } 24 | 25 | public func withMainThreadHandler(_ body: (() -> Void) -> Void, do: () -> Void) { 26 | fatalError("not implemented") 27 | } 28 | 29 | } 30 | 31 | extension Graph { 32 | 33 | public static func startProfiling() { 34 | fatalError("not implemented") 35 | } 36 | 37 | public static func stopProfiling() { 38 | fatalError("not implemented") 39 | } 40 | 41 | public static func markProfile(name: UnsafePointer) { 42 | fatalError("not implemented") 43 | 44 | } 45 | 46 | public static func resetProfile() { 47 | fatalError("not implemented") 48 | } 49 | 50 | } 51 | 52 | extension Graph { 53 | 54 | public func addTraceEvent(_ event: UnsafePointer, value: T) { 55 | fatalError("not implemented") 56 | } 57 | 58 | public func addTraceEvent(_ event: UnsafePointer, context: UnsafePointer) { 59 | fatalError("not implemented") 60 | } 61 | 62 | } 63 | 64 | extension Graph { 65 | 66 | public func print(includeValues: Bool) { 67 | fatalError("not implemented") 68 | } 69 | 70 | public func archiveJSON(name: String?) { 71 | fatalError("not implemented") 72 | } 73 | 74 | public func graphvizDescription(includeValues: Bool) -> String { 75 | fatalError("not implemented") 76 | } 77 | 78 | public static func printStack(maxFrames: Int) { 79 | fatalError("not implemented") 80 | } 81 | 82 | public static func stackDescription(maxFrames: Int) -> String { 83 | fatalError("not implemented") 84 | } 85 | 86 | } 87 | 88 | extension Graph: @retroactive Equatable { 89 | 90 | public static func == (_ lhs: Graph, _ rhs: Graph) -> Bool { 91 | return lhs.counter(for: .contextID) == rhs.counter(for: .contextID) 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /Sources/Compute/Graph/Subgraph.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | extension Subgraph { 4 | 5 | public func addObserver(_ observer: () -> Void) -> Int { 6 | fatalError("not implemented") 7 | } 8 | 9 | public func apply(_ body: () -> T) -> T { 10 | fatalError("not implemented") 11 | } 12 | 13 | public func forEach(_ flags: AttributeFlags, _ body: (AnyAttribute) -> Void) { 14 | fatalError("not implemented") 15 | } 16 | 17 | } 18 | 19 | extension Subgraph { 20 | 21 | public func addTreeValue(_ attribute: Attribute, forKey key: UnsafePointer, flags: UInt32) { 22 | fatalError("not implemented") 23 | } 24 | 25 | public func beginTreeElement(value: Attribute, flags: UInt32) { 26 | fatalError("not implemented") 27 | } 28 | 29 | public func endTreeElement(value: Attribute) { 30 | fatalError("not implemented") 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Compute/Graph/TreeElement.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | public struct TreeElement {} 4 | 5 | extension TreeElement { 6 | 7 | public var value: AnyAttribute? { 8 | fatalError("not implemented") 9 | } 10 | 11 | } 12 | 13 | struct Nodes: Sequence, IteratorProtocol { 14 | 15 | public func next() -> AnyAttribute? { 16 | fatalError("not implemented") 17 | } 18 | 19 | } 20 | 21 | struct Children: Sequence, IteratorProtocol { 22 | 23 | public mutating func next() -> TreeElement? { 24 | fatalError("not implemented") 25 | } 26 | 27 | } 28 | 29 | struct Values: Sequence, IteratorProtocol { 30 | 31 | public func next() -> TreeElement? { 32 | fatalError("not implemented") 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Compute/Runtime/CompareValues.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | extension AGComparisonOptions { 4 | 5 | public init(mode: AGComparisonMode) { 6 | self.init(rawValue: UInt32(mode.rawValue)) 7 | } 8 | 9 | } 10 | 11 | public func compareValues(_ lhs: Value, _ rhs: Value, mode: AGComparisonMode = .equatableAlways) -> Bool { 12 | return compareValues(lhs, rhs, options: AGComparisonOptions(mode: mode)) 13 | } 14 | 15 | public func compareValues(_ lhs: Value, _ rhs: Value, options: AGComparisonOptions) -> Bool { 16 | return withUnsafePointer(to: lhs) { lhsPointer in 17 | return withUnsafePointer(to: rhs) { rhsPointer in 18 | return __AGCompareValues(lhsPointer, rhsPointer, Metadata(Value.self), options.union(.copyOnWrite)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Compute/Runtime/Enum.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | extension Metadata { 4 | 5 | @_extern(c, "AGTypeApplyEnumData") 6 | static func applyEnumData( 7 | type: Metadata, 8 | value: UnsafeRawPointer, 9 | body: (Int, Metadata, UnsafeRawPointer) -> Void 10 | ) -> Bool 11 | 12 | } 13 | 14 | public func withUnsafePointerToEnumCase( 15 | of enumValue: UnsafeMutablePointer, 16 | do body: (Int, Any.Type, UnsafeRawPointer) -> Void 17 | ) -> Bool { 18 | return Metadata.applyEnumData(type: Metadata(Value.self), value: enumValue) { tag, fieldType, fieldValue in 19 | body(tag, fieldType.type, fieldValue) 20 | } 21 | } 22 | 23 | @_extern(c, "AGTypeApplyMutableEnumData") 24 | func applyMutableEnumData( 25 | type: Metadata, 26 | value: UnsafeRawPointer, 27 | body: (Int, Metadata, UnsafeMutableRawPointer) -> Void 28 | ) -> Bool 29 | 30 | public func withUnsafeMutablePointerToEnumCase( 31 | of enumValue: UnsafeMutablePointer, 32 | do body: (Int, Any.Type, UnsafeMutableRawPointer) -> Void 33 | ) -> Bool { 34 | return applyMutableEnumData(type: Metadata(Value.self), value: enumValue) { tag, fieldType, fieldValue in 35 | body(tag, fieldType.type, fieldValue) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Compute/Runtime/Metadata.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | import Foundation 3 | 4 | extension Metadata { 5 | 6 | @_extern(c, "AGTypeApplyFields") 7 | static func applyFields(type: Metadata, body: (UnsafePointer, Int, Metadata) -> Void) 8 | 9 | } 10 | 11 | public func forEachField(of type: Any.Type, do body: (UnsafePointer, Int, Any.Type) -> Void) { 12 | Metadata.applyFields(type: Metadata(type)) { fieldName, fieldOffset, fieldType in 13 | body(fieldName, fieldOffset, fieldType.type) 14 | } 15 | } 16 | 17 | extension Metadata { 18 | 19 | public init(_ type: Any.Type) { 20 | self.init(rawValue: unsafeBitCast(type, to: OpaquePointer.self)) 21 | } 22 | 23 | public var type: Any.Type { 24 | return unsafeBitCast(rawValue, to: Any.Type.self) 25 | } 26 | 27 | @_extern(c, "AGTypeApplyFields2") 28 | static func applyFields2( 29 | type: Metadata, 30 | options: AGTypeApplyOptions, 31 | body: (UnsafePointer, Int, Metadata) -> Bool 32 | ) 33 | -> Bool 34 | 35 | public func forEachField(options: AGTypeApplyOptions, do body: (UnsafePointer, Int, Any.Type) -> Bool) 36 | -> Bool 37 | { 38 | return Metadata.applyFields2(type: self, options: options) { fieldName, fieldOffset, fieldType in 39 | return body(fieldName, fieldOffset, fieldType.type) 40 | } 41 | } 42 | 43 | } 44 | 45 | extension Metadata: @retroactive CustomStringConvertible { 46 | 47 | public var description: String { 48 | return __AGTypeDescription(self) as String 49 | } 50 | 51 | } 52 | 53 | extension Metadata: @retroactive Equatable {} 54 | 55 | extension Metadata: @retroactive Hashable {} 56 | -------------------------------------------------------------------------------- /Sources/Compute/Runtime/Signature.swift: -------------------------------------------------------------------------------- 1 | import ComputeCxx 2 | 3 | extension Signature: @retroactive Equatable { 4 | 5 | public static func == (_ lhs: Signature, _ rhs: Signature) -> Bool { 6 | return lhs.data.0 == rhs.data.0 && lhs.data.1 == rhs.data.1 && lhs.data.2 == rhs.data.2 7 | && lhs.data.3 == rhs.data.3 && lhs.data.4 == rhs.data.4 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Compute/Runtime/Tuple.swift: -------------------------------------------------------------------------------- 1 | public func withUnsafeTuple(of type: TupleType, count: Int, body: (UnsafeMutableTuple) -> Void) { 2 | return TupleType.withUnsafeTuple(of: type, count: count, body: body) 3 | } 4 | 5 | extension TupleType { 6 | 7 | @_extern(c, "AGTupleWithBuffer") 8 | fileprivate static func withUnsafeTuple(of type: TupleType, count: Int, body: (UnsafeMutableTuple) -> Void) 9 | 10 | public init(_ types: [Any.Type]) { 11 | self.init(count: UInt32(types.count), elements: types.map(Metadata.init)) 12 | } 13 | 14 | public init(_ type: Any.Type) { 15 | self.init(rawValue: unsafeBitCast(type, to: OpaquePointer.self)) 16 | } 17 | 18 | public var type: Any.Type { 19 | return unsafeBitCast(rawValue, to: Any.Type.self) 20 | } 21 | 22 | public var isEmpty: Bool { 23 | return count == 0 24 | } 25 | 26 | public var indices: Range { 27 | return 0.. Any.Type { 31 | return elementType(at: UInt32(index)).type 32 | } 33 | 34 | public func offset(at index: Int, as type: T.Type) -> Int { 35 | return elementOffset(at: UInt32(index), type: Metadata(type)) 36 | } 37 | 38 | public func getElement( 39 | in tupleValue: UnsafeMutableRawPointer, 40 | at index: Int, 41 | to destinationValue: UnsafeMutablePointer, 42 | options: CopyOptions 43 | ) { 44 | __AGTupleGetElement(self, tupleValue, UInt32(index), destinationValue, Metadata(T.self), options) 45 | } 46 | 47 | public func setElement( 48 | in tupleValue: UnsafeMutableRawPointer, 49 | at index: Int, 50 | from sourceValue: UnsafePointer, 51 | options: CopyOptions 52 | ) { 53 | __AGTupleSetElement(self, tupleValue, UInt32(index), sourceValue, Metadata(T.self), options) 54 | } 55 | 56 | } 57 | 58 | extension UnsafeTuple { 59 | 60 | public var count: Int { 61 | return type.count 62 | } 63 | 64 | public var isEmpty: Bool { 65 | return type.isEmpty 66 | } 67 | 68 | public var indices: Range { 69 | return type.indices 70 | } 71 | 72 | public func address(as expectedType: T.Type) -> UnsafePointer { 73 | guard type.type == expectedType else { 74 | preconditionFailure() 75 | } 76 | return value.assumingMemoryBound(to: expectedType) 77 | } 78 | 79 | public func address(of index: Int, as elementType: T.Type) -> UnsafePointer { 80 | return value.advanced(by: type.elementOffset(at: UInt32(index), type: Metadata(elementType))) 81 | .assumingMemoryBound(to: elementType) 82 | } 83 | 84 | public subscript() -> T { 85 | unsafeAddress { 86 | return address(as: T.self) 87 | } 88 | } 89 | 90 | public subscript(_ index: Int) -> T { 91 | unsafeAddress { 92 | return address(of: index, as: T.self) 93 | } 94 | } 95 | 96 | } 97 | 98 | extension UnsafeMutableTuple { 99 | 100 | public init(with tupleType: TupleType) { 101 | self.init( 102 | type: tupleType, 103 | value: UnsafeMutableRawPointer.allocate( 104 | byteCount: tupleType.size, 105 | alignment: -1 106 | ) 107 | ) 108 | } 109 | 110 | public func deallocate(initialized: Bool) { 111 | if initialized { 112 | deinitialize() 113 | } 114 | value.deallocate() 115 | } 116 | 117 | public func initialize(at index: Int, to element: T) { 118 | withUnsafePointer(to: element) { elementPointer in 119 | type.setElement(in: value, at: index, from: elementPointer, options: .initCopy) 120 | } 121 | } 122 | 123 | public func deinitialize() { 124 | type.destroy(value) 125 | } 126 | 127 | public func deinitialize(at index: Int) { 128 | type.destroy(value, at: UInt32(index)) 129 | } 130 | 131 | public var count: Int { 132 | return type.count 133 | } 134 | 135 | public var isEmpty: Bool { 136 | return type.isEmpty 137 | } 138 | 139 | public var indices: Range { 140 | return type.indices 141 | } 142 | 143 | public func address(as expectedType: T.Type) -> UnsafeMutablePointer { 144 | guard type.type == expectedType else { 145 | preconditionFailure() 146 | } 147 | return value.assumingMemoryBound(to: expectedType) 148 | } 149 | 150 | public func address(of index: Int, as elementType: T.Type) -> UnsafeMutablePointer { 151 | return value.advanced(by: type.elementOffset(at: UInt32(index), type: Metadata(elementType))) 152 | .assumingMemoryBound(to: elementType) 153 | } 154 | 155 | public subscript() -> T { 156 | unsafeAddress { 157 | return UnsafePointer(address(as: T.self)) 158 | } 159 | nonmutating unsafeMutableAddress { 160 | return address(as: T.self) 161 | } 162 | } 163 | 164 | public subscript(_ index: Int) -> T { 165 | unsafeAddress { 166 | return UnsafePointer(address(of: index, as: T.self)) 167 | } 168 | nonmutating unsafeMutableAddress { 169 | return address(of: index, as: T.self) 170 | } 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/AGSwiftSupport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if __has_attribute(swift_private) 4 | # define AG_REFINED_FOR_SWIFT __attribute__((swift_private)) 5 | #else 6 | # define AG_REFINED_FOR_SWIFT 7 | #endif 8 | 9 | 10 | #if __has_attribute(swift_name) 11 | # define AG_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) 12 | #else 13 | # define AG_SWIFT_NAME(_name) 14 | #endif 15 | 16 | #if __has_attribute(swift_wrapper) 17 | #define AG_SWIFT_STRUCT __attribute__((swift_wrapper(struct))) 18 | #else 19 | #define AG_SWIFT_STRUCT 20 | #endif 21 | 22 | // Define mappings for calling conventions. 23 | 24 | // Annotation for specifying a calling convention of 25 | // a runtime function. It should be used with declarations 26 | // of runtime functions like this: 27 | // void runtime_function_name() AG_SWIFT_CC(swift) 28 | #define AG_SWIFT_CC(CC) AG_SWIFT_CC_##CC 29 | 30 | // AG_SWIFT_CC(c) is the C calling convention. 31 | #define AG_SWIFT_CC_c 32 | 33 | // AG_SWIFT_CC(swift) is the Swift calling convention. 34 | #if __has_attribute(swiftcall) 35 | #define AG_SWIFT_CC_swift __attribute__((swiftcall)) 36 | #define AG_SWIFT_CONTEXT __attribute__((swift_context)) 37 | #define AG_SWIFT_ERROR_RESULT __attribute__((swift_error_result)) 38 | #define AG_SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) 39 | #else 40 | #define AG_SWIFT_CC_swift 41 | #define AG_SWIFT_CONTEXT 42 | #define AG_SWIFT_ERROR_RESULT 43 | #define AG_SWIFT_INDIRECT_RESULT 44 | #endif 45 | 46 | #if __has_attribute(swift_async_context) 47 | #define AG_SWIFT_ASYNC_CONTEXT __attribute__((swift_async_context)) 48 | #else 49 | #define AG_SWIFT_ASYNC_CONTEXT 50 | #endif 51 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeData/Node/IndirectNode.cpp: -------------------------------------------------------------------------------- 1 | #include "IndirectNode.h" 2 | 3 | #include 4 | 5 | namespace AG { 6 | 7 | const MutableIndirectNode &IndirectNode::to_mutable() const { 8 | assert(is_mutable()); 9 | return static_cast(*this); 10 | } 11 | 12 | void IndirectNode::modify(WeakAttributeID source, size_t size) { 13 | _source = source; 14 | _info.size = uint32_t(size); 15 | } 16 | 17 | } // namespace AG 18 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeData/Node/IndirectNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Attribute/AttributeID/AttributeID.h" 6 | #include "Attribute/AttributeID/WeakAttributeID.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | 12 | class MutableIndirectNode; 13 | 14 | class IndirectNode { 15 | private: 16 | struct Info { 17 | unsigned int is_mutable : 1; 18 | unsigned int traverses_graph_contexts : 1; 19 | unsigned int offset : 30; 20 | unsigned int size : 32; 21 | }; 22 | static_assert(sizeof(Info) == 8); 23 | static constexpr uint32_t InvalidSize = 0xffff; 24 | 25 | WeakAttributeID _source; 26 | Info _info; 27 | 28 | public: 29 | bool is_mutable() const { return _info.is_mutable; }; 30 | const MutableIndirectNode &to_mutable() const; 31 | 32 | bool traverses_graph_contexts() const { return _info.traverses_graph_contexts; }; 33 | 34 | uint32_t offset() const { return _info.offset; }; 35 | std::optional size() const { 36 | return _info.size != InvalidSize ? std::optional(size_t(_info.size)) : std::optional(); 37 | }; 38 | 39 | const WeakAttributeID &source() const { return _source; }; 40 | 41 | void modify(WeakAttributeID source, size_t size); 42 | }; 43 | 44 | class MutableIndirectNode : public IndirectNode { 45 | private: 46 | AttributeID _dependency; 47 | 48 | public: 49 | const AttributeID &dependency() const { return _dependency; }; 50 | }; 51 | 52 | } // namespace AG 53 | 54 | CF_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeData/Node/Node.cpp: -------------------------------------------------------------------------------- 1 | #include "Node.h" 2 | 3 | #include "Attribute/AttributeType/AttributeType.h" 4 | #include "Data/Pointer.h" 5 | #include "Data/Zone.h" 6 | #include "Graph/Graph.h" 7 | #include "Swift/Metadata.h" 8 | 9 | namespace AG { 10 | 11 | void *Node::get_self(const AttributeType &type) { 12 | void *self = ((char *)this + type.body_offset()); 13 | if (_flags & Flags::HasIndirectSelf) { 14 | self = *(void **)self; 15 | } 16 | return self; 17 | } 18 | 19 | void Node::update_self(const Graph &graph, void *new_self) { 20 | auto type = graph.attribute_type(_type_id); 21 | void *self = get_self(type); 22 | 23 | if (!_state.is_self_initialized()) { 24 | _state = _state.with_self_initialized(true); 25 | type.body_metadata().vw_initializeWithCopy(static_cast(self), 26 | static_cast(new_self)); 27 | } else { 28 | type.body_metadata().vw_assignWithCopy(static_cast(self), 29 | static_cast(new_self)); 30 | } 31 | } 32 | 33 | void Node::destroy_self(const Graph &graph) { 34 | if (!_state.is_self_initialized()) { 35 | return; 36 | } 37 | _state = _state.with_self_initialized(false); 38 | 39 | auto type = graph.attribute_type(_type_id); 40 | type.destroy_body(*this); 41 | type.destroy(*this); 42 | } 43 | 44 | void *Node::get_value() { 45 | void *value = _value.get(); 46 | if (_flags & Flags::HasIndirectValue) { 47 | value = *(void **)value; 48 | } 49 | return value; 50 | } 51 | 52 | void Node::allocate_value(Graph &graph, data::zone &zone) { 53 | if (_value) { 54 | return; 55 | } 56 | 57 | auto type = graph.attribute_type(_type_id); 58 | size_t size = type.value_metadata().vw_size(); 59 | size_t alignment_mask = type.value_metadata().getValueWitnesses()->getAlignmentMask(); 60 | 61 | if (_flags & Flags::HasIndirectValue) { 62 | _value = zone.alloc_bytes_recycle(sizeof(void *), sizeof(void *) - 1); 63 | void *persistent_buffer = zone.alloc_persistent(size); 64 | *_value.unsafe_cast().get() = persistent_buffer; 65 | } else { 66 | if (size <= 0x10) { 67 | _value = zone.alloc_bytes_recycle(uint32_t(size), uint32_t(alignment_mask)); 68 | } else { 69 | _value = zone.alloc_bytes(uint32_t(size), uint32_t(alignment_mask)); 70 | } 71 | } 72 | 73 | graph.did_allocate_node_value(size); 74 | } 75 | 76 | void Node::destroy_value(Graph &graph) { 77 | if (!_state.is_value_initialized()) { 78 | return; 79 | } 80 | _state = _state.with_value_initialized(false); 81 | 82 | auto type = graph.attribute_type(_type_id); 83 | void *value = get_value(); 84 | 85 | type.value_metadata().vw_destroy(static_cast(value)); 86 | } 87 | 88 | void Node::destroy(Graph &graph) { 89 | auto type = graph.attribute_type(_type_id); 90 | 91 | if (_state.is_value_initialized()) { 92 | void *value = get_value(); 93 | type.value_metadata().vw_destroy(static_cast(value)); 94 | } 95 | if (_value) { 96 | graph.did_destroy_node_value(type.value_metadata().vw_size()); 97 | } 98 | 99 | if (_state.is_self_initialized()) { 100 | type.destroy_body(*this); 101 | type.destroy(*this); 102 | } 103 | } 104 | 105 | } // namespace AG 106 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeData/Node/Node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Data/Pointer.h" 6 | 7 | CF_ASSUME_NONNULL_BEGIN 8 | 9 | namespace AG { 10 | 11 | namespace data { 12 | class zone; 13 | } 14 | class AttributeType; 15 | class Graph; 16 | 17 | class Node { 18 | private: 19 | class State { 20 | public: 21 | enum : uint8_t { 22 | ValueInitialized = 1 << 4, 23 | SelfInitialized = 1 << 5, 24 | }; 25 | 26 | private: 27 | uint8_t _data; 28 | explicit constexpr State(uint8_t data) : _data(data) {}; 29 | 30 | public: 31 | bool is_value_initialized() { return _data & ValueInitialized; }; 32 | State with_value_initialized(bool value) const { 33 | return State((_data & ~ValueInitialized) | (value ? ValueInitialized : 0)); 34 | }; 35 | 36 | bool is_self_initialized() { return _data & SelfInitialized; }; 37 | State with_self_initialized(bool value) const { 38 | return State((_data & ~SelfInitialized) | (value ? SelfInitialized : 0)); 39 | }; 40 | }; 41 | 42 | enum Flags : uint8_t { 43 | HasIndirectSelf = 1 << 0, 44 | HasIndirectValue = 1 << 1, 45 | }; 46 | 47 | State _state; 48 | unsigned int _type_id : 24; 49 | uint16_t _relative_offset; 50 | uint8_t _subgraph_flags; 51 | Flags _flags; 52 | data::ptr _value; 53 | 54 | uint32_t _padding1; 55 | uint16_t _padding2; 56 | uint32_t _padding4; 57 | uint16_t _padding5; 58 | 59 | public: 60 | uint32_t type_id() const { return _type_id; }; 61 | 62 | void *get_self(const AttributeType &type); 63 | void update_self(const Graph &graph, void *new_self); 64 | void destroy_self(const Graph &graph); 65 | 66 | void *get_value(); 67 | void allocate_value(Graph &graph, data::zone &zone); 68 | void destroy_value(Graph &graph); 69 | 70 | void destroy(Graph &graph); 71 | }; 72 | 73 | static_assert(sizeof(Node) == 0x1c); 74 | 75 | } // namespace AG 76 | 77 | CF_ASSUME_NONNULL_END 78 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeID/AGAttribute.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AGSwiftSupport.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | CF_EXTERN_C_BEGIN 11 | 12 | typedef uint32_t AGAttribute AG_SWIFT_STRUCT AG_SWIFT_NAME(AnyAttribute); 13 | 14 | CF_EXTERN_C_END 15 | 16 | CF_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeID/AttributeID.cpp: -------------------------------------------------------------------------------- 1 | #include "AttributeID.h" 2 | 3 | #include "Errors/Errors.h" 4 | 5 | #include "Attribute/AttributeData/Node/IndirectNode.h" 6 | #include "Attribute/AttributeData/Node/Node.h" 7 | #include "Attribute/AttributeType/AttributeType.h" 8 | #include "Graph/Graph.h" 9 | #include "OffsetAttributeID.h" 10 | #include "Subgraph/Subgraph.h" 11 | 12 | namespace AG { 13 | 14 | std::optional AttributeID::size() const { 15 | if (is_direct()) { 16 | const AttributeType &attribute_type = subgraph()->graph()->attribute_type(to_node().type_id()); 17 | size_t size = attribute_type.value_metadata().vw_size(); 18 | return std::optional(size); 19 | } 20 | if (is_indirect()) { 21 | return to_indirect_node().size(); 22 | } 23 | return std::optional(); 24 | } 25 | 26 | bool AttributeID::traverses(AttributeID other, TraversalOptions options) const { 27 | if (!is_indirect()) { 28 | return *this == other; 29 | } 30 | 31 | if (with_kind(Kind::Indirect) == other) { 32 | return true; 33 | } 34 | 35 | auto indirect_node = to_indirect_node(); 36 | if (options & TraversalOptions::SkipMutableReference && indirect_node.is_mutable()) { 37 | return *this == other; 38 | } 39 | 40 | return indirect_node.source().attribute().traverses(other, options); 41 | } 42 | 43 | OffsetAttributeID AttributeID::resolve(TraversalOptions options) const { 44 | if (is_direct()) { 45 | return OffsetAttributeID(*this); 46 | } 47 | return resolve_slow(options); 48 | } 49 | 50 | OffsetAttributeID AttributeID::resolve_slow(TraversalOptions options) const { 51 | AttributeID result = *this; 52 | uint32_t offset = 0; 53 | while (result.is_indirect()) { 54 | if (offset == 0 && options & TraversalOptions::ReportIndirectionInOffset) { 55 | offset = 1; 56 | } 57 | 58 | auto indirect_node = to_indirect_node(); 59 | 60 | if (indirect_node.is_mutable()) { 61 | if (options & TraversalOptions::SkipMutableReference) { 62 | return OffsetAttributeID(result, offset); 63 | } 64 | 65 | if (options & TraversalOptions::UpdateDependencies) { 66 | AttributeID dependency = indirect_node.to_mutable().dependency(); 67 | if (dependency) { 68 | auto subgraph = dependency.subgraph(); 69 | if (subgraph) { 70 | subgraph->graph()->update_attribute(dependency, false); 71 | } 72 | } 73 | } 74 | } 75 | 76 | if (options && TraversalOptions::EvaluateWeakReferences) { 77 | if (indirect_node.source().expired()) { 78 | if (options & TraversalOptions::AssertNotNil) { 79 | precondition_failure("invalid indirect ref: %u", _value); 80 | } 81 | return OffsetAttributeID(AttributeID::make_nil()); 82 | } 83 | } 84 | 85 | offset += indirect_node.offset(); 86 | result = indirect_node.source().attribute(); 87 | } 88 | 89 | if (options & TraversalOptions::AssertNotNil && !is_direct()) { 90 | precondition_failure("invalid attribute id: %u", _value); 91 | } 92 | 93 | return OffsetAttributeID(result, offset); 94 | } 95 | 96 | } // namespace AG 97 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeID/AttributeID.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Data/Page.h" 9 | #include "Data/Pointer.h" 10 | #include "Data/Zone.h" 11 | #include "Subgraph/Subgraph.h" 12 | 13 | CF_ASSUME_NONNULL_BEGIN 14 | 15 | namespace AG { 16 | 17 | class Subgraph; 18 | class Node; 19 | class IndirectNode; 20 | class OffsetAttributeID; 21 | 22 | class AttributeID { 23 | private: 24 | static constexpr uint32_t KindMask = 0x3; 25 | 26 | uint32_t _value; 27 | AttributeID(uint32_t value) : _value(value) {}; 28 | 29 | public: 30 | enum Kind : uint32_t { 31 | Direct = 0, 32 | Indirect = 1 << 0, 33 | NilAttribute = 1 << 1, 34 | }; 35 | enum TraversalOptions : uint32_t { 36 | None = 0, 37 | 38 | /// Updates indirect node dependencies prior to traversing. 39 | UpdateDependencies = 1 << 0, 40 | 41 | /// Guarantees the resolved attribute is not nil, otherwise traps. 42 | AssertNotNil = 1 << 1, 43 | 44 | /// When set, only statically evaluable references are traversed. 45 | /// The returned attribute may be a mutable indirect node. 46 | SkipMutableReference = 1 << 2, 47 | 48 | /// When set, the returned offset will be 0 if no indirection was traversed, 49 | /// otherwise it will be the the actual offset + 1. 50 | ReportIndirectionInOffset = 1 << 3, 51 | 52 | /// When set and `AssertNotNil` is not also set, returns the nil attribute 53 | /// if any weak references evaluate to nil. 54 | EvaluateWeakReferences = 1 << 4, 55 | }; 56 | 57 | explicit AttributeID(data::ptr node) : _value(node.offset() | Kind::Direct) {}; 58 | explicit AttributeID(data::ptr indirect_node) : _value(indirect_node.offset() | Kind::Indirect) {}; 59 | static AttributeID make_nil() { return AttributeID(Kind::NilAttribute); }; 60 | 61 | operator bool() const { return _value == 0; }; 62 | 63 | Kind kind() const { return Kind(_value & KindMask); }; 64 | AttributeID with_kind(Kind kind) const { return AttributeID((_value & ~KindMask) | kind); }; 65 | 66 | bool is_direct() const { return kind() == Kind::Direct; }; 67 | bool is_indirect() const { return kind() == Kind::Indirect; }; 68 | bool is_nil() const { return kind() == Kind::NilAttribute; }; 69 | 70 | const Node &to_node() const { 71 | assert(is_direct()); 72 | return *data::ptr(_value & ~KindMask); 73 | }; 74 | 75 | const IndirectNode &to_indirect_node() const { 76 | assert(is_indirect()); 77 | return *data::ptr(_value & ~KindMask); 78 | }; 79 | 80 | Subgraph *_Nullable subgraph() const { return static_cast(page_ptr()->zone); } 81 | 82 | data::ptr page_ptr() const { return data::ptr(_value).page_ptr(); }; 83 | 84 | // Value metadata 85 | std::optional size() const; 86 | 87 | // Graph traversal 88 | bool traverses(AttributeID other, TraversalOptions options) const; 89 | OffsetAttributeID resolve(TraversalOptions options) const; 90 | OffsetAttributeID resolve_slow(TraversalOptions options) const; 91 | }; 92 | 93 | } // namespace AG 94 | 95 | CF_ASSUME_NONNULL_END 96 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeID/OffsetAttributeID.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AttributeID.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | 12 | class OffsetAttributeID { 13 | private: 14 | AttributeID _attribute; 15 | uint32_t _offset; 16 | 17 | public: 18 | OffsetAttributeID(const AttributeID &attribute, uint32_t offset = 0) : _attribute(attribute), _offset(offset) {}; 19 | 20 | const AttributeID &attribute() { return _attribute; }; 21 | uint32_t offset() { return _offset; }; 22 | }; 23 | 24 | } // namespace AG 25 | 26 | CF_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeID/WeakAttributeID.cpp: -------------------------------------------------------------------------------- 1 | #include "WeakAttributeID.h" 2 | 3 | #include "AttributeID.h" 4 | #include "Data/Table.h" 5 | #include "Data/Zone.h" 6 | 7 | namespace AG { 8 | 9 | bool WeakAttributeID::expired() const { 10 | uint64_t raw_page_seed = data::table::shared().raw_page_seed(_attribute.page_ptr()); 11 | if (raw_page_seed & 0xff00000000) { 12 | auto zone_info = data::zone::info::from_raw_value(uint32_t(raw_page_seed)); 13 | if (zone_info.zone_id() == _zone_id) { 14 | return false; 15 | } 16 | } 17 | return true; 18 | } 19 | 20 | const AttributeID &WeakAttributeID::attribute() const { return _attribute; }; 21 | 22 | } // namespace AG 23 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeID/WeakAttributeID.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AttributeID.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | 12 | class WeakAttributeID { 13 | private: 14 | AttributeID _attribute; 15 | uint32_t _zone_id; 16 | 17 | public: 18 | bool expired() const; 19 | const AttributeID &attribute() const; 20 | }; 21 | 22 | } // namespace AG 23 | 24 | CF_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeType/AGAttributeType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Closure/AGClosure.h" 4 | #include "Swift/AGType.h" 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | CF_EXTERN_C_BEGIN 9 | 10 | struct AGAttributeType; 11 | 12 | typedef struct AGAttributeVTable { 13 | void (*callback0)(AGAttributeType *); 14 | void (*deallocate)(AGAttributeType *); 15 | 16 | void (*destroySelf)(const AGAttributeType *, void *); 17 | CFStringRef _Nonnull (*_Nonnull selfDescription)(const AGAttributeType *, void *); 18 | CFStringRef _Nonnull (*_Nonnull valueDescription)(const AGAttributeType *, void *); 19 | void (*_Nullable initializeValue)(const AGAttributeType *, void *); 20 | } AGAttributeVTable; 21 | 22 | typedef CF_OPTIONS(uint32_t, AGAttributeTypeFlags) { 23 | AGAttributeTypeFlagsComparisonModeMask = 0x03, 24 | 25 | AGAttributeTypeFlagsHasDestroySelf = 1 << 2, 26 | AGAttributeTypeFlagsMainThread = 1 << 3, 27 | AGAttributeTypeFlagsExternal = 1 << 4, 28 | AGAttributeTypeFlagsThreadSafe = 1 << 5, 29 | }; 30 | 31 | typedef struct AGAttributeType { 32 | AGTypeID selfType; 33 | AGTypeID valueType; 34 | AGClosureStorage update; 35 | const AGAttributeVTable *_Nullable callbacks; 36 | AGAttributeTypeFlags flags; 37 | 38 | uint32_t selfOffset; 39 | const unsigned char *_Nullable layout; 40 | 41 | AGTypeID initialSelfType; 42 | const void *initialAttributeBodyWitnessTable; 43 | } AGAttributeType; 44 | 45 | CF_EXTERN_C_END 46 | 47 | CF_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Attribute/AttributeType/AttributeType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGAttributeType.h" 6 | #include "Attribute/AttributeData/Node/Node.h" 7 | #include "Attribute/AttributeID/AGAttribute.h" 8 | #include "Comparison/AGComparison.h" 9 | #include "Comparison/LayoutDescriptor.h" 10 | #include "Swift/Metadata.h" 11 | 12 | CF_ASSUME_NONNULL_BEGIN 13 | 14 | namespace AG { 15 | 16 | class AttributeType { 17 | 18 | private: 19 | swift::metadata *_body_metadata; 20 | swift::metadata *_value_metadata; 21 | void (*_update)(const void *context, void *body, AGAttribute attribute); 22 | void *_update_context; 23 | const AGAttributeVTable *_callbacks; 24 | AGAttributeTypeFlags _flags; 25 | 26 | // set after construction 27 | uint32_t _body_offset; 28 | ValueLayout _layout; 29 | 30 | public: 31 | class deleter { 32 | public: 33 | void operator()(AttributeType *ptr) { 34 | if (ptr != nullptr) { 35 | auto callbacks = ptr->callbacks(); 36 | callbacks.deallocate(reinterpret_cast(ptr)); 37 | } 38 | } 39 | }; 40 | 41 | const swift::metadata &body_metadata() const { return *_body_metadata; }; 42 | const swift::metadata &value_metadata() const { return *_value_metadata; }; 43 | 44 | void update(void *body, AGAttribute attribute) const { _update(_update_context, body, attribute); }; 45 | 46 | const AGAttributeVTable &callbacks() const { return *_callbacks; } 47 | AGAttributeTypeFlags flags() const { return _flags; }; 48 | 49 | /// Returns the offset in bytes from a Node to the attribute body, 50 | /// aligned to the body's alignment. 51 | uint32_t body_offset() const { return _body_offset; }; 52 | void init_body_offset() { 53 | uint32_t alignment_mask = uint32_t(_body_metadata->getValueWitnesses()->getAlignmentMask()); 54 | _body_offset = (sizeof(Node) + alignment_mask) & ~alignment_mask; 55 | } 56 | 57 | void prefetch_layout() { 58 | AGComparisonMode comparison_mode = AGComparisonMode(_flags & AGAttributeTypeFlagsComparisonModeMask); 59 | _layout = LayoutDescriptor::fetch(value_metadata(), AGComparisonOptions(comparison_mode), 1); 60 | }; 61 | 62 | void destroy_body(Node &node) const { 63 | if (_flags & AGAttributeTypeFlagsHasDestroySelf) { 64 | void *body = node.get_self(*this); 65 | callbacks().destroySelf(reinterpret_cast(this), body); 66 | } 67 | } 68 | 69 | void destroy(Node &node) { 70 | void *body = node.get_self(*this); 71 | body_metadata().vw_destroy(static_cast(body)); 72 | } 73 | }; 74 | 75 | } // namespace AG 76 | 77 | CF_ASSUME_NONNULL_END 78 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Closure/AGClosure.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | CF_ASSUME_NONNULL_BEGIN 6 | 7 | struct AGClosureStorage { 8 | const void *function; 9 | const void *context; 10 | }; 11 | 12 | CF_ASSUME_NONNULL_END 13 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Closure/ClosureFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AGSwiftSupport.h" 7 | 8 | namespace AG { 9 | 10 | template class ClosureFunction { 11 | public: 12 | using Context = const void *_Nullable; 13 | using Function = AG_SWIFT_CC(swift) ReturnType (*_Nullable)(Context AG_SWIFT_CONTEXT, Args...); 14 | 15 | private: 16 | Function _function; 17 | Context _context; 18 | 19 | public: 20 | inline ClosureFunction(Function function, Context context) noexcept : _function(function), _context(context) { 21 | ::swift::swift_retain((::swift::HeapObject *)_context); 22 | } 23 | inline ClosureFunction() : _function(), _context() {} 24 | inline ClosureFunction(std::nullptr_t) : _function(nullptr), _context(nullptr) {} 25 | inline ~ClosureFunction() { ::swift::swift_release((::swift::HeapObject *)_context); } 26 | 27 | explicit operator bool() { return _function != nullptr; } 28 | 29 | const ReturnType operator()(Args... args) const noexcept { 30 | return _function(_context, std::forward(args)...); 31 | } 32 | }; 33 | 34 | template 35 | requires std::is_pointer_v 36 | using ClosureFunctionVP = ClosureFunction; 37 | 38 | } // namespace AG 39 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/AGComparison-Private.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGComparison.h" 6 | 7 | CF_ASSUME_NONNULL_BEGIN 8 | 9 | typedef struct AGComparisonStateStorage { 10 | const void *destination; 11 | const void *source; 12 | AGFieldRange field_range; 13 | AGTypeID field_type; 14 | } AGComparisonStateStorage; 15 | 16 | CF_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/AGComparison.cpp: -------------------------------------------------------------------------------- 1 | #include "AGComparison-Private.h" 2 | 3 | #include "Comparison/LayoutDescriptor.h" 4 | #include "Swift/ContextDescriptor.h" 5 | #include "Swift/Metadata.h" 6 | 7 | const void *AGComparisonStateGetDestination(AGComparisonState state) { return state->destination; } 8 | 9 | const void *AGComparisonStateGetSource(AGComparisonState state) { return state->source; } 10 | 11 | AGFieldRange AGComparisonStateGetFieldRange(AGComparisonState state) { return state->field_range; } 12 | 13 | AGTypeID AGComparisonStateGetFieldType(AGComparisonState state) { return state->field_type; } 14 | 15 | bool AGCompareValues(const void *destination, const void *source, AGTypeID type_id, AGComparisonOptions options) { 16 | auto type = reinterpret_cast(type_id); 17 | auto layout = AG::LayoutDescriptor::fetch(*type, options, 0); 18 | if (layout == AG::ValueLayoutTrivial) { 19 | layout = nullptr; 20 | } 21 | return AG::LayoutDescriptor::compare(layout, (const unsigned char *)destination, (const unsigned char *)source, 22 | type->vw_size(), options); 23 | } 24 | 25 | const unsigned char *AGPrefetchCompareValues(AGTypeID type_id, AGComparisonOptions options, uint32_t priority) { 26 | auto type = reinterpret_cast(type_id); 27 | return AG::LayoutDescriptor::fetch(*type, options, priority); 28 | } 29 | 30 | void AGOverrideComparisonForTypeDescriptor(void *descriptor, AGComparisonMode mode) { 31 | AG::LayoutDescriptor::add_type_descriptor_override( 32 | reinterpret_cast(descriptor), mode); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/AGComparison.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AGSwiftSupport.h" 7 | #include "Swift/AGType.h" 8 | 9 | CF_ASSUME_NONNULL_BEGIN 10 | 11 | CF_EXTERN_C_BEGIN 12 | 13 | struct AGFieldRange { 14 | size_t offset; 15 | size_t size; 16 | }; 17 | 18 | typedef struct AGComparisonStateStorage *AGComparisonState; 19 | 20 | CF_EXPORT 21 | CF_REFINED_FOR_SWIFT 22 | const void *AGComparisonStateGetDestination(AGComparisonState state); 23 | 24 | CF_EXPORT 25 | CF_REFINED_FOR_SWIFT 26 | const void *AGComparisonStateGetSource(AGComparisonState state); 27 | 28 | CF_EXPORT 29 | CF_REFINED_FOR_SWIFT 30 | AGFieldRange AGComparisonStateGetFieldRange(AGComparisonState state); 31 | 32 | CF_EXPORT 33 | CF_REFINED_FOR_SWIFT 34 | AGTypeID AGComparisonStateGetFieldType(AGComparisonState state); 35 | 36 | typedef CF_ENUM(uint8_t, AGComparisonMode) { 37 | AGComparisonModeBitwise = 0, 38 | AGComparisonModeIndirect = 1, 39 | AGComparisonModeEquatableUnlessPOD = 2, 40 | AGComparisonModeEquatableAlways = 3, 41 | }; 42 | 43 | typedef CF_OPTIONS(uint32_t, AGComparisonOptions) { 44 | AGComparisonOptionsComparisonModeMask = 0xff, 45 | 46 | AGComparisonOptionsCopyOnWrite = 1 << 8, 47 | AGComparisonOptionsFetchLayoutsSynchronously = 1 << 9, 48 | AGComparisonOptionsReportFailures = 1ul << 31, // -1 signed int 49 | }; 50 | 51 | CF_EXPORT 52 | CF_REFINED_FOR_SWIFT 53 | bool AGCompareValues(const void *destination, const void *source, AGTypeID type_id, AGComparisonOptions options); 54 | 55 | CF_EXPORT 56 | CF_REFINED_FOR_SWIFT 57 | const unsigned char *_Nullable AGPrefetchCompareValues(AGTypeID type_id, AGComparisonOptions options, 58 | uint32_t priority); 59 | 60 | CF_EXPORT 61 | CF_REFINED_FOR_SWIFT 62 | void AGOverrideComparisonForTypeDescriptor(void *descriptor, AGComparisonMode mode); 63 | 64 | CF_EXTERN_C_END 65 | 66 | CF_ASSUME_NONNULL_END 67 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/Builder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGComparison.h" 6 | #include "LayoutDescriptor.h" 7 | #include "Swift/MetadataVisitor.h" 8 | #include "Vector/Vector.h" 9 | 10 | CF_ASSUME_NONNULL_BEGIN 11 | 12 | namespace AG { 13 | namespace LayoutDescriptor { 14 | 15 | class Builder : public swift::metadata_visitor { 16 | public: 17 | struct RangeItem { 18 | size_t offset; 19 | size_t size; 20 | }; 21 | struct DataItem : RangeItem {}; 22 | struct EqualsItem : RangeItem { 23 | const swift::metadata *type; 24 | const swift::equatable_witness_table *equatable; 25 | }; 26 | struct IndirectItem : RangeItem { 27 | const swift::metadata *type; 28 | }; 29 | struct ExistentialItem : RangeItem { 30 | const swift::existential_type_metadata *type; 31 | }; 32 | struct HeapRefItem : RangeItem { 33 | bool is_function; 34 | }; 35 | struct NestedItem : RangeItem { 36 | ValueLayout layout; 37 | }; 38 | struct EnumItem : RangeItem { 39 | struct Case { 40 | uint64_t item_index; 41 | size_t offset; 42 | vector, 43 | 0, uint64_t> 44 | children; 45 | }; 46 | 47 | const swift::metadata *type; 48 | vector cases; 49 | }; 50 | using Item = std::variant; 51 | 52 | // Emitter 53 | 54 | template class Emitter { 55 | private: 56 | T *_Nonnull _data; 57 | size_t _emitted_size = 0; 58 | bool _invalid = false; 59 | 60 | public: 61 | void operator()(const DataItem &item); 62 | void operator()(const EqualsItem &item); 63 | void operator()(const IndirectItem &item); 64 | void operator()(const ExistentialItem &item); 65 | void operator()(const HeapRefItem &item); 66 | void operator()(const NestedItem &item); 67 | void operator()(const EnumItem &item); 68 | void enter(const RangeItem &range_item); 69 | 70 | const vector &data() const { return *_data; }; 71 | size_t emitted_size() const { return _emitted_size; }; 72 | bool is_invalid() const { return _invalid; }; 73 | void set_invalid(bool invalid) { _invalid = invalid; }; 74 | 75 | void finish(); 76 | }; 77 | 78 | template <> class Emitter> { 79 | private: 80 | vector *_Nonnull _data; 81 | size_t _emitted_size = 0; 82 | bool _invalid = false; 83 | 84 | public: 85 | Emitter(vector *data); 86 | 87 | void operator()(const DataItem &item); 88 | void operator()(const EqualsItem &item); 89 | void operator()(const IndirectItem &item); 90 | void operator()(const ExistentialItem &item); 91 | void operator()(const HeapRefItem &item); 92 | void operator()(const NestedItem &item); 93 | void operator()(const EnumItem &item); 94 | void enter(const RangeItem &range_item); 95 | 96 | const vector &data() const { return *_data; }; 97 | size_t emitted_size() const { return _emitted_size; }; 98 | bool is_invalid() const { return _invalid; }; 99 | void set_invalid(bool invalid) { _invalid = invalid; }; 100 | 101 | void finish(); 102 | 103 | template void emit_value(value_t value) { 104 | // TODO: make not set to zero before overwriting 105 | uint64_t size = _data->size(); 106 | _data->resize(size + sizeof(value_t), 0); 107 | unsigned char *type_pointer = &(*_data)[size]; 108 | *(value_t *)type_pointer = value; 109 | } 110 | }; 111 | 112 | private: 113 | static os_unfair_lock _lock; 114 | static size_t _avail; 115 | static unsigned char *_buffer; 116 | static void lock() { os_unfair_lock_lock(&_lock); }; 117 | static void unlock() { os_unfair_lock_unlock(&_lock); }; 118 | 119 | AGComparisonMode _current_comparison_mode; 120 | HeapMode _heap_mode; 121 | size_t _current_offset = 0; 122 | uint64_t _enum_case_depth = 0; 123 | EnumItem::Case *_current_enum_case = nullptr; 124 | vector _items; 125 | 126 | public: 127 | Builder(AGComparisonMode comparison_mode, HeapMode heap_mode) 128 | : _current_comparison_mode(comparison_mode), _heap_mode(heap_mode) {} 129 | 130 | size_t current_offset() { return _current_offset; }; 131 | AGComparisonMode current_comparison_mode() { return _current_comparison_mode; }; 132 | vector &get_items() { 133 | return _current_enum_case != nullptr ? _current_enum_case->children : _items; 134 | }; 135 | 136 | ValueLayout commit(const swift::metadata &type); 137 | 138 | void add_field(size_t field_size); 139 | bool should_visit_fields(const swift::metadata &type, bool flag); 140 | 141 | struct RevertItemsInfo { 142 | uint64_t item_index; 143 | DataItem data_item; 144 | }; 145 | 146 | void revert(const RevertItemsInfo &info); 147 | 148 | virtual bool visit_element(const swift::metadata &type, const swift::metadata::ref_kind kind, size_t element_offset, 149 | size_t element_size) override; 150 | 151 | virtual bool visit_case(const swift::metadata &type, const swift::field_record &field, uint32_t arg) override; 152 | virtual bool visit_existential(const swift::existential_type_metadata &type) override; 153 | virtual bool visit_function(const swift::function_type_metadata &type) override; 154 | virtual bool visit_native_object(const swift::metadata &type) override; 155 | }; 156 | 157 | } // namespace LayoutDescriptor 158 | } // namespace AG 159 | 160 | CF_ASSUME_NONNULL_END 161 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/Compare.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "LayoutDescriptor.h" 4 | 5 | #include "AGComparison.h" 6 | #include "Vector/Vector.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | namespace LayoutDescriptor { 12 | 13 | class Compare { 14 | public: 15 | struct Enum { 16 | enum Mode : uint32_t { 17 | Unmanaged = 0, 18 | Managed = 1, 19 | }; 20 | 21 | const swift::metadata *type; 22 | unsigned int enum_tag; 23 | const unsigned char *lhs; 24 | const unsigned char *rhs; 25 | const unsigned char *lhs_copy; 26 | const unsigned char *rhs_copy; 27 | size_t offset; 28 | Mode mode; 29 | bool owns_copies; 30 | 31 | Enum() 32 | : type(nullptr), enum_tag(0), lhs(nullptr), rhs(nullptr), lhs_copy(nullptr), rhs_copy(nullptr), offset(0), 33 | mode(Mode::Unmanaged), owns_copies(false) {}; 34 | Enum(const swift::metadata *type, Mode mode, unsigned int enum_tag, size_t offset, const unsigned char *lhs, 35 | const unsigned char *lhs_copy, const unsigned char *rhs, const unsigned char *rhs_copy, bool owns_copies); 36 | ~Enum(); 37 | }; 38 | 39 | class Frame { 40 | private: 41 | vector *_enums; 42 | uint64_t _start; 43 | 44 | public: 45 | ~Frame(); 46 | }; 47 | 48 | private: 49 | vector _enums; 50 | 51 | public: 52 | bool operator()(ValueLayout layout, const unsigned char *lhs, const unsigned char *rhs, size_t offset, size_t size, 53 | AGComparisonOptions options); 54 | 55 | bool failed(AGComparisonOptions options, const unsigned char *lhs, const unsigned char *rhs, size_t offset, 56 | size_t size, const swift::metadata *_Nullable type); 57 | }; 58 | 59 | } // namespace LayoutDescriptor 60 | } // namespace AG 61 | 62 | CF_ASSUME_NONNULL_END 63 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/LayoutDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AGComparison.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | 12 | namespace swift { 13 | class metadata; 14 | class existential_type_metadata; 15 | class context_descriptor; 16 | } // namespace swift 17 | 18 | /// A string that encodes an object's layout in memory. 19 | using ValueLayout = const unsigned char *; 20 | 21 | extern const ValueLayout ValueLayoutTrivial; 22 | 23 | namespace LayoutDescriptor { 24 | 25 | enum class HeapMode : uint16_t { 26 | NonHeap = 0, 27 | Class = 1 << 0, 28 | Locals = 1 << 1, 29 | GenericLocals = 1 << 2, 30 | }; 31 | inline bool operator&(HeapMode a, HeapMode b) { return a & b; } 32 | inline HeapMode operator|(HeapMode a, HeapMode b) { return a | b; } 33 | 34 | extern unsigned char base_address; 35 | 36 | // MARK: Managing comparison modes 37 | 38 | AGComparisonMode mode_for_type(const swift::metadata *_Nullable type, AGComparisonMode default_mode); 39 | void add_type_descriptor_override(const swift::context_descriptor *_Nullable type_descriptor, 40 | AGComparisonMode override_mode); 41 | 42 | // MARK: Obtaining layouts 43 | 44 | ValueLayout fetch(const swift::metadata &type, AGComparisonOptions options, uint32_t priority); 45 | 46 | ValueLayout make_layout(const swift::metadata &type, AGComparisonMode default_mode, HeapMode heap_mode); 47 | 48 | // MARK: Comparing values 49 | 50 | /// Returns the number of characters in the layout, up to the next sibling enum marker or until the end of the 51 | /// layout. 52 | size_t length(ValueLayout layout); 53 | 54 | // MARK: Comparing values 55 | 56 | bool compare(ValueLayout layout, const unsigned char *lhs, const unsigned char *rhs, size_t size, 57 | AGComparisonOptions options); 58 | bool compare_bytes_top_level(const unsigned char *lhs, const unsigned char *rhs, size_t size, 59 | AGComparisonOptions options); 60 | bool compare_bytes(char unsigned const *lhs, char unsigned const *rhs, size_t size, size_t *_Nullable failure_location); 61 | bool compare_heap_objects(char unsigned const *lhs, char unsigned const *rhs, AGComparisonOptions options, 62 | bool is_function); 63 | bool compare_indirect(ValueLayout _Nullable *_Nullable layout_ref, const swift::metadata &lhs_type, 64 | const swift::metadata &rhs_type, AGComparisonOptions options, const unsigned char *lhs, 65 | const unsigned char *rhs); 66 | bool compare_existential_values(const swift::existential_type_metadata &type, const unsigned char *lhs, 67 | const unsigned char *rhs, AGComparisonOptions options); 68 | 69 | bool compare_partial(ValueLayout layout, const unsigned char *lhs, const unsigned char *rhs, size_t offset, size_t size, 70 | AGComparisonOptions options); 71 | struct Partial { 72 | ValueLayout layout; 73 | size_t location; 74 | }; 75 | Partial find_partial(ValueLayout layout, size_t range_location, size_t range_size); 76 | 77 | // MARK: Printing 78 | 79 | void print(std::string &output, ValueLayout layout); 80 | 81 | } // namespace LayoutDescriptor 82 | 83 | } // namespace AG 84 | 85 | CF_ASSUME_NONNULL_END 86 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Comparison/ValueLayout.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace AG { 4 | namespace LayoutDescriptor { 5 | 6 | enum class ValueLayoutEntryKind : uint8_t { 7 | End = '\x00', 8 | Equals = '\x01', 9 | Indirect = '\x02', 10 | Existential = '\x03', 11 | HeapRef = '\x04', 12 | Function = '\x05', 13 | Nested = '\x06', 14 | CompactNested = '\x07', 15 | 16 | EnumStartVariadic = '\x08', 17 | EnumStart0 = '\x09', 18 | EnumStart1 = '\x0a', 19 | EnumStart2 = '\x0b', 20 | EnumContinueVariadic = '\x0c', 21 | EnumContinue0 = '\x0d', 22 | EnumContinue1 = '\x0e', 23 | EnumContinue2 = '\x0f', 24 | EnumContinue3 = '\x10', 25 | EnumContinue4 = '\x11', 26 | EnumContinue5 = '\x12', 27 | EnumContinue6 = '\x13', 28 | EnumContinue7 = '\x14', 29 | EnumContinue8 = '\x15', 30 | EnumEnd = '\x16', 31 | }; 32 | 33 | struct ValueLayoutReader { 34 | const unsigned char *layout; 35 | 36 | inline ValueLayoutEntryKind &peek_kind() const { return *(ValueLayoutEntryKind *)layout; } 37 | 38 | inline ValueLayoutEntryKind read_kind() { 39 | auto kind = *(ValueLayoutEntryKind *)layout; 40 | layout += 1; 41 | return kind; 42 | } 43 | 44 | template inline T read_bytes() { 45 | T returnVal; 46 | memcpy(&returnVal, layout, sizeof(T)); 47 | layout += sizeof(T); 48 | return returnVal; 49 | } 50 | 51 | inline uint64_t read_varint() { 52 | unsigned shift = 0; 53 | uint64_t result = 0; 54 | while (*layout & 0x80) { 55 | result |= (*layout & 0x7f) << shift; 56 | shift += 7; 57 | layout += 1; 58 | } 59 | result |= (*layout & 0x7f) << shift; 60 | layout += 1; 61 | return result; 62 | } 63 | 64 | inline void skip_varint() { 65 | while (*layout & 0x80) { 66 | layout += 1; 67 | } 68 | layout += 1; 69 | } 70 | 71 | inline void skip(size_t n) { layout += n; } 72 | }; 73 | 74 | } // namespace LayoutDescriptor 75 | } // namespace AG 76 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Data/Constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | namespace AG { 9 | namespace data { 10 | 11 | constexpr uint32_t page_size = 0x200; 12 | constexpr uint32_t page_alignment_mask = page_size - 1; 13 | 14 | } // namespace data 15 | } // namespace AG 16 | 17 | CF_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Data/Page.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Pointer.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | namespace data { 12 | 13 | class zone; 14 | 15 | struct page { 16 | zone *zone; 17 | ptr next; 18 | uint32_t total; 19 | uint32_t in_use; 20 | 21 | uint16_t first_child_1; 22 | uint16_t first_child_2; 23 | }; 24 | static_assert(sizeof(page) == 0x18); 25 | 26 | class page_ptr_list { 27 | public: 28 | class iterator { 29 | private: 30 | ptr _current; 31 | 32 | public: 33 | iterator(ptr current) : _current(current) {} 34 | 35 | bool operator==(const iterator &other) const { return _current == other._current; } 36 | bool operator!=(const iterator &other) const { return _current != other._current; } 37 | 38 | ptr operator*() { return _current; } 39 | 40 | iterator &operator++() { 41 | assert(_current); 42 | _current = _current->next; 43 | return *this; 44 | } 45 | }; 46 | 47 | private: 48 | ptr _front; 49 | 50 | public: 51 | page_ptr_list(ptr front) : _front(front) {} 52 | 53 | iterator begin() { return iterator(_front); } 54 | iterator end() { return iterator(nullptr); } 55 | }; 56 | 57 | } // namespace data 58 | } // namespace AG 59 | 60 | CF_ASSUME_NONNULL_END 61 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Data/Pointer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Constants.h" 9 | #include "Table.h" 10 | 11 | CF_ASSUME_NONNULL_BEGIN 12 | 13 | namespace AG { 14 | namespace data { 15 | 16 | struct page; 17 | 18 | template class ptr { 19 | public: 20 | using element_type = T; 21 | using difference_type = uint32_t; 22 | 23 | private: 24 | difference_type _offset; 25 | 26 | template friend class ptr; 27 | 28 | public: 29 | ptr(difference_type offset = 0) : _offset(offset) {}; 30 | ptr(nullptr_t) {}; 31 | 32 | void assert_valid() const { 33 | if (_offset >= table::shared().ptr_max_offset()) { 34 | precondition_failure("invalid data offset: %u", _offset); 35 | } 36 | } 37 | 38 | element_type *_Nullable get() const noexcept { 39 | if (_offset == 0) { 40 | return nullptr; 41 | } 42 | return reinterpret_cast(table::shared().ptr_base() + _offset); 43 | } 44 | 45 | ptr page_ptr() const noexcept { return ptr(_offset & ~page_alignment_mask); } 46 | 47 | difference_type offset() const noexcept { return _offset; } 48 | 49 | template ptr aligned(difference_type alignment_mask = sizeof(difference_type) - 1) const { 50 | return ptr((_offset + alignment_mask) & ~alignment_mask); 51 | }; 52 | 53 | explicit operator bool() const noexcept { return _offset != 0; }; 54 | std::add_lvalue_reference_t operator*() const noexcept { return *get(); }; 55 | T *_Nonnull operator->() const noexcept { 56 | assert(_offset != 0); 57 | return get(); 58 | }; 59 | 60 | bool operator==(const ptr &other) const noexcept { return _offset == other._offset; }; 61 | bool operator!=(const ptr &other) const noexcept { return _offset != other._offset; }; 62 | bool operator==(nullptr_t) const noexcept { return _offset == 0; }; 63 | bool operator!=(nullptr_t) const noexcept { return _offset != 0; }; 64 | 65 | bool operator<(difference_type offset) const noexcept { return _offset < offset; }; 66 | bool operator<=(difference_type offset) const noexcept { return _offset <= offset; }; 67 | bool operator>(difference_type offset) const noexcept { return _offset > offset; }; 68 | bool operator>=(difference_type offset) const noexcept { return _offset >= offset; }; 69 | 70 | template ptr operator+(difference_type shift) const noexcept { return ptr(_offset + shift); }; 71 | template ptr operator-(difference_type shift) const noexcept { return ptr(_offset - shift); }; 72 | 73 | template difference_type operator-(const ptr &other) const noexcept { 74 | return _offset - other._offset; 75 | }; 76 | 77 | template ptr advanced(difference_type shift) const noexcept { return ptr(_offset + shift); }; 78 | 79 | template ptr unsafe_cast() const { return ptr(_offset); } 80 | }; 81 | 82 | } // namespace data 83 | } // namespace AG 84 | 85 | namespace std { 86 | 87 | template class hash> { 88 | public: 89 | std::uint64_t operator()(const AG::data::ptr &pointer) const { return pointer.offset(); } 90 | }; 91 | 92 | } // namespace std 93 | 94 | CF_ASSUME_NONNULL_END 95 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Data/Table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Vector/Vector.h" 12 | 13 | CF_ASSUME_NONNULL_BEGIN 14 | 15 | namespace AG { 16 | namespace data { 17 | 18 | class zone; 19 | class page; 20 | template class ptr; 21 | 22 | class table { 23 | public: 24 | class malloc_zone_deleter { 25 | public: 26 | void operator()(void *p) { malloc_zone_free(_malloc_zone, p); } 27 | }; 28 | 29 | static malloc_zone_t *_malloc_zone; 30 | static std::unique_ptr alloc_persistent(size_t size); 31 | 32 | private: 33 | vm_address_t _ptr_base; 34 | vm_address_t _vm_region_base_address; 35 | os_unfair_lock _lock = OS_UNFAIR_LOCK_INIT; 36 | uint32_t _vm_region_size; 37 | uint32_t _ptr_max_offset; 38 | 39 | uint32_t _num_used_pages = 0; 40 | uint32_t _num_reusable_bytes = 0; 41 | uint32_t _map_search_start = 0; 42 | 43 | uint32_t _num_zones = 0; 44 | 45 | using remapped_region = std::pair; 46 | vector _remapped_regions; 47 | 48 | constexpr static unsigned int pages_per_map = 64; 49 | using page_map_type = std::bitset; 50 | vector _page_maps; 51 | vector _page_metadata_maps; 52 | 53 | public: 54 | static table &ensure_shared(); 55 | static table &shared(); 56 | 57 | table(); 58 | ~table(); // only called during testing 59 | 60 | void lock(); 61 | void unlock(); 62 | 63 | // Pointers 64 | vm_address_t ptr_base() { return _ptr_base; }; 65 | uint32_t ptr_max_offset() { return _ptr_max_offset; }; 66 | 67 | // Region 68 | void grow_region(); 69 | 70 | // Zones 71 | uint32_t make_zone_id(); 72 | 73 | // Pages 74 | ptr alloc_page(zone *zone, uint32_t size); 75 | void dealloc_page_locked(ptr page); 76 | void make_pages_reusable(uint32_t page_index, bool flag); 77 | uint64_t raw_page_seed(ptr page); 78 | 79 | // Printing 80 | void print(); 81 | }; 82 | 83 | } // namespace data 84 | } // namespace AG 85 | 86 | CF_ASSUME_NONNULL_END 87 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Data/Zone.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Page.h" 7 | #include "Pointer.h" 8 | #include "Table.h" 9 | 10 | CF_ASSUME_NONNULL_BEGIN 11 | 12 | namespace AG { 13 | namespace data { 14 | 15 | class zone { 16 | public: 17 | class info { 18 | private: 19 | enum { 20 | id_mask = 0x7fffffff, 21 | deleted = 0x80000000, 22 | }; 23 | uint32_t _value; 24 | info(uint32_t value) : _value(value) {}; 25 | 26 | public: 27 | uint32_t zone_id() { return _value & id_mask; }; 28 | info with_zone_id(uint32_t zone_id) const { return info((_value & ~id_mask) | (zone_id & id_mask)); }; 29 | 30 | info with_deleted() const { return info(_value | deleted); }; 31 | 32 | uint32_t to_raw_value() { return _value; }; 33 | static info from_raw_value(uint32_t value) { return info(value); }; 34 | }; 35 | 36 | private: 37 | typedef struct _bytes_info { 38 | ptr next; 39 | uint32_t size; 40 | } bytes_info; 41 | 42 | vector, 0, uint32_t> _malloc_buffers; 43 | ptr _first_page; 44 | ptr _free_bytes; 45 | info _info; 46 | 47 | ptr alloc_slow(uint32_t size, uint32_t alignment_mask); 48 | 49 | public: 50 | zone(); 51 | ~zone(); 52 | 53 | info info() const { return _info; }; 54 | void mark_deleted() { _info = _info.with_deleted(); }; 55 | 56 | page_ptr_list pages() const { return page_ptr_list(_first_page); }; 57 | 58 | void clear(); 59 | void realloc_bytes(ptr *buffer, uint32_t size, uint32_t new_size, uint32_t alignment_mask); 60 | 61 | // Paged memory 62 | ptr alloc_bytes(uint32_t size, uint32_t alignment_mask); 63 | ptr alloc_bytes_recycle(uint32_t size, uint32_t alignment_mask); 64 | 65 | 66 | // Persistent memory 67 | void *alloc_persistent(size_t size); 68 | 69 | // Printing 70 | static void print_header(); 71 | void print(); 72 | }; 73 | 74 | } // namespace data 75 | } // namespace AG 76 | 77 | CF_ASSUME_NONNULL_END 78 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Errors/Errors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Graph/Graph.h" 4 | 5 | char *error_message = nullptr; 6 | 7 | namespace AG { 8 | 9 | os_log_t error_log() { 10 | static os_log_t log = os_log_create("dev.incrematic.compute", "error"); 11 | return log; 12 | } 13 | 14 | void precondition_failure(const char *format, ...) { 15 | char *message = nullptr; 16 | 17 | va_list args; 18 | va_start(args, format); 19 | vasprintf(&message, format, args); 20 | va_end(args); 21 | 22 | if (message != nullptr) { 23 | os_log_error(error_log(), "precondition failure: %s", message); 24 | Graph::trace_assertion_failure(true, "precondition failure: %s", message); 25 | if (error_message == nullptr) { 26 | asprintf(&error_message, "Compute precondition failure: %s.\n", message); 27 | } 28 | free(message); 29 | } 30 | 31 | abort(); 32 | } 33 | 34 | void non_fatal_precondition_failure(const char *format, ...) { 35 | char *message = nullptr; 36 | 37 | va_list args; 38 | va_start(args, format); 39 | vasprintf(&message, format, args); 40 | va_end(args); 41 | 42 | if (message != nullptr) { 43 | os_log_fault(error_log(), "precondition failure: %s", message); 44 | free(message); 45 | } 46 | } 47 | 48 | } // namespace AG 49 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Errors/Errors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | CF_ASSUME_NONNULL_BEGIN 6 | 7 | namespace AG { 8 | 9 | void precondition_failure(const char *format, ...); 10 | void non_fatal_precondition_failure(const char *format, ...); 11 | 12 | } // namespace AG 13 | 14 | CF_ASSUME_NONNULL_END 15 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/AGDescription.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | CF_EXTERN_C_BEGIN 9 | 10 | CF_EXPORT 11 | const CFStringRef AGDescriptionFormat; 12 | 13 | CF_EXPORT 14 | const CFStringRef AGDescriptionTruncationLimit; 15 | 16 | CF_EXTERN_C_END 17 | 18 | CF_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/AGDescription.mm: -------------------------------------------------------------------------------- 1 | #include "AGDescription.h" 2 | 3 | const CFStringRef AGDescriptionFormat = CFSTR("format"); 4 | const CFStringRef AGDescriptionTruncationLimit = CFSTR("truncation-limit"); 5 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/AGGraph-Private.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGGraph.h" 6 | #include "Graph/Context.h" 7 | #include "Private/CFRuntime.h" 8 | 9 | CF_ASSUME_NONNULL_BEGIN 10 | 11 | struct AGGraphStorage { 12 | CFRuntimeBase base; 13 | AG::Graph::Context context; 14 | }; 15 | 16 | struct AGGraphContextStorage { 17 | AG::Graph::Context context; 18 | }; 19 | 20 | CF_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/AGGraph.mm: -------------------------------------------------------------------------------- 1 | #include "AGGraph-Private.h" 2 | 3 | #import 4 | 5 | #include "Context.h" 6 | #include "Graph.h" 7 | 8 | #pragma mark - Description 9 | 10 | CFTypeRef AGGraphDescription(AGGraphRef graph, CFDictionaryRef options) { 11 | if (graph == nullptr) { 12 | return (__bridge CFTypeRef)AG::Graph::description(nullptr, (__bridge NSDictionary *)options); 13 | } 14 | 15 | auto graph_context = AG::Graph::Context::from_cf(graph); 16 | if (graph_context->invalidated()) { 17 | AG::precondition_failure("invalidated graph"); 18 | } 19 | return (__bridge CFTypeRef)AG::Graph::description(&graph_context->graph(), (__bridge NSDictionary *)options); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/Context.cpp: -------------------------------------------------------------------------------- 1 | #include "Context.h" 2 | 3 | #include "AGGraph-Private.h" 4 | #include "Attribute/AttributeID/AttributeID.h" 5 | #include "Subgraph/Subgraph.h" 6 | #include "UniqueID/AGUniqueID.h" 7 | 8 | namespace AG { 9 | 10 | Graph::Context::Context(Graph *graph) : _graph(graph), _id(AGMakeUniqueID()) { 11 | Graph::retain(graph); 12 | graph->_contexts_by_id.insert(_id, this); 13 | } 14 | 15 | Graph::Context::~Context() { 16 | _graph->_contexts_by_id.remove(_id); 17 | Graph::release(_graph); 18 | } 19 | 20 | Graph::Context *Graph::Context::from_cf(AGGraphStorage *storage) { 21 | if (storage->context._invalidated) { 22 | precondition_failure("invalidated graph"); 23 | } 24 | return &storage->context; 25 | } 26 | 27 | } // namespace AG 28 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/Context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Graph.h" 6 | #include "Private/CFRuntime.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | struct AGGraphStorage; 11 | 12 | namespace AG { 13 | 14 | class Graph::Context { 15 | private: 16 | Graph *_graph; 17 | const void *_context = nullptr; 18 | uint64_t _id; 19 | 20 | bool _invalidated; 21 | 22 | public: 23 | Context(Graph *graph); 24 | ~Context(); 25 | 26 | uint64_t id() const { return _id; } 27 | 28 | AGGraphStorage *to_cf() const { return reinterpret_cast((char *)this - sizeof(CFRuntimeBase)); }; 29 | static Context *from_cf(AGGraphStorage *storage); 30 | 31 | Graph &graph() const { return *_graph; }; 32 | 33 | const void *_Nullable context() const { return _context; }; 34 | void set_context(const void *_Nullable context) { _context = context; }; 35 | 36 | bool invalidated() const { return _invalidated; }; 37 | void set_invalidated(bool invalidated) { _invalidated = invalidated; }; 38 | }; 39 | 40 | } // namespace AG 41 | 42 | CF_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/Graph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __OBJC__ 11 | #import 12 | #endif 13 | 14 | #include "Attribute/AttributeID/AttributeID.h" 15 | #include "Attribute/AttributeType/AttributeType.h" 16 | #include "Closure/ClosureFunction.h" 17 | #include "Swift/Metadata.h" 18 | #include "Trace/AGTrace.h" 19 | #include "Utilities/HashTable.h" 20 | #include "Utilities/Heap.h" 21 | 22 | CF_ASSUME_NONNULL_BEGIN 23 | 24 | namespace AG { 25 | 26 | class Trace; 27 | 28 | class Graph { 29 | public: 30 | class Context; 31 | class KeyTable; 32 | class TraceRecorder; 33 | class UpdateStack; 34 | 35 | private: 36 | static Graph *_Nullable _all_graphs; 37 | static os_unfair_lock _all_graphs_lock; 38 | 39 | Graph *_Nullable _next; 40 | Graph *_Nullable _previous; 41 | util::Heap _heap; 42 | 43 | // Attribute types 44 | util::UntypedTable _interned_types; 45 | vector, 0, uint32_t> _types; 46 | 47 | // Contexts 48 | util::Table _contexts_by_id; 49 | 50 | // Trace 51 | vector _traces; 52 | 53 | // Trace recorder 54 | TraceRecorder *_trace_recorder; 55 | 56 | // Keys 57 | KeyTable *_Nullable _keys; 58 | 59 | // Threads 60 | uint32_t _ref_count = 1; 61 | 62 | uint64_t _id; 63 | 64 | static void all_lock() { os_unfair_lock_lock(&_all_graphs_lock); }; 65 | static bool all_try_lock() { return os_unfair_lock_trylock(&_all_graphs_lock); }; 66 | static void all_unlock() { os_unfair_lock_unlock(&_all_graphs_lock); }; 67 | 68 | public: 69 | Graph(); 70 | ~Graph(); 71 | 72 | uint64_t id() const { return _id; } 73 | 74 | // MARK: Context 75 | 76 | Context *_Nullable primary_context() const; 77 | 78 | inline static void retain(Graph *graph) { graph->_ref_count += 1; }; 79 | inline static void release(Graph *graph) { 80 | graph->_ref_count -= 1; 81 | if (graph->_ref_count == 0) { 82 | delete graph; 83 | } 84 | }; 85 | 86 | // MARK: Attribute types 87 | 88 | const AttributeType &attribute_type(uint32_t type_id) const { return *_types[type_id]; }; 89 | const AttributeType &attribute_ref(data::ptr attribute, const void *_Nullable *_Nullable ref_out) const; 90 | 91 | uint32_t intern_type(const swift::metadata *metadata, ClosureFunctionVP make_type); 92 | 93 | void did_allocate_node_value(size_t size); 94 | void did_destroy_node_value(size_t size); 95 | 96 | void update_attribute(AttributeID attribute, bool option); 97 | 98 | // MARK: Trace 99 | 100 | void start_tracing(AGTraceFlags trace_flags, std::span subsystems); 101 | void stop_tracing(); 102 | void sync_tracing(); 103 | CFStringRef copy_trace_path(); 104 | 105 | void prepare_trace(Trace &trace); 106 | 107 | void add_trace(Trace *_Nullable trace); 108 | void remove_trace(uint64_t trace_id); 109 | 110 | static void all_start_tracing(AGTraceFlags trace_flags, std::span span); 111 | static void all_stop_tracing(); 112 | static void all_sync_tracing(); 113 | static CFStringRef all_copy_trace_path(); 114 | 115 | static void trace_assertion_failure(bool all_stop_tracing, const char *format, ...); 116 | 117 | const vector &traces() const { return _traces; }; 118 | 119 | template 120 | requires std::invocable 121 | void foreach_trace(T body) { 122 | for (auto trace = _traces.rbegin(), end = _traces.rend(); trace != end; ++trace) { 123 | body(**trace); 124 | } 125 | }; 126 | 127 | // MARK: Keys 128 | 129 | uint32_t intern_key(const char *key); 130 | const char *key_name(uint32_t key_id) const; 131 | 132 | // MARK: Description 133 | 134 | #ifdef __OBJC__ 135 | static NSObject *_Nullable description(Graph *_Nullable graph, NSDictionary *options); 136 | static NSDictionary *description_graph(Graph *_Nullable graph, NSDictionary *options); 137 | #endif 138 | }; 139 | 140 | } // namespace AG 141 | 142 | CF_ASSUME_NONNULL_END 143 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/Graph.mm: -------------------------------------------------------------------------------- 1 | #include "Graph.h" 2 | 3 | #import 4 | 5 | #include "AGDescription.h" 6 | 7 | namespace { 8 | 9 | NSString *escaped_string(NSString *string, NSUInteger truncation_limit) { 10 | if ([string length] > truncation_limit) { 11 | string = [[string substringToIndex:truncation_limit] stringByAppendingString:@"…"]; 12 | } 13 | return [string stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 14 | } 15 | 16 | } // namespace 17 | 18 | namespace AG { 19 | 20 | NSObject *Graph::description(Graph *graph, NSDictionary *options) { 21 | NSString *format = options[(__bridge NSString *)AGDescriptionFormat]; 22 | if ([format isEqualToString:@"graph/dict"]) { 23 | return description_graph(graph, options); 24 | } 25 | return nil; 26 | } 27 | 28 | NSDictionary *Graph::description_graph(Graph *graph, NSDictionary *options) { 29 | 30 | NSNumber *truncation_limit_number = options[(__bridge NSString *)AGDescriptionTruncationLimit]; 31 | uint64_t truncation_limit = 1024; 32 | if (truncation_limit_number) { 33 | truncation_limit = [truncation_limit_number unsignedLongValue]; 34 | } 35 | 36 | // Build top-level "graphs" array with NSNull placeholders 37 | NSMutableArray *graph_dicts = [NSMutableArray array]; 38 | 39 | // Collect graphs to include in the result 40 | auto graph_indices_by_id = std::unordered_map(); 41 | auto graph_stack = std::stack>(); 42 | 43 | auto push_graph = [&graph_dicts, &graph_indices_by_id, &graph_stack](Graph *graph) -> uint64_t { 44 | auto found = graph_indices_by_id.find(graph->id()); 45 | if (found != graph_indices_by_id.end()) { 46 | return found->second; 47 | } 48 | uint64_t index = [graph_dicts count]; 49 | [graph_dicts addObject:[NSNull null]]; 50 | graph_indices_by_id.emplace(graph->id(), index); 51 | graph_stack.push(graph); 52 | return index; 53 | }; 54 | if (graph) { 55 | push_graph(graph); 56 | } 57 | 58 | // Build each graph dictionary 59 | while (!graph_stack.empty()) { 60 | Graph *graph = graph_stack.top(); 61 | graph_stack.pop(); 62 | 63 | // Collect types to include in the result 64 | auto type_ids = vector(); 65 | 66 | // Build "types" array 67 | NSMutableArray *type_dicts = [NSMutableArray array]; 68 | for (auto type_id : type_ids) { 69 | NSMutableDictionary *type_dict = [NSMutableDictionary dictionary]; 70 | 71 | const AttributeType &type = graph->attribute_type(type_id); 72 | 73 | type_dict[@"id"] = [NSNumber numberWithUnsignedInt:type_id]; 74 | NSString *name = [NSString stringWithUTF8String:type.body_metadata().name(false)]; 75 | type_dict[@"name"] = escaped_string(name, truncation_limit); 76 | NSString *value = [NSString stringWithUTF8String:type.value_metadata().name(false)]; 77 | type_dict[@"value"] = escaped_string(value, truncation_limit); 78 | type_dict[@"size"] = 79 | [NSNumber numberWithUnsignedLong:type.body_metadata().vw_size() + type.value_metadata().vw_size()]; 80 | type_dict[@"flags"] = [NSNumber numberWithUnsignedInt:type.flags()]; 81 | 82 | [type_dicts addObject:type_dict]; 83 | } 84 | 85 | // Build "nodes" array 86 | NSMutableArray *node_dicts = [NSMutableArray array]; 87 | 88 | // Build "edges" array 89 | NSMutableArray *edge_dicts = [NSMutableArray array]; 90 | 91 | // Build "subgraphs" array 92 | NSMutableArray *subgraph_dicts = [NSMutableArray array]; 93 | 94 | NSMutableDictionary *graph_dict = [NSMutableDictionary dictionary]; 95 | graph_dict[@"id"] = [NSNumber numberWithUnsignedLong:graph->id()]; 96 | 97 | graph_dict[@"types"] = type_dicts; 98 | graph_dict[@"nodes"] = node_dicts; 99 | graph_dict[@"edges"] = edge_dicts; 100 | graph_dict[@"subgraphs"] = subgraph_dicts; 101 | 102 | graph_dict[@"transaction_count"] = [NSNumber numberWithUnsignedLong:0]; 103 | graph_dict[@"update_count"] = [NSNumber numberWithUnsignedLong:0]; 104 | graph_dict[@"change_count"] = [NSNumber numberWithUnsignedLong:0]; 105 | 106 | graph_dicts[graph_indices_by_id.find(graph->id())->second] = graph_dict; 107 | } 108 | 109 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 110 | dict[@"version"] = @2; 111 | dict[@"graphs"] = graph_dicts; 112 | return dict; 113 | } 114 | 115 | } // namespace AG 116 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/KeyTable.cpp: -------------------------------------------------------------------------------- 1 | #include "KeyTable.h" 2 | 3 | namespace AG { 4 | 5 | Graph::KeyTable::KeyTable(util::Heap *_Nullable heap) 6 | : _table( 7 | util::string_hash, [](const char *a, const char *b) { return std::strcmp(a, b) == 0; }, 8 | [](const char *key) { free((void *)key); }, nullptr, heap) {}; 9 | 10 | uint32_t Graph::KeyTable::lookup(const char *key, const char *_Nullable *_Nullable found_key) const { 11 | return _table.lookup(key, found_key); 12 | } 13 | 14 | uint32_t Graph::KeyTable::size() { return _keys.size(); } 15 | 16 | uint32_t Graph::KeyTable::insert(const char *key) { 17 | const char *duplicate = strdup(key); 18 | if (!duplicate) { 19 | precondition_failure("memory allocation failure"); 20 | } 21 | uint32_t key_id = _keys.size(); 22 | _keys.push_back(duplicate); 23 | _table.insert(duplicate, key_id); 24 | return key_id; 25 | } 26 | 27 | const char *Graph::KeyTable::get(uint32_t key_id) { return _keys[key_id]; } 28 | 29 | }; // namespace AG 30 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/KeyTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Graph.h" 6 | #include "Utilities/HashTable.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace AG { 11 | 12 | class Graph::KeyTable { 13 | private: 14 | vector _keys; 15 | util::Table _table; 16 | 17 | public: 18 | KeyTable(util::Heap *_Nullable heap); 19 | 20 | uint32_t size(); 21 | 22 | uint32_t lookup(const char *key, const char *_Nullable *_Nullable found_key) const; 23 | const char *get(uint32_t key_id); 24 | 25 | uint32_t insert(const char *key); 26 | }; 27 | 28 | } // namespace AG 29 | 30 | CF_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Graph/TraceRecorder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AGGraph.h" 7 | #include "Trace/Trace.h" 8 | #include "Utilities/HashTable.h" 9 | 10 | CF_ASSUME_NONNULL_BEGIN 11 | 12 | namespace AG { 13 | 14 | class Graph::TraceRecorder : public Trace { 15 | public: 16 | TraceRecorder(Graph *graph, AGTraceFlags trace_flags, std::span subsystems); 17 | ~TraceRecorder(); 18 | 19 | uint64_t id() { return _id; }; 20 | 21 | const char *_Nullable trace_path() const { 22 | // TODO: not implemented 23 | return nullptr; 24 | }; 25 | 26 | // MARK: Trace methods 27 | 28 | void graph_destroyed() override; 29 | void trace_removed() override; 30 | 31 | void begin_trace(const Graph &graph) override; 32 | void end_trace(const Graph &graph) override; 33 | void sync_trace() override; 34 | 35 | void log_message_v(const char *format, va_list args) override; 36 | 37 | void begin_update(const Subgraph &subgraph, uint32_t options) override; 38 | void end_update(const Subgraph &subgraph) override; 39 | void begin_update(const Graph::UpdateStack &update_stack, data::ptr node, uint32_t options) override; 40 | void end_update(const Graph::UpdateStack &update_stack, data::ptr node, 41 | AGGraphUpdateStatus update_status) override; 42 | void begin_update(data::ptr node) override; 43 | void end_update(data::ptr node, bool changed) override; 44 | void begin_update(const Graph::Context &context) override; 45 | void end_update(const Graph::Context &context) override; 46 | 47 | void begin_invalidation(const Graph::Context &context, AttributeID attribute) override; 48 | void end_invalidation(const Graph::Context &context, AttributeID attribute) override; 49 | 50 | void begin_modify(data::ptr node) override; 51 | void end_modify(data::ptr node) override; 52 | 53 | void begin_event(data::ptr node, uint32_t event_id) override; 54 | void end_event(data::ptr node, uint32_t event_id) override; 55 | 56 | void created(const Graph::Context &context) override; 57 | void destroy(const Graph::Context &context) override; 58 | void needs_update(const Graph::Context &context) override; 59 | 60 | void created(const Subgraph &subgraph) override; 61 | void invalidate(const Subgraph &subgraph) override; 62 | void destroy(const Subgraph &subgraph) override; 63 | 64 | void add_child(const Subgraph &subgraph, const Subgraph &child) override; 65 | void remove_child(const Subgraph &subgraph, const Subgraph &child) override; 66 | 67 | void added(data::ptr node) override; 68 | 69 | void add_edge(data::ptr node, AttributeID input, uint8_t input_edge_flags) override; 70 | void remove_edge(data::ptr node, uint32_t input_index) override; 71 | void set_edge_pending(data::ptr node, uint32_t input_index, bool pending) override; 72 | 73 | void set_dirty(data::ptr node, bool dirty) override; 74 | void set_pending(data::ptr node, bool pending) override; 75 | 76 | void set_value(data::ptr node, const void *value) override; 77 | void mark_value(data::ptr node) override; 78 | 79 | void added(data::ptr indirect_node) override; 80 | 81 | void set_source(data::ptr indirect_node, AttributeID source) override; 82 | void set_dependency(data::ptr indirect_node, AttributeID dependency) override; 83 | 84 | void set_deadline(uint64_t deadline) override; 85 | void passed_deadline() override; 86 | 87 | void mark_profile(const Graph &graph, uint32_t options) override; 88 | 89 | void custom_event(const Graph::Context &context, const char *event_name, const void *value, 90 | const swift::metadata &type) override; 91 | void named_event(const Graph::Context &context, uint32_t event_id, uint32_t event_arg_count, const void *event_args, 92 | CFDataRef data, uint32_t arg6) override; 93 | bool named_event_enabled(uint32_t event_id) override; 94 | 95 | // compare_failed not overridden 96 | }; 97 | 98 | } // namespace AG 99 | 100 | CF_ASSUME_NONNULL_END 101 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Log/Log.cpp: -------------------------------------------------------------------------------- 1 | #include "Log/Log.h" 2 | 3 | namespace AG { 4 | 5 | os_log_t misc_log() { 6 | static os_log_t log = os_log_create("dev.incrematic.compute", "misc"); 7 | return log; 8 | } 9 | 10 | } // namespace AG 11 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Log/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | namespace AG { 9 | 10 | os_log_t misc_log(); 11 | 12 | } // namespace AG 13 | 14 | CF_ASSUME_NONNULL_END 15 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Subgraph/AGSubgraph-Private.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGSubgraph.h" 6 | #include "Private/CFRuntime.h" 7 | 8 | namespace AG { 9 | class Subgraph; 10 | } 11 | 12 | CF_ASSUME_NONNULL_BEGIN 13 | 14 | struct AGSubgraphStorage { 15 | CFRuntimeBase base; 16 | AG::Subgraph *subgraph; 17 | }; 18 | 19 | CF_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Subgraph/AGSubgraph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | CF_ASSUME_NONNULL_BEGIN 6 | 7 | CF_EXTERN_C_BEGIN 8 | 9 | typedef struct CF_BRIDGED_TYPE(id) AGSubgraphStorage *AGSubgraphRef CF_SWIFT_NAME(Subgraph); 10 | 11 | CF_EXTERN_C_END 12 | 13 | CF_ASSUME_NONNULL_END 14 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Subgraph/Subgraph.cpp: -------------------------------------------------------------------------------- 1 | #include "Subgraph.h" 2 | 3 | #include "AGSubgraph-Private.h" 4 | 5 | namespace AG { 6 | 7 | Subgraph *Subgraph::from_cf(AGSubgraphStorage *storage) { return storage->subgraph; } 8 | 9 | AGSubgraphStorage *Subgraph::to_cf() const { return reinterpret_cast(_object); } 10 | 11 | } // namespace AG 12 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Subgraph/Subgraph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGSubgraph.h" 6 | #include "Data/Zone.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | struct AGSubgraphStorage; 11 | 12 | namespace AG { 13 | 14 | class Graph; 15 | class SubgraphObject; 16 | 17 | class Subgraph : public data::zone { 18 | private: 19 | SubgraphObject *_object; 20 | Graph *_graph; 21 | uint64_t _context_id; 22 | 23 | public: 24 | AGSubgraphStorage *to_cf() const; 25 | static Subgraph *from_cf(AGSubgraphStorage *storage); 26 | 27 | Graph *graph() const { return _graph; }; 28 | 29 | uint64_t context_id() const { return _context_id; } 30 | }; 31 | 32 | } // namespace AG 33 | 34 | CF_ASSUME_NONNULL_END 35 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/AGTuple.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AGSwiftSupport.h" 6 | #include "AGType.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | CF_EXTERN_C_BEGIN 11 | 12 | typedef CF_ENUM(uint32_t, AGTupleCopyOptions) { 13 | AGTupleCopyOptionsInitialize = 1 << 0, 14 | AGTupleCopyOptionsWithTake = 1 << 1, 15 | 16 | AGTupleCopyOptionsAssignCopy = 0, 17 | AGTupleCopyOptionsInitCopy = 1, 18 | AGTupleCopyOptionsAssignTake = 2, 19 | AGTupleCopyOptionsInitTake = 3, 20 | } CF_SWIFT_NAME(TupleType.CopyOptions); 21 | 22 | typedef const AGSwiftMetadata *AGTupleType AG_SWIFT_STRUCT CF_SWIFT_NAME(TupleType); 23 | 24 | typedef struct AGUnsafeTuple { 25 | AGTupleType type; 26 | const void *value; 27 | } CF_SWIFT_NAME(UnsafeTuple) AGUnsafeTuple; 28 | 29 | typedef struct AGUnsafeMutableTuple { 30 | AGTupleType type; 31 | void *value; 32 | } CF_SWIFT_NAME(UnsafeMutableTuple) AGUnsafeMutableTuple; 33 | 34 | CF_EXPORT 35 | CF_REFINED_FOR_SWIFT 36 | AGTupleType AGNewTupleType(uint32_t count, const AGTypeID _Nonnull *_Nonnull elements) 37 | CF_SWIFT_NAME(TupleType.init(count:elements:)); 38 | 39 | CF_EXPORT 40 | CF_REFINED_FOR_SWIFT 41 | size_t AGTupleCount(AGTupleType tuple_type) CF_SWIFT_NAME(getter:AGTupleType.count(self:)); 42 | 43 | CF_EXPORT 44 | CF_REFINED_FOR_SWIFT 45 | size_t AGTupleSize(AGTupleType tuple_type) CF_SWIFT_NAME(getter:AGTupleType.size(self:)); 46 | 47 | CF_EXPORT 48 | CF_REFINED_FOR_SWIFT 49 | AGTypeID AGTupleElementType(AGTupleType tuple_type, uint32_t index) CF_SWIFT_NAME(TupleType.elementType(self:at:)); 50 | 51 | CF_EXPORT 52 | CF_REFINED_FOR_SWIFT 53 | size_t AGTupleElementSize(AGTupleType tuple_type, uint32_t index) CF_SWIFT_NAME(TupleType.elementSize(self:at:)); 54 | 55 | CF_EXPORT 56 | CF_REFINED_FOR_SWIFT 57 | size_t AGTupleElementOffset(AGTupleType tuple_type, uint32_t index) CF_SWIFT_NAME(TupleType.elementOffset(self:at:)); 58 | 59 | CF_EXPORT 60 | CF_REFINED_FOR_SWIFT 61 | size_t AGTupleElementOffsetChecked(AGTupleType tuple_type, uint32_t index, AGTypeID element_type) 62 | CF_SWIFT_NAME(TupleType.elementOffset(self:at:type:)); 63 | 64 | CF_EXPORT 65 | CF_REFINED_FOR_SWIFT 66 | void *AGTupleGetElement(AGTupleType tuple_type, void *tuple_value, uint32_t index, void *element_value, 67 | AGTypeID element_type, AGTupleCopyOptions options); 68 | 69 | CF_EXPORT 70 | CF_REFINED_FOR_SWIFT 71 | void *AGTupleSetElement(AGTupleType tuple_type, void *tuple_value, uint32_t index, const void *element_value, 72 | AGTypeID element_type, AGTupleCopyOptions options); 73 | 74 | CF_EXPORT 75 | CF_REFINED_FOR_SWIFT 76 | void AGTupleDestroy(AGTupleType tuple_type, void *tuple_value) CF_SWIFT_NAME(TupleType.destroy(self:_:)); 77 | 78 | CF_EXPORT 79 | CF_REFINED_FOR_SWIFT 80 | void AGTupleDestroyElement(AGTupleType tuple_type, void *tuple_value, uint32_t index) 81 | CF_SWIFT_NAME(TupleType.destroy(self:_:at:)); 82 | 83 | CF_EXPORT 84 | CF_REFINED_FOR_SWIFT 85 | void AGTupleWithBuffer(AGTupleType tuple_type, size_t count, 86 | void (*function)(const void *context AG_SWIFT_CONTEXT, const AGUnsafeMutableTuple mutable_tuple) 87 | AG_SWIFT_CC(swift), 88 | const void *context); 89 | 90 | CF_EXTERN_C_END 91 | 92 | CF_ASSUME_NONNULL_END 93 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/AGType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AGSwiftSupport.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | CF_IMPLICIT_BRIDGING_ENABLED 10 | 11 | CF_EXTERN_C_BEGIN 12 | 13 | typedef const struct AGSwiftMetadata *AGTypeID AG_SWIFT_STRUCT AG_SWIFT_NAME(Metadata); 14 | 15 | typedef struct AGTypeSignature { 16 | uint32_t data[5]; 17 | } AG_SWIFT_NAME(Signature) AGTypeSignature; 18 | 19 | typedef CF_CLOSED_ENUM(uint32_t, AGTypeKind) { 20 | AGTypeKindNone, 21 | AGTypeKindClass, 22 | AGTypeKindStruct, 23 | AGTypeKindEnum, 24 | AGTypeKindOptional, 25 | AGTypeKindTuple, 26 | AGTypeKindFunction, 27 | AGTypeKindExistential, 28 | AGTypeKindMetatype, 29 | } CF_SWIFT_NAME(Metadata.Kind); 30 | 31 | CF_EXPORT 32 | CF_REFINED_FOR_SWIFT 33 | CFStringRef AGTypeDescription(AGTypeID typeID); 34 | 35 | CF_EXPORT 36 | CF_REFINED_FOR_SWIFT 37 | AGTypeKind AGTypeGetKind(AGTypeID typeID) CF_SWIFT_NAME(getter:Metadata.kind(self:)); 38 | 39 | CF_EXPORT 40 | CF_REFINED_FOR_SWIFT 41 | const AGTypeSignature AGTypeGetSignature(AGTypeID typeID) CF_SWIFT_NAME(getter:Metadata.signature(self:)); 42 | 43 | CF_EXPORT 44 | CF_REFINED_FOR_SWIFT 45 | const void *_Nullable AGTypeGetDescriptor(AGTypeID typeID) CF_SWIFT_NAME(getter:Metadata.descriptor(self:)); 46 | 47 | CF_EXPORT 48 | CF_REFINED_FOR_SWIFT 49 | const void *_Nullable AGTypeNominalDescriptor(AGTypeID typeID) CF_SWIFT_NAME(getter:Metadata.nominalDescriptor(self:)); 50 | 51 | CF_EXPORT 52 | CF_REFINED_FOR_SWIFT 53 | const char *_Nullable AGTypeNominalDescriptorName(AGTypeID typeID) 54 | CF_SWIFT_NAME(getter:Metadata.nominalDescriptorName(self:)); 55 | 56 | typedef CF_OPTIONS(uint32_t, AGTypeApplyOptions) { 57 | AGTypeApplyOptionsEnumerateStructFields = 0, 58 | AGTypeApplyOptionsEnumerateClassFields = 1 << 0, 59 | AGTypeApplyOptionsContinueAfterUnknownField = 1 << 1, 60 | AGTypeApplyOptionsEnumerateEnumCases = 1 << 2, 61 | }; 62 | 63 | CF_EXPORT 64 | CF_REFINED_FOR_SWIFT 65 | void AGTypeApplyFields(AGTypeID typeID, 66 | void (*apply)(const void *_Nullable context AG_SWIFT_CONTEXT, const char *field_name, 67 | size_t field_offset, AGTypeID field_type) AG_SWIFT_CC(swift), 68 | const void *apply_context); 69 | 70 | CF_EXPORT 71 | CF_REFINED_FOR_SWIFT 72 | bool AGTypeApplyFields2(AGTypeID typeID, AGTypeApplyOptions options, 73 | bool (*_Nonnull apply)(const void *context AG_SWIFT_CONTEXT, const char *field_name, 74 | size_t field_offset, AGTypeID field_type) AG_SWIFT_CC(swift), 75 | const void *apply_context); 76 | 77 | CF_EXPORT 78 | CF_REFINED_FOR_SWIFT 79 | bool AGTypeApplyEnumData(AGTypeID typeID, void *value, 80 | void (*body)(const void *context AG_SWIFT_CONTEXT, uint32_t tag, AGTypeID field_type, 81 | const void *field_value) AG_SWIFT_CC(swift), 82 | const void *context); 83 | 84 | CF_EXPORT 85 | CF_REFINED_FOR_SWIFT 86 | bool AGTypeApplyMutableEnumData(AGTypeID typeID, void *value, 87 | void (*body)(const void *context AG_SWIFT_CONTEXT, uint32_t tag, AGTypeID field_type, 88 | void *field_value) AG_SWIFT_CC(swift), 89 | const void *context); 90 | 91 | CF_EXPORT 92 | CF_REFINED_FOR_SWIFT 93 | uint64_t AGTypeGetEnumTag(AGTypeID typeID, void *value); 94 | 95 | CF_EXPORT 96 | CF_REFINED_FOR_SWIFT 97 | void AGTypeProjectEnumData(AGTypeID typeID); 98 | 99 | CF_EXPORT 100 | CF_REFINED_FOR_SWIFT 101 | void AGTypeInjectEnumTag(AGTypeID typeID); 102 | 103 | CF_EXTERN_C_END 104 | 105 | CF_IMPLICIT_BRIDGING_DISABLED 106 | CF_ASSUME_NONNULL_END 107 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/ContextDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "ContextDescriptor.h" 2 | 3 | #include "Metadata.h" 4 | 5 | namespace AG { 6 | namespace swift { 7 | 8 | context_descriptor::generic_params_info::generic_params_info(const context_descriptor &context, 9 | const metadata *_Nullable type) { 10 | if (context.isGeneric()) { 11 | generic_header = &context.getGenericContext()->getGenericContextHeader(); 12 | 13 | if (type) { 14 | switch (context.getKind()) { 15 | case ::swift::ContextDescriptorKind::Class: { 16 | auto class_descriptor = reinterpret_cast(context.base()); 17 | auto asWords = reinterpret_cast(type); 18 | generic_args = asWords + class_descriptor->immediate_members_offset(); 19 | break; 20 | } 21 | case ::swift::ContextDescriptorKind::Struct: { 22 | auto struct_descriptor = reinterpret_cast(context.base()); 23 | auto asWords = reinterpret_cast(type); 24 | generic_args = asWords + struct_descriptor->getGenericArgumentOffset(); 25 | break; 26 | } 27 | case ::swift::ContextDescriptorKind::Enum: { 28 | auto enum_descriptor = reinterpret_cast(context.base()); 29 | auto asWords = reinterpret_cast(type); 30 | generic_args = asWords + enum_descriptor->getGenericArgumentOffset(); 31 | break; 32 | } 33 | default: 34 | return; 35 | } 36 | } 37 | 38 | if (generic_header->NumParams > 0) { 39 | auto type_descriptor = reinterpret_cast(context.base()); 40 | auto generic_params = type_descriptor->getGenericParams(); 41 | params = generic_params; 42 | 43 | if (generic_header->Flags.hasTypePacks()) { 44 | pack_shape_header = type_descriptor->getGenericContext()->getGenericPackShapeHeader(); 45 | pack_shape_descriptors = type_descriptor->getGenericContext()->getGenericPackShapeDescriptors(); 46 | } 47 | } 48 | } 49 | } 50 | 51 | uint64_t context_descriptor::count_generic_args() const { 52 | auto info = generic_params_info(*this, nullptr); 53 | 54 | uint64_t count = 0; 55 | for (auto param : info.params) { 56 | switch (param.getKind()) { 57 | case ::swift::GenericParamKind::Type: 58 | case ::swift::GenericParamKind::TypePack: { 59 | if (param.hasKeyArgument()) { 60 | count += 1; 61 | } 62 | break; 63 | } 64 | default: 65 | break; 66 | } 67 | } 68 | return count; 69 | } 70 | 71 | void context_descriptor::push_generic_args(const metadata &type, 72 | vector &generic_args_vector) const { 73 | auto info = generic_params_info(*this, &type); 74 | if (info.params.empty()) { 75 | return; 76 | } 77 | 78 | // The generic arguments array consists of: 79 | // - a sequence of pack lengths 80 | // - a sequence of metadata or metadata pack pointers 81 | // - a sequence of witness table or witness table pack pointers 82 | // See https://github.com/swiftlang/swift/blob/main/include/swift/ABI/GenericContext.h 83 | 84 | // Start from the metadata or metadata pack points 85 | unsigned arg_index = info.pack_shape_header.NumShapeClasses; 86 | 87 | // Iterate through over the pack shape descriptors array in parallel with the generic arguments array 88 | unsigned pack_index = 0; 89 | 90 | for (auto param : info.params) { 91 | if (!param.hasKeyArgument()) { 92 | continue; 93 | } 94 | 95 | switch (param.getKind()) { 96 | case ::swift::GenericParamKind::Type: { 97 | generic_args_vector.push_back({ 98 | info.generic_args[arg_index], 99 | 1, 100 | false, 101 | }); 102 | break; 103 | } 104 | case ::swift::GenericParamKind::TypePack: { 105 | const metadata *types = nullptr; 106 | uint64_t num_types = 0; 107 | if (info.generic_args[arg_index] != nullptr) { 108 | types = info.generic_args[arg_index]; 109 | // The shape class is represented as the length of the type parameter pack 110 | num_types = 111 | reinterpret_cast(info.generic_args[info.pack_shape_descriptors[pack_index].ShapeClass]); 112 | } 113 | 114 | pack_index += 1; 115 | 116 | generic_args_vector.push_back({ 117 | types, 118 | num_types, 119 | true, 120 | }); 121 | break; 122 | } 123 | default: 124 | break; 125 | } 126 | 127 | arg_index += 1; 128 | } 129 | } 130 | 131 | uint64_t class_type_descriptor::immediate_members_offset() const { 132 | if (base()->hasResilientSuperclass()) { 133 | // This is equivalent to ::swift::getResilientImmediateMembersOffset 134 | // but without using any atomic-ordered loads, 135 | // as we already have the metadata pointer 136 | const auto &stored_bounds = base()->ResilientMetadataBounds.get(); 137 | ptrdiff_t offset = stored_bounds->ImmediateMembersOffset.load(std::memory_order_relaxed); 138 | return offset / sizeof(void *); 139 | } 140 | return base()->getNonResilientImmediateMembersOffset(); 141 | } 142 | 143 | uint64_t class_type_descriptor::field_offset_vector_offset() const { 144 | // FieldOffsetVectorOffset is a private field, 145 | // but we know comes directly after Numfields which is a uint32_t 146 | uint32_t offset = *(&_base.NumFields + sizeof(uint32_t)); 147 | 148 | if (base()->hasResilientSuperclass()) { 149 | return immediate_members_offset() + offset; 150 | } else { 151 | return offset; 152 | } 153 | } 154 | 155 | } // namespace swift 156 | } // namespace AG 157 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/ContextDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Metadata.h" 9 | #include "Vector/Vector.h" 10 | 11 | CF_ASSUME_NONNULL_BEGIN 12 | 13 | namespace AG { 14 | namespace swift { 15 | 16 | class context_descriptor : public ::swift::ContextDescriptor { 17 | public: 18 | struct generic_params_info { 19 | const ::swift::GenericContextDescriptorHeader *generic_header = nullptr; 20 | llvm::ArrayRef<::swift::GenericParamDescriptor> params = {}; 21 | ::swift::GenericPackShapeHeader pack_shape_header = {}; 22 | llvm::ArrayRef<::swift::GenericPackShapeDescriptor> pack_shape_descriptors = {}; 23 | const metadata *_Nonnull const *_Nullable generic_args = nullptr; 24 | 25 | generic_params_info(const context_descriptor &context, const metadata *_Nullable type); 26 | }; 27 | 28 | struct generic_arg { 29 | const metadata *types; 30 | uint64_t num_types; 31 | bool is_pack; 32 | }; 33 | 34 | const ::swift::ContextDescriptor *base() const { return this; }; 35 | static const context_descriptor *from_base(const ::swift::ContextDescriptor *base) { 36 | return static_cast(base); 37 | }; 38 | 39 | const context_descriptor *_Nullable parent() const { return context_descriptor::from_base(Parent.get()); }; 40 | 41 | uint64_t count_generic_args() const; 42 | void push_generic_args(const metadata &metadata, vector &generic_args_vector) const; 43 | }; 44 | 45 | class type_context_descriptor : ::swift::TypeContextDescriptor { 46 | public: 47 | const char *name() const { return Name.get(); } 48 | }; 49 | 50 | class class_type_descriptor { 51 | private: 52 | ::swift::ClassDescriptor _base; 53 | 54 | public: 55 | const ::swift::ClassDescriptor *base() const { return &_base; }; 56 | static const class_type_descriptor *from_base(const ::swift::ClassDescriptor *base) { 57 | return reinterpret_cast(base); 58 | }; 59 | 60 | // We need to reimplement these to avoid errors when linking against the Swift runtime library 61 | uint64_t immediate_members_offset(void) const; 62 | uint64_t field_offset_vector_offset() const; 63 | }; 64 | 65 | } // namespace swift 66 | } // namespace AG 67 | 68 | CF_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/Metadata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Comparison/LayoutDescriptor.h" 8 | 9 | CF_ASSUME_NONNULL_BEGIN 10 | 11 | namespace AG { 12 | namespace swift { 13 | 14 | using opaque_value = ::swift::OpaqueValue; 15 | using equatable_witness_table = ::swift::equatable_support::EquatableWitnessTable; 16 | 17 | class metadata_visitor; 18 | class context_descriptor; 19 | class type_context_descriptor; 20 | 21 | class metadata : public ::swift::Metadata { 22 | private: 23 | const ::swift::Metadata *base() const { return this; }; 24 | static const metadata *from_base(const ::swift::Metadata *base) { return static_cast(base); }; 25 | 26 | bool is_type_metadata() const { 27 | if (::swift::ClassMetadata::classof(this)) { 28 | const auto class_type = static_cast(base()); 29 | // Depending on the deployment target a binary was compiled for, 30 | // statically emitted metadata templates may have a different bit set 31 | // from the one that this runtime canonically considers the "is Swift" bit. 32 | // See SWIFT_CLASS_IS_SWIFT_MASK in 33 | // https://github.com/swiftlang/swift/blob/main/include/swift/ABI/Metadata.h 34 | return class_type->Data & 0x3; 35 | } 36 | return true; 37 | } 38 | 39 | public: 40 | const char *name(bool qualified) const; 41 | 42 | const context_descriptor *_Nullable descriptor() const; 43 | const type_context_descriptor *_Nullable nominal_descriptor() const; 44 | 45 | void append_description(CFMutableStringRef description) const; 46 | const void *signature() const; 47 | 48 | const equatable_witness_table *_Nullable equatable() const; 49 | 50 | // Mutating objects 51 | 52 | void copy_on_write_heap_object(void *_Nonnull *_Nonnull object_ref) const; 53 | 54 | // Looking up types by name 55 | 56 | enum class ref_kind { 57 | strong = 0, 58 | weak = 1, 59 | unowned = 2, 60 | unmanaged = 3, 61 | }; 62 | 63 | const metadata *_Nullable mangled_type_name_ref(const char *type_name, bool fault_if_null, 64 | ref_kind *_Nullable kind_out) const; 65 | const metadata *_Nullable mangled_type_name_ref_cached(const char *type_name, ref_kind *_Nullable kind_out) const; 66 | 67 | // Visiting 68 | 69 | bool visit(metadata_visitor &visitor) const; 70 | bool visit_heap(metadata_visitor &visitor, LayoutDescriptor::HeapMode heap_mode) const; 71 | 72 | private: 73 | bool visit_heap_class(metadata_visitor &visitor) const; 74 | bool visit_heap_locals(metadata_visitor &visitor) const; 75 | }; 76 | 77 | class any_class_type_metadata : public ::swift::AnyClassMetadata {}; 78 | 79 | class function_type_metadata : public ::swift::FunctionTypeMetadata {}; 80 | 81 | class existential_type_metadata : public ::swift::ExistentialTypeMetadata { 82 | public: 83 | // We need to reimplement these to avoid errors when linking against the Swift runtime library 84 | ::swift::ExistentialTypeRepresentation representation(void) const; 85 | const void *project_value(void *container) const; 86 | const metadata *dynamic_type(void *container) const; 87 | }; 88 | 89 | } // namespace swift 90 | } // namespace AG 91 | 92 | CF_ASSUME_NONNULL_END 93 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/MetadataVisitor.cpp: -------------------------------------------------------------------------------- 1 | #include "MetadataVisitor.h" 2 | 3 | #include 4 | 5 | namespace AG { 6 | namespace swift { 7 | 8 | bool metadata_visitor::unknown_result() { return false; } 9 | 10 | bool metadata_visitor::visit_element(const metadata &type, const metadata::ref_kind kind, size_t element_offset, 11 | size_t element_size) { 12 | return unknown_result(); 13 | } 14 | 15 | bool metadata_visitor::visit_field(const metadata &type, const field_record &field, size_t field_offset, 16 | size_t field_size) { 17 | const char *mangled_type_name = field.MangledTypeName ? field.MangledTypeName.get() : nullptr; 18 | if (mangled_type_name) { 19 | metadata::ref_kind ref_kind = metadata::ref_kind::strong; 20 | const metadata *element_type = type.mangled_type_name_ref(mangled_type_name, false, &ref_kind); 21 | if (element_type) { 22 | size_t element_size = element_type->vw_size(); 23 | if (element_type->getKind() == ::swift::MetadataKind::Metatype) { 24 | element_size = std::min(element_size, field_size); 25 | } 26 | return visit_element(*element_type, ref_kind, field_offset, element_size); 27 | } 28 | } 29 | return unknown_result(); 30 | } 31 | 32 | bool metadata_visitor::visit_case(const metadata &type, const field_record &field, uint32_t index) { 33 | return unknown_result(); 34 | } 35 | 36 | bool metadata_visitor::metadata_visitor::visit_class(const any_class_type_metadata &type) { return unknown_result(); } 37 | 38 | bool metadata_visitor::visit_existential(const existential_type_metadata &type) { return unknown_result(); } 39 | 40 | bool metadata_visitor::visit_function(const function_type_metadata &type) { return unknown_result(); } 41 | 42 | bool metadata_visitor::visit_native_object(const metadata &type) { return unknown_result(); } 43 | 44 | } // namespace swift 45 | } // namespace AG 46 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/MetadataVisitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // needed by swift/RemoteInspection/Records.h 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "Metadata.h" 11 | 12 | CF_ASSUME_NONNULL_BEGIN 13 | 14 | namespace AG { 15 | namespace swift { 16 | 17 | using field_record = ::swift::reflection::FieldRecord; 18 | 19 | class metadata_visitor { 20 | public: 21 | virtual bool unknown_result(); 22 | 23 | virtual bool visit_element(const metadata &type, const metadata::ref_kind kind, size_t element_offset, 24 | size_t element_size); 25 | 26 | virtual bool visit_field(const metadata &type, const field_record &field, size_t field_offset, size_t field_size); 27 | 28 | virtual bool visit_case(const metadata &type, const field_record &field, uint32_t index); 29 | virtual bool visit_class(const any_class_type_metadata &type); 30 | virtual bool visit_existential(const existential_type_metadata &type); 31 | virtual bool visit_function(const function_type_metadata &type); 32 | virtual bool visit_native_object(const metadata &type); 33 | }; 34 | 35 | } // namespace swift 36 | } // namespace AG 37 | 38 | CF_ASSUME_NONNULL_END 39 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/SwiftShims.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "AGSwiftSupport.h" 9 | 10 | CF_ASSUME_NONNULL_BEGIN 11 | 12 | CF_EXTERN_C_BEGIN 13 | 14 | AG_SWIFT_CC(swift) 15 | bool AGDispatchEquatable(const void *lhs_value, const void *rhs_value, const ::swift::Metadata *type, 16 | const ::swift::equatable_support::EquatableWitnessTable *wt); 17 | 18 | CF_EXTERN_C_END 19 | 20 | CF_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/_SwiftStdlibCxxOverlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AGSwiftSupport.h" 4 | 5 | extern "C" const ::swift::Metadata *_Nullable swift_getTypeByMangledNameInContext( 6 | const char *_Nullable typeNameStart, size_t typeNameLength, const void *_Nullable context, 7 | const void *_Nullable const *_Nullable genericArgs) AG_SWIFT_CC(swift); 8 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/mach-o/MachOFile.cpp: -------------------------------------------------------------------------------- 1 | #include "MachOFile.h" 2 | 3 | #include 4 | 5 | bool MachOFile::hasMachOMagic() const { return magic == MH_MAGIC || magic == MH_MAGIC_64; } 6 | 7 | bool MachOFile::getUuid(uuid_t uuid) const { 8 | __block bool found = false; 9 | forEachLoadCommand(^(const load_command *cmd, bool &stop) { 10 | if (cmd->cmd == LC_UUID) { 11 | const uuid_command *uc = (const uuid_command *)cmd; 12 | memcpy(uuid, uc->uuid, sizeof(uuid_t)); 13 | found = true; 14 | stop = true; 15 | } 16 | }); 17 | /* diag.assertNoError(); // any malformations in the file should have been caught by earlier validate() call */ 18 | if (!found) { 19 | bzero(uuid, sizeof(uuid_t)); 20 | } 21 | return found; 22 | } 23 | 24 | bool MachOFile::hasMachOBigEndianMagic() const { return magic == MH_CIGAM || magic == MH_CIGAM_64; }; 25 | 26 | void MachOFile::forEachLoadCommand(/* Diagnostics& diag, */ void (^callback)(const load_command *cmd, bool &stop)) const { 27 | bool stop = false; 28 | const load_command *startCmds = nullptr; 29 | if (this->magic == MH_MAGIC_64) { 30 | startCmds = (load_command *)((char *)this + sizeof(mach_header_64)); 31 | } else if (this->magic == MH_MAGIC) { 32 | startCmds = (load_command *)((char *)this + sizeof(mach_header)); 33 | } else if (hasMachOBigEndianMagic()) { 34 | return; // can't process big endian mach-o 35 | } else { 36 | const uint32_t *h = (uint32_t *)this; 37 | /* diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h[1]); */ 38 | return; // not a mach-o file 39 | } 40 | const load_command *const cmdsEnd = (load_command *)((char *)startCmds + this->sizeofcmds); 41 | const load_command *cmd = startCmds; 42 | for (uint32_t i = 0; i < this->ncmds; ++i) { 43 | const load_command *nextCmd = (load_command *)((char *)cmd + cmd->cmdsize); 44 | if (cmd->cmdsize < 8) { 45 | /* diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, 46 | * cmd, this, cmd->cmdsize); */ 47 | return; 48 | } 49 | if ((nextCmd > cmdsEnd) || (nextCmd < startCmds)) { 50 | /* diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands 51 | * end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd); */ 52 | return; 53 | } 54 | callback(cmd, stop); 55 | if (stop) { 56 | return; 57 | } 58 | cmd = nextCmd; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/mach-o/MachOFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // A partial port of https://github.com/PureDarwin/dyld/blob/master/dyld3/MachOFile.h 7 | struct MachOFile : mach_header { 8 | public: 9 | bool hasMachOMagic() const; 10 | bool getUuid(uuid_t uuid) const; 11 | 12 | protected: 13 | bool hasMachOBigEndianMagic() const; 14 | void forEachLoadCommand(/* Diagnostics &diag, */ void (^callback)(const load_command *cmd, bool &stop)) const; 15 | }; 16 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/mach-o/dyld.cpp: -------------------------------------------------------------------------------- 1 | #include "dyld.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "MachOFile.h" 8 | 9 | bool dyld_get_image_uuid(const mach_header *mh, uuid_t uuid) { 10 | const MachOFile *mf = (MachOFile *)mh; 11 | if (!mf->hasMachOMagic()) { 12 | return false; 13 | } 14 | return mf->getUuid(uuid); 15 | } 16 | 17 | void dyld_images_for_addresses(unsigned count, const void *addresses[], dyld_image_uuid_offset infos[]) { 18 | for (unsigned i = 0; i < count; i++) { 19 | const void *addr = addresses[i]; 20 | bzero(&infos[i], sizeof(dyld_image_uuid_offset)); 21 | 22 | Dl_info dl_info; 23 | if (dladdr(addr, &dl_info)) { 24 | infos[i].image = (mach_header *)dl_info.dli_fbase; 25 | infos[i].offsetInImage = (uintptr_t)addr - (uintptr_t)dl_info.dli_fbase; 26 | dyld_get_image_uuid((mach_header *)dl_info.dli_fbase, infos[i].uuid); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Swift/mach-o/dyld.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | 8 | struct dyld_image_uuid_offset { 9 | uuid_t uuid; 10 | uint64_t offsetInImage; 11 | const struct mach_header *image; 12 | }; 13 | 14 | // Given an array of addresses, returns info about each address. 15 | // For each address, returns the where that image was loaded, the offset 16 | // of the address in the image, and the image's uuid. If a specified 17 | // address is unknown to dyld, all fields will be returned a zeros. 18 | extern void dyld_images_for_addresses(unsigned count, const void *addresses[], struct dyld_image_uuid_offset infos[]); 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Time/Time.cpp: -------------------------------------------------------------------------------- 1 | #include "Time.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace AG { 7 | 8 | double current_time() { return absolute_time_to_seconds(mach_absolute_time()); } 9 | 10 | double absolute_time_to_seconds(uint64_t ticks) { 11 | static double time_scale = []() -> double { 12 | struct mach_timebase_info info; 13 | auto err = mach_timebase_info(&info); 14 | if (err) { 15 | return NAN; 16 | } 17 | return (info.numer / info.denom) * 0.000000001; 18 | }(); 19 | return static_cast(ticks) * time_scale; 20 | } 21 | 22 | } // namespace AG 23 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Time/Time.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace AG { 4 | 5 | double current_time(void); 6 | double absolute_time_to_seconds(uint64_t ticks); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Trace/AGTrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Graph/AGGraph.h" 6 | 7 | CF_ASSUME_NONNULL_BEGIN 8 | 9 | CF_EXTERN_C_BEGIN 10 | 11 | typedef CF_ENUM(uint64_t, AGTraceEvents) { 12 | AGTraceEventsCustom = 1, 13 | AGTraceEventsNamed = 2, 14 | AGTraceEventsDeadline = 3, 15 | AGTraceEventsCompareFailed = 4, 16 | }; 17 | 18 | typedef struct AGTrace { 19 | AGTraceEvents events; 20 | 21 | void (*_Nullable beginTrace)(void *_Nullable context, AGGraphRef graph); 22 | void (*_Nullable endTrace)(void *_Nullable context, AGGraphRef graph); 23 | 24 | void (*_Nullable beginUpdateSubgraph)(void *_Nullable context, AGSubgraphRef subgraph); 25 | void (*_Nullable endUpdateSubgraph)(void *_Nullable context, AGSubgraphRef subgraph); 26 | void (*_Nullable beginUpdate)(void *_Nullable context, AGAttribute attribute); 27 | void (*_Nullable endUpdate)(void *_Nullable context, bool changed); 28 | void (*_Nullable beginUpdateAttribute)(void *_Nullable context); 29 | void (*_Nullable endUpdateAttribute)(void *_Nullable context); 30 | void (*_Nullable beginUpdateGraph)(void *_Nullable context, AGGraphRef graph); 31 | void (*_Nullable endUpdateGraph)(void *_Nullable context, AGGraphRef graph); 32 | 33 | void (*_Nullable beginInvalidation)(void *_Nullable context, AGGraphRef graph, AGAttribute attribute); 34 | void (*_Nullable endInvalidation)(void *_Nullable context, AGGraphRef graph, AGAttribute attribute); 35 | 36 | void (*_Nullable beginModify)(void *_Nullable context); 37 | void (*_Nullable endModify)(void *_Nullable context); 38 | 39 | void (*_Nullable beginEvent)(void *_Nullable context, AGAttribute attribute, const char *event_name); 40 | void (*_Nullable endEvent)(void *_Nullable context, AGAttribute attribute, const char *event_name); 41 | 42 | void (*_Nullable createdGraph)(void *_Nullable context, AGGraphRef graph); 43 | void (*_Nullable destroyGraph)(void *_Nullable context, AGGraphRef graph); 44 | void (*_Nullable needsUpdate)(void *_Nullable context, AGGraphRef graph); 45 | 46 | void (*_Nullable createdSubgraph)(void *_Nullable context, AGSubgraphRef subgraph); 47 | void (*_Nullable invalidateSubgraph)(void *_Nullable context, AGSubgraphRef subgraph); 48 | void (*_Nullable addChildSubgraph)(void *_Nullable context, AGSubgraphRef subgraph, AGSubgraphRef child); 49 | void (*_Nullable removeChildSubgraph)(void *_Nullable context, AGSubgraphRef subgraph, AGSubgraphRef child); 50 | 51 | void (*_Nullable addedAttribute)(void *_Nullable context); 52 | void (*_Nullable addEdge)(void *_Nullable context); 53 | void (*_Nullable removeEdge)(void *_Nullable context); 54 | void (*_Nullable setEdgePending)(void *_Nullable context); 55 | 56 | void (*_Nullable setDirty)(void *_Nullable context); 57 | void (*_Nullable setPending)(void *_Nullable context); 58 | void (*_Nullable setValue)(void *_Nullable context); 59 | void (*_Nullable markValue)(void *_Nullable context); 60 | 61 | void (*_Nullable addedIndirectAttribute)(void *_Nullable context, AGAttribute attribute); 62 | void (*_Nullable setSource)(void *_Nullable context, AGAttribute attribute); 63 | void (*_Nullable setDependency)(void *_Nullable context, AGAttribute attribute); 64 | 65 | void (*_Nullable markProfile)(void *_Nullable context, const char *event_name); 66 | 67 | void (*_Nullable customEvent)(void *_Nullable context, AGGraphRef graph, const char *event_name, const void *value, 68 | AGTypeID type); 69 | void (*_Nullable namedEvent)(void *_Nullable context, AGGraphRef graph, uint32_t eventID, uint32_t eventArgCount, 70 | const void *eventArgs, CFDataRef data, uint32_t arg6); 71 | bool (*_Nullable namedEventEnabled)(void *_Nullable context); 72 | void (*_Nullable setDeadline)(void *_Nullable context); 73 | void (*_Nullable passedDeadline)(void *_Nullable context); 74 | 75 | void (*_Nullable compareFailed)(void *_Nullable context, AGAttribute attribute, AGComparisonState comparisonState); 76 | } AGTrace; 77 | 78 | CF_EXTERN_C_END 79 | 80 | CF_ASSUME_NONNULL_END 81 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Trace/AGTraceFlags.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Graph/AGGraph.h" 6 | 7 | CF_ASSUME_NONNULL_BEGIN 8 | 9 | CF_EXTERN_C_BEGIN 10 | 11 | typedef CF_OPTIONS(uint32_t, AGTraceFlags) { 12 | AGTraceFlagsEnabled = 1 << 0, 13 | AGTraceFlagsFull = 1 << 1, 14 | AGTraceFlagsBacktrace = 1 << 2, 15 | AGTraceFlagsPrepare = 1 << 3, 16 | AGTraceFlagsCustom = 1 << 4, 17 | AGTraceFlagsAll = 1 << 5, 18 | }; 19 | 20 | CF_EXTERN_C_END 21 | 22 | CF_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Trace/ExternalTrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Attribute/AttributeID/AGAttribute.h" 6 | #include "Comparison/AGComparison.h" 7 | #include "Graph/AGGraph.h" 8 | #include "Graph/Context.h" 9 | #include "Subgraph/Subgraph.h" 10 | #include "Swift/AGType.h" 11 | #include "Trace/Trace.h" 12 | 13 | CF_ASSUME_NONNULL_BEGIN 14 | 15 | class ExternalTrace : public AG::Trace { 16 | public: 17 | private: 18 | const AGTrace *_trace; 19 | void *_Nullable _context; 20 | 21 | public: 22 | ExternalTrace(AGTrace *trace, void *context) : _trace(trace), _context(context) {}; 23 | ExternalTrace(uint64_t id, const AGTrace *trace, void *context) 24 | : AG::Trace(id), _trace(trace), _context(context) {}; 25 | 26 | void graph_destroyed() override; 27 | void trace_removed() override; 28 | 29 | void begin_trace(const AG::Graph &graph) override; 30 | void end_trace(const AG::Graph &graph) override; 31 | 32 | void begin_update(const AG::Subgraph &subgraph, uint32_t options) override; 33 | void end_update(const AG::Subgraph &subgraph) override; 34 | 35 | void begin_update(const AG::Graph::UpdateStack &update_stack, AG::data::ptr node, 36 | uint32_t options) override; 37 | void end_update(const AG::Graph::UpdateStack &update_stack, AG::data::ptr node, 38 | AGGraphUpdateStatus update_status) override; 39 | void begin_update(AG::data::ptr node) override; 40 | void end_update(AG::data::ptr node, bool changed) override; 41 | void begin_update(const AG::Graph::Context &context) override; 42 | void end_update(const AG::Graph::Context &context) override; 43 | 44 | void begin_invalidation(const AG::Graph::Context &context, AG::AttributeID attribute) override; 45 | void end_invalidation(const AG::Graph::Context &context, AG::AttributeID attribute) override; 46 | 47 | void begin_modify(AG::data::ptr node) override; 48 | void end_modify(AG::data::ptr node) override; 49 | 50 | void begin_event(AG::data::ptr node, uint32_t event_id) override; 51 | void end_event(AG::data::ptr node, uint32_t event_id) override; 52 | 53 | void created(const AG::Graph::Context &context) override; 54 | void destroy(const AG::Graph::Context &context) override; 55 | void needs_update(const AG::Graph::Context &context) override; 56 | 57 | void created(const AG::Subgraph &subgraph) override; 58 | void invalidate(const AG::Subgraph &subgraph) override; 59 | void destroy(const AG::Subgraph &subgraph) override; 60 | 61 | void add_child(const AG::Subgraph &subgraph, const AG::Subgraph &child) override; 62 | void remove_child(const AG::Subgraph &subgraph, const AG::Subgraph &child) override; 63 | 64 | void added(AG::data::ptr node) override; 65 | 66 | void add_edge(AG::data::ptr node, AG::AttributeID input, uint8_t input_edge_flags) override; 67 | void remove_edge(AG::data::ptr node, uint32_t input_index) override; 68 | void set_edge_pending(AG::data::ptr node, uint32_t input_index, bool pending) override; 69 | 70 | void set_dirty(AG::data::ptr node, bool dirty) override; 71 | void set_pending(AG::data::ptr node, bool pending) override; 72 | void set_value(AG::data::ptr node, const void *value) override; 73 | void mark_value(AG::data::ptr node) override; 74 | 75 | void added(AG::data::ptr indirect_node) override; 76 | 77 | void set_source(AG::data::ptr indirect_node, AG::AttributeID source) override; 78 | void set_dependency(AG::data::ptr indirect_node, AG::AttributeID dependency) override; 79 | 80 | void mark_profile(const AG::Graph &graph, uint32_t event_id) override; 81 | 82 | void custom_event(const AG::Graph::Context &context, const char *event_name, const void *value, 83 | const AG::swift::metadata &type) override; 84 | void named_event(const AG::Graph::Context &context, uint32_t event_id, uint32_t event_arg_count, 85 | const void *event_args, CFDataRef data, uint32_t arg6) override; 86 | bool named_event_enabled(uint32_t event_id) override; 87 | 88 | void set_deadline(uint64_t deadline) override; 89 | void passed_deadline() override; 90 | 91 | void compare_failed(AG::data::ptr node, const void *lhs, const void *rhs, size_t range_offset, 92 | size_t range_size, const AG::swift::metadata *_Nullable type) override; 93 | }; 94 | 95 | CF_ASSUME_NONNULL_END 96 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Trace/Trace.cpp: -------------------------------------------------------------------------------- 1 | #include "Trace.h" 2 | 3 | namespace AG { 4 | 5 | void Trace::log_message(const char *format, ...) { 6 | va_list args; 7 | va_start(args, format); 8 | log_message_v(format, args); 9 | va_end(args); 10 | } 11 | 12 | } // namespace AG 13 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/Trace/Trace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Graph/AGGraph.h" 6 | #include "Graph/Graph.h" 7 | #include "UniqueID/AGUniqueID.h" 8 | 9 | CF_ASSUME_NONNULL_BEGIN 10 | 11 | namespace AG { 12 | 13 | class Node; 14 | class Subgraph; 15 | 16 | class Trace { 17 | protected: 18 | uint64_t _id; 19 | 20 | public: 21 | uint64_t id() { return _id; } 22 | 23 | Trace() : _id(AGMakeUniqueID()) {}; 24 | Trace(uint64_t id) : _id(id) {}; 25 | 26 | virtual void graph_destroyed() {}; 27 | virtual void trace_removed() {}; 28 | 29 | // Trace 30 | virtual void begin_trace(const Graph &graph) {}; 31 | virtual void end_trace(const Graph &graph) {}; 32 | virtual void sync_trace() {}; 33 | 34 | // Log 35 | virtual void log_message_v(const char *format, va_list args) {}; 36 | void log_message(const char *format, ...); 37 | 38 | // Updates 39 | virtual void begin_update(const Subgraph &subgraph, uint32_t options) {}; 40 | virtual void end_update(const Subgraph &subgraph) {}; 41 | virtual void begin_update(const Graph::UpdateStack &update_stack, data::ptr node, uint32_t options) {}; 42 | virtual void end_update(const Graph::UpdateStack &update_stack, data::ptr node, 43 | AGGraphUpdateStatus update_status) {}; 44 | virtual void begin_update(data::ptr node) {}; 45 | virtual void end_update(data::ptr node, bool changed) {}; 46 | virtual void begin_update(const Graph::Context &context) {}; 47 | virtual void end_update(const Graph::Context &context) {}; 48 | 49 | virtual void begin_invalidation(const Graph::Context &context, AttributeID attribute) {}; 50 | virtual void end_invalidation(const Graph::Context &context, AttributeID attribute) {}; 51 | 52 | virtual void begin_modify(data::ptr node) {}; 53 | virtual void end_modify(data::ptr node) {}; 54 | 55 | virtual void begin_event(data::ptr node, uint32_t event_id) {}; 56 | virtual void end_event(data::ptr node, uint32_t event_id) {}; 57 | 58 | virtual void created(const Graph::Context &context) {}; 59 | virtual void destroy(const Graph::Context &context) {}; 60 | virtual void needs_update(const Graph::Context &context) {}; 61 | 62 | virtual void created(const Subgraph &subgraph) {}; 63 | virtual void invalidate(const Subgraph &subgraph) {}; 64 | virtual void destroy(const Subgraph &subgraph) {}; 65 | 66 | virtual void add_child(const Subgraph &subgraph, const Subgraph &child) {}; 67 | virtual void remove_child(const Subgraph &subgraph, const Subgraph &child) {}; 68 | 69 | virtual void added(data::ptr node) {}; 70 | 71 | virtual void add_edge(data::ptr node, AttributeID input, uint8_t input_edge_flags) {}; 72 | virtual void remove_edge(data::ptr node, uint32_t input_index) {}; 73 | virtual void set_edge_pending(data::ptr node, uint32_t input_index, bool pending) {}; 74 | 75 | virtual void set_dirty(data::ptr node, bool dirty) {}; 76 | virtual void set_pending(data::ptr node, bool pending) {}; 77 | 78 | virtual void set_value(data::ptr node, const void *value) {}; 79 | virtual void mark_value(data::ptr node) {}; 80 | 81 | virtual void added(data::ptr indirect_node) {}; 82 | 83 | virtual void set_source(data::ptr indirect_node, AttributeID source) {}; 84 | virtual void set_dependency(data::ptr indirect_node, AttributeID dependency) {}; 85 | 86 | virtual void set_deadline(uint64_t deadline) {}; 87 | virtual void passed_deadline() {}; 88 | 89 | virtual void mark_profile(const Graph &graph, uint32_t options) {}; 90 | 91 | virtual void custom_event(const Graph::Context &context, const char *event_name, const void *value, 92 | const swift::metadata &type) {}; 93 | virtual void named_event(const Graph::Context &context, uint32_t event_id, uint32_t event_arg_count, 94 | const void *event_args, CFDataRef data, uint32_t arg6) {}; 95 | virtual bool named_event_enabled(uint32_t event_id) { return false; }; 96 | 97 | virtual void compare_failed(data::ptr node, const void *lhs, const void *rhs, size_t range_offset, 98 | size_t range_size, const swift::metadata *_Nullable type) {}; 99 | }; 100 | 101 | } // namespace AG 102 | 103 | CF_ASSUME_NONNULL_END 104 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/UniqueID/AGUniqueID.cpp: -------------------------------------------------------------------------------- 1 | #include "AGUniqueID.h" 2 | 3 | uint64_t AGMakeUniqueID() { 4 | static uint64_t counter = 0; 5 | return ++counter; 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/UniqueID/AGUniqueID.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | CF_EXTERN_C_BEGIN 9 | 10 | uint64_t AGMakeUniqueID() CF_SWIFT_NAME(makeUniqueID()); 11 | 12 | CF_EXTERN_C_END 13 | 14 | CF_ASSUME_NONNULL_END 15 | -------------------------------------------------------------------------------- /Sources/ComputeCxx/include/Compute.h: -------------------------------------------------------------------------------- 1 | #include "Attribute/AttributeID/AGAttribute.h" 2 | #include "Comparison/AGComparison.h" 3 | #include "Graph/AGDescription.h" 4 | #include "Graph/AGGraph.h" 5 | #include "Subgraph/AGSubgraph.h" 6 | #include "Swift/AGTuple.h" 7 | #include "Swift/AGType.h" 8 | #include "Trace/AGTrace.h" 9 | -------------------------------------------------------------------------------- /Sources/ComputeCxxSwiftSupport/ComputeCxxSwiftSupport.swift: -------------------------------------------------------------------------------- 1 | @_silgen_name("AGDispatchEquatable") 2 | public func Equatable_isEqual_indirect( 3 | _ lhs: UnsafePointer, 4 | _ rhs: UnsafePointer 5 | ) -> Bool { 6 | return lhs.pointee == rhs.pointee 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Utilities/Heap.cpp: -------------------------------------------------------------------------------- 1 | #include "Utilities/Heap.h" 2 | 3 | #include 4 | 5 | namespace util { 6 | 7 | constexpr size_t default_increment = 0x2000; 8 | 9 | Heap *Heap::create(char *_Nullable start, size_t capacity, size_t increment) { 10 | return new Heap(start, capacity, increment); 11 | } 12 | 13 | void Heap::destroy(Heap *value) { delete value; } 14 | 15 | Heap::Heap(char *start, size_t capacity, size_t increment) { 16 | // enforce minimum but treat 0 as the default 17 | size_t effective_increment = increment > 0 ? std::max(increment, minimum_increment) : default_increment; 18 | 19 | _increment = effective_increment; 20 | _node = nullptr; 21 | reset(start, capacity); 22 | }; 23 | 24 | util::Heap::~Heap() { reset(nullptr, 0); } 25 | 26 | void *util::Heap::alloc_(size_t size) { 27 | if (_capacity >= size) { 28 | char *result = _free_start; 29 | _free_start += size; 30 | _capacity -= size; 31 | return result; 32 | } 33 | 34 | if (size <= minimum_increment) { 35 | int64_t increment = _increment; 36 | char *buffer = static_cast(malloc(increment)); 37 | 38 | _free_start = buffer; 39 | _capacity = increment; 40 | 41 | Node *node = alloc(); 42 | 43 | node->next = _node; 44 | node->buffer = buffer; 45 | _node = node; 46 | 47 | char *result = _free_start; 48 | _free_start += size; 49 | _capacity -= size; 50 | return result; 51 | } 52 | 53 | Node *node = alloc(); 54 | void *result = malloc(size); 55 | if (result) { 56 | node->next = _node; 57 | node->buffer = result; 58 | _node = node; 59 | } 60 | return result; 61 | } 62 | 63 | void util::Heap::reset(char *_Nullable start, size_t capacity) { 64 | while (_node) { 65 | void *buffer = _node->buffer; 66 | _node = _node->next; 67 | free(buffer); 68 | } 69 | 70 | constexpr uintptr_t alignment_mask = sizeof(char *) - 1; 71 | char *aligned_start = (char *)(((uintptr_t)start + alignment_mask) & ~alignment_mask); 72 | 73 | bool prealigned = ((uintptr_t)start & alignment_mask) == 0; 74 | _free_start = prealigned ? start : aligned_start; 75 | _capacity = capacity + (start - aligned_start); 76 | } 77 | 78 | size_t util::Heap::num_nodes() const { 79 | size_t count = 0; 80 | for (Node *node = _node; node != nullptr; node = node->next) { 81 | count += 1; 82 | } 83 | return count; 84 | } 85 | 86 | void util::Heap::print() const { 87 | fprintf(stdout, "Nodes\n"); 88 | for (Node *node = _node; node != nullptr; node = node->next) { 89 | fprintf(stdout, "address=%-16p; buffer=%-16p; next=%-16p\n", node, node->buffer, node->next); 90 | } 91 | } 92 | 93 | }; // namespace util 94 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/CFPointer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | namespace util { 9 | 10 | template class cf_ptr { 11 | private: 12 | CFTypeRef _storage; 13 | 14 | static inline CFTypeRef to_storage(T ref) { return (CFTypeRef)(ref); } 15 | static inline T from_storage(CFTypeRef storage) { return (T)storage; } 16 | 17 | public: 18 | constexpr cf_ptr() noexcept : _storage(nullptr) {} 19 | constexpr cf_ptr(std::nullptr_t) noexcept : _storage(nullptr) {} 20 | 21 | explicit cf_ptr(T ref) : _storage(to_storage(ref)) { 22 | if (_storage) { 23 | CFRetain(_storage); 24 | } 25 | } 26 | 27 | ~cf_ptr() { 28 | if (_storage) { 29 | CFRelease(_storage); 30 | } 31 | } 32 | 33 | // Copy and move constructors 34 | 35 | cf_ptr(const cf_ptr &other) noexcept : _storage(other._storage) { 36 | if (_storage) { 37 | CFRetain(_storage); 38 | } 39 | }; 40 | 41 | cf_ptr(cf_ptr &&other) noexcept : _storage(std::exchange(other._storage, nullptr)) {}; 42 | 43 | // Copy and move assignment operators 44 | 45 | cf_ptr &operator=(const cf_ptr &other) noexcept { 46 | if (this != &other) { 47 | if (_storage) { 48 | CFRelease(_storage); 49 | } 50 | _storage = other._storage; 51 | if (_storage) { 52 | CFRetain(_storage); 53 | } 54 | } 55 | return *this; 56 | }; 57 | 58 | cf_ptr &operator=(cf_ptr &&other) noexcept { 59 | if (this != &other) { 60 | if (_storage) { 61 | CFRelease(_storage); 62 | } 63 | _storage = other._storage; 64 | other._storage = nullptr; 65 | } 66 | return *this; 67 | } 68 | 69 | // Modifiers 70 | 71 | void reset() noexcept { reset(nullptr); } 72 | 73 | void reset(T ref = nullptr) noexcept { 74 | if (_storage != ref) { 75 | if (_storage) { 76 | CFRelease(_storage); 77 | } 78 | _storage = to_storage(ref); 79 | if (_storage) { 80 | CFRetain(_storage); 81 | } 82 | } 83 | } 84 | 85 | // Observers 86 | 87 | T get() const noexcept { return from_storage(_storage); }; 88 | 89 | explicit operator bool() const noexcept { return _storage != nullptr; } 90 | }; 91 | 92 | } // namespace util 93 | 94 | CF_ASSUME_NONNULL_END 95 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/FreeDeleter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | namespace util { 9 | 10 | class free_deleter { 11 | public: 12 | template void operator()(T *_Nullable ptr) { 13 | if (ptr) { 14 | free((void *)ptr); 15 | } 16 | } 17 | }; 18 | 19 | } // namespace util 20 | 21 | CF_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/HashTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | namespace util { 9 | 10 | class Heap; 11 | 12 | uint64_t string_hash(char const *str); 13 | 14 | class UntypedTable { 15 | public: 16 | using key_type = const void *_Nonnull; 17 | using nullable_key_type = const void *_Nullable; 18 | using value_type = const void *_Nullable; 19 | using size_type = uint64_t; 20 | using hasher = uint64_t (*)(void const *); 21 | using key_equal = bool (*)(void const *, void const *); 22 | using key_callback = void (*)(const key_type); 23 | using value_callback = void (*)(const value_type); 24 | using entry_callback = void (*)(const key_type, const value_type, void *context); 25 | 26 | private: 27 | struct HashNode { 28 | HashNode *next; 29 | key_type key; 30 | value_type value; 31 | uint64_t hash_value; 32 | }; 33 | using Bucket = HashNode *_Nonnull; 34 | 35 | hasher _hash; 36 | key_equal _compare; 37 | key_callback _did_remove_key; 38 | value_callback _did_remove_value; 39 | Heap *_heap; 40 | HashNode *_spare_node; 41 | Bucket *_Nonnull _buckets; 42 | uint64_t _count; 43 | uint64_t _bucket_mask; 44 | uint32_t _bucket_mask_width; 45 | bool _is_heap_owner; 46 | bool _compare_by_pointer; 47 | 48 | // Managing buckets 49 | void create_buckets(); 50 | void grow_buckets(); 51 | 52 | public: 53 | static UntypedTable *create(); 54 | static void destroy(UntypedTable *value); 55 | 56 | UntypedTable(); 57 | UntypedTable(hasher _Nullable custom_hasher, key_equal _Nullable custom_compare, 58 | key_callback _Nullable did_remove_key, value_callback _Nullable did_remove_value, 59 | Heap *_Nullable heap); 60 | ~UntypedTable(); 61 | 62 | // non-copyable 63 | UntypedTable(const UntypedTable &) = delete; 64 | UntypedTable &operator=(const UntypedTable &) = delete; 65 | 66 | // non-movable 67 | UntypedTable(UntypedTable &&) = delete; 68 | UntypedTable &operator=(UntypedTable &&) = delete; 69 | 70 | // Lookup 71 | bool empty() const noexcept { return _count == 0; }; 72 | size_type count() const noexcept { return _count; }; 73 | value_type lookup(key_type key, nullable_key_type *_Nullable found_key) const noexcept; 74 | void for_each(entry_callback body, void *context) const; 75 | 76 | // Modifiers 77 | bool insert(const key_type key, const value_type value); 78 | bool remove(const key_type key); 79 | bool remove_ptr(const key_type key); 80 | } SWIFT_UNSAFE_REFERENCE; 81 | 82 | template class Table : public UntypedTable { 83 | public: 84 | using key_type = Key; 85 | using value_type = Value; 86 | using hasher = uint64_t (*)(const key_type); 87 | using key_equal = bool (*)(const key_type, const key_type); 88 | using key_callback = void (*)(const key_type); 89 | using value_callback = void (*)(const value_type); 90 | using entry_callback = void (*)(const key_type, const value_type, void *context); 91 | 92 | Table() : UntypedTable() {}; 93 | Table(hasher _Nullable custom_hasher, key_equal _Nullable custom_compare, key_callback _Nullable did_remove_key, 94 | value_callback _Nullable did_remove_value, Heap *_Nullable heap) 95 | : UntypedTable(reinterpret_cast(custom_hasher), 96 | reinterpret_cast(custom_compare), 97 | reinterpret_cast(did_remove_key), 98 | reinterpret_cast(did_remove_value), heap) {}; 99 | 100 | // Lookup 101 | 102 | value_type lookup(const key_type key, key_type *_Nullable found_key) const noexcept { 103 | auto result = UntypedTable::lookup(*(void **)&key, 104 | reinterpret_cast(found_key)); 105 | return *(value_type *)&result; 106 | }; 107 | 108 | void for_each(entry_callback _Nonnull body, void *_Nullable context) const { 109 | UntypedTable::for_each((UntypedTable::entry_callback)body, context); 110 | }; 111 | 112 | // Modifying entries 113 | 114 | bool insert(const key_type key, const value_type value) { 115 | return UntypedTable::insert(*(void **)&key, *(void **)&value); 116 | }; 117 | bool remove(const key_type key) { return UntypedTable::remove(*(void **)&key); }; 118 | bool remove_ptr(const key_type key) { return UntypedTable::remove_ptr(key); }; 119 | }; 120 | 121 | } // namespace util 122 | 123 | CF_ASSUME_NONNULL_END 124 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/Heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | namespace util { 9 | 10 | class Heap { 11 | protected: 12 | typedef struct Node { 13 | struct Node *next; 14 | void *buffer; 15 | } Node; 16 | 17 | size_t _increment; 18 | Node *_node; 19 | char *_free_start; 20 | size_t _capacity; 21 | 22 | void *alloc_(size_t arg1); 23 | 24 | public: 25 | static constexpr size_t minimum_increment = 0x400; 26 | 27 | static Heap *create(char *_Nullable start, size_t capacity, size_t increment); 28 | static void destroy(Heap *value); 29 | 30 | Heap(char *_Nullable start, size_t capacity, size_t increment); 31 | ~Heap(); 32 | 33 | // non-copyable 34 | Heap(const Heap &) = delete; 35 | Heap &operator=(const Heap &) = delete; 36 | 37 | // non-movable 38 | Heap(Heap &&) = delete; 39 | Heap &operator=(Heap &&) = delete; 40 | 41 | template inline T *_Nonnull alloc(size_t count = 1) { 42 | return static_cast(alloc_(sizeof(T) * count)); 43 | }; 44 | void reset(char *_Nullable start, size_t capacity); 45 | 46 | // Debugging 47 | 48 | size_t num_nodes() const; 49 | size_t increment() const { return _increment; } 50 | size_t capacity() const { return _capacity; } 51 | 52 | void print() const; 53 | 54 | #ifdef SWIFT_TESTING 55 | uint64_t *alloc_uint64_t(size_t count = 1) { return alloc(count); } 56 | #endif 57 | 58 | } SWIFT_UNSAFE_REFERENCE; 59 | 60 | template class InlineHeap : public Heap { 61 | private: 62 | char _inline_buffer[_inline_size] = {}; 63 | 64 | public: 65 | InlineHeap() : Heap(_inline_buffer, _inline_size, 0) {} 66 | }; 67 | 68 | } // namespace util 69 | 70 | CF_ASSUME_NONNULL_END 71 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/List.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Utilities/Heap.h" 7 | 8 | CF_ASSUME_NONNULL_BEGIN 9 | 10 | namespace util { 11 | 12 | /// ForwardList is a linked list container that uses util::Heap to allocate nodes, 13 | /// reusing previously removed nodes where possible. 14 | template class ForwardList { 15 | public: 16 | using reference = T &; 17 | using const_reference = const T &; 18 | 19 | private: 20 | struct Node { 21 | Node *_Nullable next; 22 | T value; 23 | }; 24 | 25 | util::Heap *_heap; 26 | Node *_Nullable _front; 27 | Node *_Nullable _spare; 28 | bool _is_heap_owner; 29 | 30 | public: 31 | ForwardList(); 32 | ForwardList(util::Heap *heap); 33 | ~ForwardList(); 34 | 35 | // non-copyable 36 | ForwardList(const ForwardList &) = delete; 37 | ForwardList &operator=(const ForwardList &) = delete; 38 | 39 | // non-movable 40 | ForwardList(ForwardList &&) = delete; 41 | ForwardList &operator=(ForwardList &&) = delete; 42 | 43 | // MARK: Element access 44 | 45 | reference front(); 46 | const_reference front() const; 47 | 48 | // MARK: Capacity 49 | 50 | bool empty() const noexcept { return _front == nullptr; } 51 | 52 | // MARK: Modifiers 53 | 54 | void push_front(const T &value); 55 | void push_front(T &&value); 56 | template void emplace_front(Args &&...args); 57 | 58 | void pop_front(); 59 | }; 60 | 61 | template 62 | ForwardList::ForwardList() : _heap(new Heap(nullptr, 0, util::Heap::minimum_increment)), _is_heap_owner(true){}; 63 | 64 | template ForwardList::ForwardList(util::Heap *heap) : _heap(heap), _is_heap_owner(false){}; 65 | 66 | template ForwardList::~ForwardList() { 67 | if (_is_heap_owner && _heap) { 68 | delete _heap; 69 | } 70 | }; 71 | 72 | template ForwardList::reference ForwardList::front() { 73 | assert(!empty()); 74 | return _front->value; 75 | } 76 | 77 | template ForwardList::const_reference ForwardList::front() const { 78 | assert(!empty()); 79 | return _front->value; 80 | } 81 | 82 | template void ForwardList::push_front(const T &value) { 83 | Node *new_node; 84 | if (_spare != nullptr) { 85 | new_node = _spare; 86 | _spare = _spare->next; 87 | } else { 88 | new_node = _heap->alloc(); 89 | } 90 | new_node->next = _front; 91 | new_node->value = value; 92 | _front = new_node; 93 | } 94 | 95 | template void ForwardList::push_front(T &&value) { 96 | Node *new_node; 97 | if (_spare != nullptr) { 98 | new_node = _spare; 99 | _spare = _spare->previous; 100 | } else { 101 | new_node = _heap->alloc(); 102 | } 103 | new_node->next = _front; 104 | new_node->value = std::move(value); 105 | _front = new_node; 106 | } 107 | 108 | template template void ForwardList::emplace_front(Args &&...args) { 109 | Node *new_node; 110 | if (_spare != nullptr) { 111 | new_node = _spare; 112 | _spare = _spare->next; 113 | } else { 114 | new_node = _heap->alloc(); 115 | } 116 | new_node->next = _front; 117 | new (&new_node->value) T(args...); 118 | _front = new_node; 119 | } 120 | 121 | template void ForwardList::pop_front() { 122 | if (_front == nullptr) { 123 | return; 124 | } 125 | 126 | Node *next = _front->next; 127 | T value = _front->value; 128 | 129 | _front->next = _spare; 130 | _spare = _front; 131 | 132 | _front = next; 133 | } 134 | 135 | #ifdef SWIFT_TESTING 136 | 137 | class UInt64ForwardList : public ForwardList { 138 | public: 139 | static UInt64ForwardList *create(); 140 | static void destroy(UInt64ForwardList *value); 141 | 142 | bool empty() const noexcept; 143 | 144 | uint64_t front(); 145 | 146 | void push_front(const uint64_t &element); 147 | void push_front(uint64_t &&element); 148 | 149 | void pop_front(); 150 | 151 | } SWIFT_UNSAFE_REFERENCE; 152 | 153 | UInt64ForwardList *UInt64ForwardList::create() { return new UInt64ForwardList(); } 154 | 155 | void UInt64ForwardList::destroy(UInt64ForwardList *value) { delete value; } 156 | 157 | bool UInt64ForwardList::empty() const noexcept { return ForwardList::empty(); } 158 | 159 | uint64_t UInt64ForwardList::front() { return ForwardList::front(); } 160 | 161 | void UInt64ForwardList::push_front(const uint64_t &element) { ForwardList::push_front(element); } 162 | 163 | void UInt64ForwardList::push_front(uint64_t &&element) { ForwardList::push_front(element); } 164 | 165 | void UInt64ForwardList::pop_front() { ForwardList::pop_front(); } 166 | 167 | #endif 168 | 169 | } // namespace util 170 | 171 | CF_ASSUME_NONNULL_END 172 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/ObjCPointer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | CF_ASSUME_NONNULL_BEGIN 7 | 8 | // Redeclare APIs from the Objective-C runtime. 9 | // These functions are not available through public headers, but are guaranteed 10 | // to exist on OS X >= 10.9 and iOS >= 7.0. 11 | OBJC_EXPORT id objc_retain(id obj); 12 | OBJC_EXPORT void objc_release(id obj); 13 | 14 | namespace util { 15 | 16 | template class objc_ptr { 17 | private: 18 | id _storage; 19 | 20 | static inline id to_storage(T obj) { return (id)(obj); } 21 | static inline T from_storage(id storage) { return (T)storage; } 22 | 23 | public: 24 | constexpr objc_ptr() noexcept : _storage(nullptr) {} 25 | constexpr objc_ptr(std::nullptr_t) noexcept : _storage(nullptr) {} 26 | 27 | explicit objc_ptr(T obj) : _storage(to_storage(obj)) { 28 | if (_storage) { 29 | objc_retain(_storage); 30 | } 31 | } 32 | 33 | ~objc_ptr() { 34 | if (_storage) { 35 | objc_release(_storage); 36 | } 37 | } 38 | 39 | // Copy and move constructors 40 | 41 | objc_ptr(const objc_ptr &other) noexcept : _storage(other._storage) { 42 | if (_storage) { 43 | objc_retain(_storage); 44 | } 45 | } 46 | 47 | objc_ptr(objc_ptr &&other) noexcept : _storage(std::exchange(other._storage, nullptr)) {}; 48 | 49 | // Copy and move assignment operators 50 | 51 | objc_ptr &operator=(const objc_ptr &other) noexcept { 52 | if (this != &other) { 53 | if (_storage) { 54 | objc_release(_storage); 55 | } 56 | _storage = other._storage; 57 | if (_storage) { 58 | objc_retain(_storage); 59 | } 60 | } 61 | return *this; 62 | } 63 | 64 | objc_ptr &operator=(objc_ptr &&other) noexcept { 65 | if (this != &other) { 66 | if (_storage) { 67 | objc_release(_storage); 68 | } 69 | _storage = other._storage; 70 | other._storage = nullptr; 71 | } 72 | return *this; 73 | } 74 | 75 | // Modifiers 76 | 77 | void reset() noexcept { reset(nullptr); } 78 | 79 | void reset(T obj = nullptr) noexcept { 80 | if (_storage != obj) { 81 | if (_storage) { 82 | objc_release(_storage); 83 | } 84 | _storage = obj; 85 | if (_storage) { 86 | objc_retain(_storage); 87 | } 88 | } 89 | } 90 | 91 | // Observers 92 | 93 | T get() const noexcept { return from_storage(_storage); }; 94 | 95 | explicit operator bool() const noexcept { return _storage != nullptr; } 96 | }; 97 | 98 | } // namespace util 99 | 100 | CF_ASSUME_NONNULL_END 101 | -------------------------------------------------------------------------------- /Sources/Utilities/include/Utilities/TaggedPointer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | CF_ASSUME_NONNULL_BEGIN 6 | 7 | namespace util { 8 | 9 | template class tagged_ptr { 10 | private: 11 | enum : uintptr_t { 12 | mask = 0x1, 13 | }; 14 | 15 | uintptr_t _value; 16 | 17 | public: 18 | tagged_ptr() : _value(0){}; 19 | tagged_ptr(T *_Nullable value) : _value((uintptr_t)value){}; 20 | tagged_ptr(T *_Nullable value, bool tag) : _value(((uintptr_t)value & ~0x1) | (tag ? 1 : 0)){}; 21 | 22 | uintptr_t value() { return _value; }; 23 | bool tag() { return static_cast(_value & 0x1); }; 24 | tagged_ptr with_tag(bool tag) { return tagged_ptr(get(), tag); }; 25 | 26 | T *_Nullable get() { return reinterpret_cast(_value & ~mask); }; 27 | const T *_Nullable get() const { return reinterpret_cast(_value & ~mask); }; 28 | 29 | bool operator==(nullptr_t) const noexcept { return _value == 0; }; 30 | bool operator!=(nullptr_t) const noexcept { return _value != 0; }; 31 | }; 32 | 33 | } // namespace util 34 | 35 | CF_ASSUME_NONNULL_END 36 | -------------------------------------------------------------------------------- /Tests/ComputeCompatibilityTests/Shared: -------------------------------------------------------------------------------- 1 | ../ComputeTests/Shared -------------------------------------------------------------------------------- /Tests/ComputeCompatibilityTests/Shims.swift: -------------------------------------------------------------------------------- 1 | @_exported public import AttributeGraph 2 | 3 | typealias Graph = AGGraph 4 | typealias Subgraph = AGSubgraph 5 | -------------------------------------------------------------------------------- /Tests/ComputeTests/Shared/Runtime/CompareValuesTests.swift: -------------------------------------------------------------------------------- 1 | import Testing 2 | 3 | @Suite 4 | struct CompareValuesTests { 5 | 6 | @Test 7 | func intCompare() throws { 8 | #expect(compareValues(1, 1) == true) 9 | #expect(compareValues(1, 2) == false) 10 | } 11 | 12 | @Test 13 | func enumCompare() throws { 14 | enum A { case a, b } 15 | #expect(compareValues(A.a, A.a) == true) 16 | #expect(compareValues(A.a, A.b) == false) 17 | 18 | enum B { case a, b, c } 19 | let b = B.b 20 | withUnsafePointer(to: b) { p in 21 | p.withMemoryRebound(to: A.self, capacity: MemoryLayout.size) { pointer in 22 | #expect(compareValues(pointer.pointee, A.b) == true) 23 | } 24 | } 25 | withUnsafePointer(to: b) { p in 26 | p.withMemoryRebound(to: A.self, capacity: MemoryLayout.size) { pointer in 27 | #expect(compareValues(pointer.pointee, A.a) == false) 28 | } 29 | } 30 | } 31 | 32 | @Test 33 | func testStructCompare() throws { 34 | struct A1 { 35 | var a: Int 36 | var b: Bool 37 | } 38 | struct A2 { 39 | var a: Int 40 | var b: Bool 41 | } 42 | let a = A1(a: 1, b: true) 43 | let b = A1(a: 1, b: true) 44 | let c = A1(a: 1, b: false) 45 | #expect(compareValues(b, a) == true) 46 | #expect(compareValues(c, a) == false) 47 | let d = A2(a: 1, b: true) 48 | withUnsafePointer(to: d) { p in 49 | p.withMemoryRebound(to: A1.self, capacity: MemoryLayout.size) { pointer in 50 | #expect(compareValues(pointer.pointee, a) == true) 51 | } 52 | } 53 | withUnsafePointer(to: d) { p in 54 | p.withMemoryRebound(to: A1.self, capacity: MemoryLayout.size) { pointer in 55 | #expect(compareValues(pointer.pointee, c) == false) 56 | } 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Tests/ComputeTests/Shared/Runtime/ReflectionTests.swift: -------------------------------------------------------------------------------- 1 | import Testing 2 | 3 | @Suite 4 | struct ReflectionTests { 5 | 6 | @Test 7 | func reflectEmptyStruct() { 8 | 9 | struct EmptyStruct {} 10 | 11 | var fields: [(String, Int, any Any.Type)] = [] 12 | let finished = Metadata(EmptyStruct.self).forEachField(options: []) { 13 | fieldName, 14 | fieldOffset, 15 | fieldType in 16 | fields.append((String(cString: fieldName), fieldOffset, fieldType)) 17 | return true 18 | } 19 | 20 | #expect(finished == false) 21 | #expect(fields.count == 0) 22 | } 23 | 24 | @Test 25 | func reflectStaticString() { 26 | 27 | var fields: [(String, Int, any Any.Type)] = [] 28 | let finished = Metadata(StaticString.self).forEachField(options: []) { 29 | fieldName, 30 | fieldOffset, 31 | fieldType in 32 | fields.append((String(cString: fieldName), fieldOffset, fieldType)) 33 | return true 34 | } 35 | 36 | #expect(finished == true) 37 | #expect(fields.count == 3) 38 | 39 | #expect(fields[0].1 == 0) 40 | #expect(fields[1].1 == 8) 41 | #expect(fields[2].1 == 16) 42 | } 43 | 44 | @Test 45 | func reflectOptionalInt() { 46 | 47 | var fields: [(String, Int, any Any.Type)] = [] 48 | let finished = Metadata(Optional.self).forEachField(options: [.enumerateEnumCases]) { 49 | fieldName, 50 | fieldOffset, 51 | fieldType in 52 | fields.append((String(cString: fieldName), fieldOffset, fieldType)) 53 | return true 54 | } 55 | 56 | #expect(finished == true) 57 | #expect(fields.count == 1) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Tests/ComputeTests/Shared/Runtime/TupleTypeTests.swift: -------------------------------------------------------------------------------- 1 | import Testing 2 | 3 | @Suite 4 | struct TupleTypeTests { 5 | 6 | class T1 { 7 | var a = 0 8 | var b: Double = 0 9 | } 10 | 11 | struct T2 { 12 | var a: Int = 0 13 | var b: Double = 0 14 | } 15 | 16 | enum T3 { 17 | case a, b 18 | } 19 | 20 | @Test 21 | func initType() { 22 | #expect(TupleType(T1.self).rawValue == Metadata(T1.self).rawValue) 23 | #expect(TupleType([T1.self, T2.self]).rawValue == Metadata((T1, T2).self).rawValue) 24 | #expect(TupleType([T1.self, T2.self, T3.self]).rawValue == Metadata((T1, T2, T3).self).rawValue) 25 | } 26 | 27 | @Test 28 | func type() { 29 | #expect(TupleType([T1.self, T2.self, T3.self]).type == (T1, T2, T3).self) 30 | } 31 | 32 | @Test(arguments: [ 33 | (TupleType(Void.self), true, 0..<0), 34 | (TupleType(T1.self), false, 0..<1), 35 | (TupleType([T1.self, T2.self]), false, 0..<2), 36 | ]) 37 | func collectionAPI(tupleType: TupleType, expectedIsEmpty: Bool, expectedIndices: Range) { 38 | #expect(tupleType.isEmpty == expectedIsEmpty) 39 | #expect(tupleType.indices == expectedIndices) 40 | } 41 | 42 | @Test 43 | func elementTypeAndOffset() { 44 | let tupleType = TupleType([T1.self, T2.self, T3.self]) 45 | #expect(tupleType.type(at: 0) == T1.self) 46 | #expect(tupleType.type(at: 1) == T2.self) 47 | #expect(tupleType.type(at: 2) == T3.self) 48 | 49 | #expect(tupleType.offset(at: 0, as: T1.self) == 0) 50 | #expect(tupleType.offset(at: 1, as: T2.self) == 8) 51 | #expect(tupleType.offset(at: 2, as: T3.self) == 24) 52 | } 53 | 54 | @Test 55 | func getAndSetElement() { 56 | let tupleType = TupleType([T1.self, T2.self]) 57 | var tuple = (T1(), T2()) 58 | #expect(tuple.0.a == 0) 59 | #expect(tuple.0.b == 0) 60 | #expect(tuple.1.a == 0) 61 | #expect(tuple.1.b == 0) 62 | 63 | var newT1 = T1() 64 | newT1.a = 1 65 | var newT2 = T2(a: 2) 66 | 67 | withUnsafeMutablePointer(to: &tuple) { tuplePointer in 68 | withUnsafePointer(to: newT1) { 69 | tupleType.setElement(in: tuplePointer, at: 0, from: $0, options: .assignCopy) 70 | } 71 | #expect(tuplePointer.pointee.0.a == 1) 72 | #expect(tuplePointer.pointee.1.a == 0) 73 | withUnsafePointer(to: newT2) { 74 | tupleType.setElement(in: tuplePointer, at: 1, from: $0, options: .assignCopy) 75 | } 76 | #expect(tuplePointer.pointee.0.a == 1) 77 | #expect(tuplePointer.pointee.1.a == 2) 78 | } 79 | 80 | tuple.0.a = 3 81 | tuple.1.a = 4 82 | 83 | withUnsafeMutablePointer(to: &tuple) { tuplePointer in 84 | withUnsafeMutablePointer(to: &newT1) { 85 | tupleType.getElement(in: tuplePointer, at: 0, to: $0, options: .assignCopy) 86 | } 87 | #expect(newT1.a == 3) 88 | #expect(newT2.a == 2) 89 | 90 | withUnsafeMutablePointer(to: &newT2) { 91 | tupleType.getElement(in: tuplePointer, at: 1, to: $0, options: .assignCopy) 92 | } 93 | #expect(newT2.a == 4) 94 | } 95 | } 96 | } 97 | 98 | @Suite 99 | struct UnsafeMutableTupleTests { 100 | 101 | class T1 { 102 | var a = 0 103 | } 104 | 105 | struct T2 { 106 | var a = 0 107 | } 108 | 109 | @Test 110 | func buffer() { 111 | withUnsafeTuple(of: TupleType([T1.self, T2.self]), count: 1) { mutableTuple in 112 | let ref = T1() 113 | ref.a = 1 114 | mutableTuple.initialize(at: 0, to: ref) 115 | mutableTuple.initialize(at: 1, to: T2(a: 2)) 116 | 117 | let tuple = UnsafeTuple(type: mutableTuple.type, value: mutableTuple.value) 118 | let t1 = tuple[0] as T1 119 | let t2 = tuple[1] as T2 120 | 121 | #expect(t1 === ref) 122 | #expect(t1.a == 1) 123 | #expect(t2.a == 2) 124 | } 125 | } 126 | 127 | @Test 128 | func initialize() { 129 | let mutableTuple = UnsafeMutableTuple(with: TupleType([T1.self, T2.self])) 130 | 131 | #expect(mutableTuple.count == 2) 132 | #expect(mutableTuple.isEmpty == false) 133 | 134 | let t1 = T1() 135 | t1.a = 1 136 | let t2 = T2(a: 2) 137 | mutableTuple.initialize(at: 0, to: t1) 138 | mutableTuple.initialize(at: 1, to: t2) 139 | 140 | #expect((mutableTuple[0] as T1).a == 1) 141 | #expect((mutableTuple[1] as T2).a == 2) 142 | 143 | mutableTuple.deinitialize() 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /Tests/ComputeTests/Shared/TestTypes.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Class 4 | 5 | class TestClass { 6 | var a: Bool = false 7 | } 8 | 9 | // Struct 10 | 11 | struct TestStruct { 12 | var a: Bool = false 13 | } 14 | 15 | // Enum 16 | 17 | enum TestEnum { 18 | case a 19 | case b 20 | } 21 | 22 | enum TestTaggedEnum { 23 | case a(TestClass) 24 | case b(TestStruct) 25 | } 26 | 27 | indirect enum TestIndirectEnum { 28 | case a 29 | case b(TestIndirectEnum) 30 | } 31 | 32 | // Optional 33 | 34 | typealias TestOptionalClass = TestClass? 35 | typealias TestOptionalStruct = TestStruct? 36 | 37 | // Foreign Class 38 | 39 | typealias TestForeignClass = CFDate 40 | 41 | // ForeignReferenceType (non-swift non-objc-c class type) 42 | //typealias TestForeignReferenceType = util.UntypedTable 43 | 44 | // Opaque, type not exposed in metadata system 45 | 46 | // Tuple 47 | 48 | typealias TestTuple = (String, Int) 49 | 50 | // Function 51 | 52 | typealias TestFunction = (String) -> Int 53 | 54 | // Existentialtype 55 | 56 | typealias TestExistential = any Hashable 57 | typealias TestConstrainedExistential = any Sequence 58 | typealias TestComposedExistential = any Hashable & CustomStringConvertible 59 | 60 | // Metatype 61 | 62 | typealias TestMetatype = TestClass.Type 63 | 64 | // ObjC 65 | 66 | typealias TestObjCClass = NSDate 67 | 68 | // Existential metatype 69 | 70 | typealias TestExistentialMetatype = (any Hashable).Type 71 | 72 | // Nesting 73 | 74 | enum TestNamespace { 75 | struct TestNestedStruct {} 76 | } 77 | 78 | // Generic 79 | 80 | struct TestGenericStruct { 81 | struct TestNestedGenericStruct {} 82 | } 83 | 84 | // extended existential type 85 | 86 | // heap-allocated local variable using statically generated metadata 87 | // heap-allocated local variable using runtime instantiated meatdta 88 | 89 | // native error object 90 | 91 | // heap allocated task 92 | // non-task async ob 93 | 94 | // POD types 95 | 96 | struct PODStruct { 97 | var a: Int 98 | var b: Double 99 | var c: Float 100 | } 101 | 102 | // Enum types 103 | 104 | enum EmptyEnum {} 105 | 106 | enum CEnum { 107 | case a 108 | case b 109 | case c 110 | } 111 | 112 | enum TaggedEnum1 { 113 | case a(Int) 114 | } 115 | 116 | enum TaggedEnum { 117 | case a(Int) 118 | case b(Double) 119 | case c(Float) 120 | } 121 | 122 | indirect enum IndirectEnum { 123 | case a 124 | case b 125 | case c(IndirectEnum) 126 | } 127 | 128 | // Heap types 129 | 130 | class HeapClass { 131 | var a: Int = 0 132 | var b: Double = 0.0 133 | var c: Float = 0.0 134 | } 135 | 136 | // Product types 137 | 138 | //struct TestStruct { 139 | // var a: Void 140 | // 141 | // var b: Bool 142 | // 143 | // var c: Int 144 | // var d: Double 145 | // var e: Float 146 | // 147 | // var f: String 148 | // var g: Character 149 | // 150 | // var h: CEnum 151 | // var i: TaggedEnum 152 | // var j: IndirectEnum 153 | // 154 | // var k: [String] 155 | // var l: [String: String] 156 | // var m: Set 157 | // 158 | // var n: (String, String) 159 | // 160 | // var o: (Int) -> String 161 | // var p: any Equatable 162 | //} 163 | // 164 | //class TestClass { 165 | // var a: Void = () 166 | // 167 | // var b: Bool = false 168 | // 169 | // var c: Int = 0 170 | // var d: Double = 0.0 171 | // var e: Float = 0.0 172 | // 173 | // var f: String = "" 174 | // var g: Character = "\0" 175 | // 176 | // var h: CEnum = .a 177 | // var i: TaggedEnum = .a(0) 178 | // var j: IndirectEnum = .a 179 | // 180 | // var k: [String] = [] 181 | // var l: [String: String] = [:] 182 | // var m: Set = [] 183 | // 184 | // var n: (String, String) = ("", "") 185 | // 186 | // var o: (Int) -> String = { _ in "" } 187 | // var p: any Equatable = 0 188 | //} 189 | -------------------------------------------------------------------------------- /Tests/ComputeTests/Shared/reprinting.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Additionally writes any data written to standard output into the given output stream. 4 | /// 5 | /// - Parameters: 6 | /// - output: An output stream to receive the standard output text 7 | /// - encoding: The encoding to use when converting standard output into text. 8 | /// - body: A closure that is executed immediately. 9 | /// - Returns: The return value, if any, of the `body` closure. 10 | func reprintingStandardOutput( 11 | to output: inout Target, 12 | encoding: String.Encoding = .utf8, 13 | body: () -> Result 14 | ) 15 | async -> Result where Target: TextOutputStream 16 | { 17 | var result: Result? = nil 18 | 19 | let consumer = Pipe() // reads from stdout 20 | let producer = Pipe() // writes to stdout 21 | 22 | let stream = AsyncStream { continuation in 23 | let clonedStandardOutput = dup(STDOUT_FILENO) 24 | defer { 25 | dup2(clonedStandardOutput, STDOUT_FILENO) 26 | close(clonedStandardOutput) 27 | } 28 | 29 | dup2(STDOUT_FILENO, producer.fileHandleForWriting.fileDescriptor) 30 | dup2(consumer.fileHandleForWriting.fileDescriptor, STDOUT_FILENO) 31 | 32 | consumer.fileHandleForReading.readabilityHandler = { fileHandle in 33 | let chunk = fileHandle.availableData 34 | if chunk.isEmpty { 35 | continuation.finish() 36 | } else { 37 | continuation.yield(chunk) 38 | producer.fileHandleForWriting.write(chunk) 39 | } 40 | } 41 | 42 | result = body() 43 | try! consumer.fileHandleForWriting.close() 44 | } 45 | 46 | for await chunk in stream { 47 | output.write(String(data: chunk, encoding: encoding)!) 48 | } 49 | 50 | return result! 51 | } 52 | 53 | /// Additionally writes any data written to standard error into the given output stream. 54 | /// 55 | /// - Parameters: 56 | /// - output: An output stream to receive the standard error text 57 | /// - encoding: The encoding to use when converting standard output into text. 58 | /// - body: A closure that is executed immediately. 59 | /// - Returns: The return value, if any, of the `body` closure. 60 | 61 | func reprintingStandardError( 62 | to stream: inout Target, 63 | encoding: String.Encoding = .utf8, 64 | body: () -> Result 65 | ) async 66 | -> Result where Target: TextOutputStream 67 | { 68 | var result: Result? = nil 69 | 70 | let consumer = Pipe() // reads from stderr 71 | let producer = Pipe() // writes to stderr 72 | 73 | let chunks = AsyncStream { continuation in 74 | let clonedStandardError = dup(STDERR_FILENO) 75 | defer { 76 | dup2(clonedStandardError, STDERR_FILENO) 77 | close(clonedStandardError) 78 | } 79 | 80 | dup2(STDERR_FILENO, producer.fileHandleForWriting.fileDescriptor) 81 | dup2(consumer.fileHandleForWriting.fileDescriptor, STDERR_FILENO) 82 | 83 | consumer.fileHandleForReading.readabilityHandler = { fileHandle in 84 | let chunk = fileHandle.availableData 85 | if chunk.isEmpty { 86 | continuation.finish() 87 | } else { 88 | continuation.yield(chunk) 89 | producer.fileHandleForWriting.write(chunk) 90 | } 91 | } 92 | 93 | result = body() 94 | try! consumer.fileHandleForWriting.close() 95 | } 96 | 97 | for await chunk in chunks { 98 | guard let chunkString = String(data: chunk, encoding: encoding) else { 99 | continue 100 | } 101 | stream.write(chunkString) 102 | } 103 | 104 | return result! 105 | } 106 | -------------------------------------------------------------------------------- /Tests/ComputeTests/Shims.swift: -------------------------------------------------------------------------------- 1 | @_exported public import Compute 2 | -------------------------------------------------------------------------------- /Tests/UtilitiesTests/HashTableTests.swift: -------------------------------------------------------------------------------- 1 | import Testing 2 | import Utilities 3 | 4 | @Suite("HashTable tests") 5 | struct HashTableTests { 6 | 7 | @Test("Initialize empty table") 8 | func initEmpty() { 9 | let table = util.UntypedTable.create() 10 | defer { 11 | util.UntypedTable.destroy(table) 12 | } 13 | 14 | #expect(table.empty()) 15 | #expect(table.count() == 0) 16 | } 17 | 18 | @Test("Insert entry") 19 | func insertEntry() { 20 | class Value { 21 | let prop: String 22 | init(prop: String) { 23 | self.prop = prop 24 | } 25 | } 26 | 27 | let table = util.UntypedTable.create() 28 | defer { 29 | util.UntypedTable.destroy(table) 30 | } 31 | 32 | let key = "key1" 33 | let value = Value(prop: "valueProp") 34 | withUnsafePointer(to: key) { keyPointer in 35 | withUnsafePointer(to: value) { valuePointer in 36 | let inserted = table.insert(keyPointer, valuePointer) 37 | 38 | #expect(inserted == true) 39 | #expect(table.count() == 1) 40 | 41 | let foundValue = table.__lookupUnsafe(keyPointer, nil) 42 | #expect(foundValue?.assumingMemoryBound(to: Value.self).pointee.prop == "valueProp") 43 | } 44 | } 45 | } 46 | 47 | @Test("Remove entry") 48 | func removeEntry() { 49 | class Value { 50 | let prop: String 51 | init(prop: String) { 52 | self.prop = prop 53 | } 54 | } 55 | 56 | let table = util.UntypedTable.create() 57 | defer { 58 | util.UntypedTable.destroy(table) 59 | } 60 | 61 | let key = "key1" 62 | let value = Value(prop: "valueProp") 63 | withUnsafePointer(to: key) { keyPointer in 64 | withUnsafePointer(to: value) { valuePointer in 65 | let inserted = table.insert(keyPointer, valuePointer) 66 | 67 | try! #require(inserted == true) 68 | try! #require(table.count() == 1) 69 | 70 | let removed = table.remove(keyPointer) 71 | 72 | #expect(removed == true) 73 | #expect(table.count() == 0) 74 | 75 | let foundValue = table.__lookupUnsafe(keyPointer, nil) 76 | #expect(foundValue == nil) 77 | } 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /Tests/UtilitiesTests/HeapTests.swift: -------------------------------------------------------------------------------- 1 | import Testing 2 | import Utilities 3 | 4 | @Suite("Heap tests") 5 | struct HeapTests { 6 | 7 | let nodeSize = 16 8 | 9 | @Test("Initializing with default arguments") 10 | func initDefault() { 11 | let heap = util.Heap.create(nil, 0, 0) 12 | defer { 13 | util.Heap.destroy(heap) 14 | } 15 | 16 | #expect(heap.capacity() == 0) 17 | #expect(heap.increment() == 0x2000) 18 | #expect(heap.num_nodes() == 0) 19 | } 20 | 21 | @Test("Allocating small object uses node") 22 | func allocateSmallObjects() { 23 | let heap = util.Heap.create(nil, 0, 0) 24 | defer { 25 | util.Heap.destroy(heap) 26 | } 27 | 28 | let _ = heap.__alloc_uint64_tUnsafe() 29 | 30 | // creates 1 node 31 | #expect(heap.num_nodes() == 1) 32 | #expect(heap.capacity() == 0x2000 - nodeSize - 8) 33 | 34 | let _ = heap.__alloc_uint64_tUnsafe() 35 | 36 | // second object is allocated from same node 37 | #expect(heap.num_nodes() == 1) 38 | #expect(heap.capacity() == 0x2000 - nodeSize - 2 * 8) 39 | } 40 | 41 | @Test("Allocating large object creates new node") 42 | func allocateLargeObject() { 43 | let heap = util.Heap.create(nil, 0, 0) 44 | defer { 45 | util.Heap.destroy(heap) 46 | } 47 | 48 | // larger than minimum increment 49 | let _ = heap.__alloc_uint64_tUnsafe(500) 50 | 51 | // data is allocated from second node 52 | #expect(heap.num_nodes() == 2) 53 | #expect(heap.capacity() == 0x2000 - 2 * nodeSize) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Tests/UtilitiesTests/ListTests.swift: -------------------------------------------------------------------------------- 1 | import Testing 2 | import Utilities 3 | 4 | @Suite("List tests") 5 | struct ListTests { 6 | 7 | @Test("Initialize empty list") 8 | func initEmpty() { 9 | let list = util.UInt64ForwardList.create() 10 | defer { 11 | util.UInt64ForwardList.destroy(list) 12 | } 13 | 14 | #expect(list.empty()) 15 | } 16 | 17 | @Test("Push element") 18 | func pushElement() { 19 | let list = util.UInt64ForwardList.create() 20 | defer { 21 | util.UInt64ForwardList.destroy(list) 22 | } 23 | 24 | list.push_front(1) 25 | 26 | #expect(list.empty() == false) 27 | 28 | let front = list.front() 29 | #expect(front == 1) 30 | } 31 | 32 | @Test("Push multiple elements") 33 | func pushMultipleElements() { 34 | let list = util.UInt64ForwardList.create() 35 | defer { 36 | util.UInt64ForwardList.destroy(list) 37 | } 38 | 39 | list.push_front(1) 40 | list.push_front(2) 41 | list.push_front(3) 42 | 43 | let front = list.front() 44 | #expect(front == 3) 45 | } 46 | 47 | @Test("Remove element") 48 | func removeElement() { 49 | let list = util.UInt64ForwardList.create() 50 | defer { 51 | util.UInt64ForwardList.destroy(list) 52 | } 53 | 54 | list.push_front(1) 55 | list.push_front(2) 56 | list.push_front(3) 57 | list.pop_front() 58 | 59 | let front = list.front() 60 | #expect(front == 2) 61 | } 62 | 63 | } 64 | --------------------------------------------------------------------------------