-
Notifications
You must be signed in to change notification settings - Fork 17
fix(swift-sections): guard SymbolIndexStore race + align section readers with ABI #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import MachOKit | ||
| import MachOReading | ||
| import MachOExtensions | ||
|
|
||
| public protocol RelativeDirectPointerIntPairProtocol<Pointee>: RelativeDirectPointerProtocol { | ||
| typealias Integer = Value.RawValue | ||
| associatedtype Value: RawRepresentable where Value.RawValue: FixedWidthInteger | ||
| var relativeOffsetPlusInt: Offset { get } | ||
| } | ||
|
|
||
| extension RelativeDirectPointerIntPairProtocol { | ||
| public var relativeOffset: Offset { | ||
| relativeOffsetPlusInt & ~mask | ||
| } | ||
|
|
||
| public var mask: Offset { | ||
| Offset(MemoryLayout<Offset>.alignment - 1) | ||
| } | ||
|
|
||
| public var intValue: Integer { | ||
| numericCast(relativeOffsetPlusInt & mask) | ||
| } | ||
|
|
||
| public var value: Value { | ||
| return Value(rawValue: intValue)! | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import MachOReading | ||
| import MachOResolving | ||
| import MachOExtensions | ||
|
|
||
| public struct TargetRelativeDirectPointerIntPair<Pointee: Resolvable, Offset: FixedWidthInteger & SignedInteger & Sendable, Value: RawRepresentable>: RelativeDirectPointerIntPairProtocol where Value.RawValue: FixedWidthInteger { | ||
| public let relativeOffsetPlusInt: Offset | ||
|
|
||
| public init(relativeOffsetPlusInt: Offset) { | ||
| self.relativeOffsetPlusInt = relativeOffsetPlusInt | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import Foundation | ||
| import MachOKit | ||
| import MachOFoundation | ||
|
|
||
| /// Mirrors `TargetProtocolRecord` from | ||
| /// `swift/include/swift/ABI/Metadata.h:2766`. One entry per 4-byte slot of | ||
| /// `__swift5_protos`. | ||
| /// | ||
| /// The C++ declaration stores a single | ||
| /// `RelativeContextPointerIntPair<Runtime, bool, TargetProtocolDescriptor>` | ||
| /// (`MetadataRef.h:109` — a `RelativeIndirectablePointerIntPair` with | ||
| /// `nullable=true`). The low bit is the indirect flag handled by the pointer | ||
| /// itself; the next bit ("reserved for future use", see | ||
| /// `Metadata.h:2769`) is exposed via `Bit` and currently ignored by the | ||
| /// runtime (`MetadataLookup.cpp:821` only calls `getPointer()`). | ||
| public struct ProtocolRecord: ResolvableLocatableLayoutWrapper { | ||
| public struct Layout: LayoutProtocol { | ||
| public let `protocol`: RelativeIndirectablePointerIntPair<ProtocolDescriptor?, Bit, Pointer<ProtocolDescriptor?>> | ||
| } | ||
|
|
||
| public let offset: Int | ||
| public var layout: Layout | ||
|
|
||
| public init(layout: Layout, offset: Int) { | ||
| self.offset = offset | ||
| self.layout = layout | ||
| } | ||
| } | ||
|
|
||
| extension ProtocolRecord { | ||
| public func protocolDescriptor<MachO: MachOSwiftSectionRepresentableWithCache>(in machO: MachO) throws -> ProtocolDescriptor? { | ||
| try layout.protocol.resolve(from: offset(of: \.protocol), in: machO) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import Foundation | ||
| import MachOKit | ||
| import MachOFoundation | ||
|
|
||
| /// Mirrors `TargetTypeMetadataRecord` from | ||
| /// `swift/include/swift/ABI/Metadata.h:2720`. One entry per 4-byte slot of | ||
| /// `__swift5_types` / `__swift5_types2`. | ||
| /// | ||
| /// In C++ the record is a union over two arms, both | ||
| /// `RelativeDirectPointerIntPair<…, TypeReferenceKind>` with identical | ||
| /// in-memory layout, so a single storage field is enough; the | ||
| /// `TypeReferenceKind` tag picks which arm to resolve at access time. | ||
| public struct TypeMetadataRecord: ResolvableLocatableLayoutWrapper { | ||
| public struct Layout: LayoutProtocol { | ||
| public let nominalTypeDescriptor: RelativeDirectPointerIntPair<ContextDescriptorWrapper, TypeReferenceKind> | ||
| } | ||
|
|
||
| public let offset: Int | ||
| public var layout: Layout | ||
|
|
||
| public init(layout: Layout, offset: Int) { | ||
| self.offset = offset | ||
| self.layout = layout | ||
| } | ||
| } | ||
|
|
||
| extension TypeMetadataRecord { | ||
| public var typeKind: TypeReferenceKind { | ||
| return layout.nominalTypeDescriptor.value | ||
| } | ||
|
|
||
| /// Resolves the referenced context descriptor, branching on | ||
| /// `TypeReferenceKind` the same way Swift runtime does in | ||
| /// `TargetTypeMetadataRecord::getContextDescriptor()` | ||
| /// (`swift/include/swift/ABI/Metadata.h:2743`). ObjC kinds are never | ||
| /// populated in this section (see the comment at Metadata.h:2751); return | ||
| /// `nil` for them to mirror the runtime's `nullptr` fallback. | ||
| public func contextDescriptor<MachO: MachOSwiftSectionRepresentableWithCache>(in machO: MachO) throws -> ContextDescriptorWrapper? { | ||
| let fieldOffset = offset(of: \.nominalTypeDescriptor) | ||
| let relativeOffset = layout.nominalTypeDescriptor.relativeOffset | ||
| switch typeKind { | ||
| case .directTypeDescriptor: | ||
| let pointer = RelativeDirectPointer<ContextDescriptorWrapper>(relativeOffset: relativeOffset) | ||
| return try pointer.resolve(from: fieldOffset, in: machO) | ||
| case .indirectTypeDescriptor: | ||
| let pointer = RelativeIndirectPointer<ContextDescriptorWrapper, Pointer<ContextDescriptorWrapper>>(relativeOffset: relativeOffset) | ||
| return try pointer.resolve(from: fieldOffset, in: machO) | ||
| case .directObjCClassName, .indirectObjCClass: | ||
| return nil | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -152,6 +152,7 @@ public final class SymbolIndexStore: SharedCache<SymbolIndexStore.Storage>, @unc | |
|
|
||
| private(set) var symbolsByOffset: OrderedDictionary<Int, [Symbol]> = [:] | ||
|
|
||
| @Mutex | ||
| private(set) var demangledNodeBySymbol: [Symbol: Node] = [:] | ||
|
Comment on lines
+155
to
156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While |
||
|
|
||
|
Comment on lines
+155
to
157
|
||
| private(set) var thunkAttributeMembersByKindAndTypeName: [Node.Kind: [String: [ThunkAttributeMember]]] = [:] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,12 +72,7 @@ final class GenericSpecializationTests: MachOImageTests, @unchecked Sendable { | |
| ) | ||
| try #expect(#require(metadata.value.resolve().struct).fieldOffsets() == [0, 8, 16]) | ||
| } | ||
| } | ||
|
|
||
| // MARK: - GenericSpecializer API Tests | ||
|
|
||
| @Suite | ||
| struct GenericSpecializerAPITests { | ||
|
|
||
| @Test func makeRequest() async throws { | ||
| let machO = MachOImage.current() | ||
|
Comment on lines
74
to
77
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR description says CI should pass
--no-paralleltoswift test, but these invocations still run with default parallelism. If disabling parallelism is required to avoid cross-suite races, add--no-parallelhere (or update the PR description if that’s no longer the approach).