Skip to content

Commit 87232e5

Browse files
committed
Add a runtime-internal function, _enumerateTypes(fromImageAt:conformingTo:_:), that will walk the protocol conformance tables looking for types that conform to a given protocol.
1 parent e67e5c1 commit 87232e5

13 files changed

+465
-35
lines changed

stdlib/public/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ set(SWIFTLIB_ESSENTIAL
173173
SwiftNativeNSArray.swift
174174
TemporaryAllocation.swift
175175
ThreadLocalStorage.swift
176+
TypeDiscovery.swift
176177
UIntBuffer.swift
177178
UnavailableStringAPIs.swift
178179
UnicodeData.swift

stdlib/public/core/GroupInfo.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@
155155
"Mirror.swift",
156156
"Mirrors.swift",
157157
"ReflectionMirror.swift",
158-
"ObjectIdentifier.swift"
158+
"ObjectIdentifier.swift",
159+
"TypeDiscovery.swift"
159160
],
160161
"Math": [
161162
"SetAlgebra.swift",
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// A function that instantiates the type described by a type descriptor.
14+
///
15+
/// - Parameters:
16+
/// - descriptor: A type descriptor as passed to `_swift_enumerateTypes()`'s
17+
/// callback.
18+
///
19+
/// - Returns: The initialized type corresponding to `descriptor`, or `nil` if
20+
/// the type could not be initialized. This value can subsequently be cast to
21+
/// `Any.Type` using `unsafeBitCast(_:to:)`.
22+
private typealias _TypeGetter = @convention(c) (
23+
_ descriptor: UnsafeRawPointer
24+
) -> UnsafeRawPointer?
25+
26+
/// A type describing another type available in the current process.
27+
@available(SwiftStdlib 9999, *)
28+
public struct _TypeRecord {
29+
/// Initialize an instance of this type.
30+
///
31+
/// - Parameters:
32+
/// - name: The name of this type.
33+
/// - typeInstantiator: A function to call that calls back into the runtime
34+
/// to instantiate the type.
35+
fileprivate init(
36+
_name name: String,
37+
instantiatingTypeUsing typeInstantiator: @escaping () -> Any.Type?
38+
) {
39+
self.name = name
40+
_typeInstantiator = typeInstantiator
41+
}
42+
43+
/// The name of this type.
44+
public let name: String
45+
46+
/// Storage for `type`.
47+
///
48+
/// This function calls back into the runtime to instantiate the type.
49+
private let _typeInstantiator: () -> Any.Type?
50+
51+
/// The Swift type described by this type record.
52+
///
53+
/// On first use, this property will "instantiate" the type, meaning that the
54+
/// type will become fully realized and will be available for use in Swift. If
55+
/// that operation fails, the value of this property is `nil`.
56+
public var type: Any.Type? {
57+
return _typeInstantiator()
58+
}
59+
}
60+
61+
@_silgen_name("swift_enumerateAllTypesFromImage")
62+
private func _swift_enumerateTypes(
63+
fromImageAt imageAddress: UnsafeRawPointer?,
64+
_ body: (
65+
_ name: UnsafePointer<CChar>,
66+
_ descriptor: UnsafeRawPointer,
67+
_ typeGetter: @escaping _TypeGetter,
68+
_ stop: inout Bool
69+
) throws -> Void
70+
) rethrows
71+
72+
/// Enumerate all types in a given image.
73+
///
74+
/// - Parameters:
75+
/// - imageAddress: A platform-specific pointer to the image of interest. The
76+
/// image must have been loaded into the current process. For the binary of
77+
/// the calling function, you can pass `#dsohandle`. For all binaries, pass
78+
/// `nil` (the default.)
79+
/// - body: A closure to invoke once per conforming type.
80+
///
81+
/// - Throws: Whatever is thrown by `body`.
82+
///
83+
/// This function walks all known types in the given image and passes them to
84+
/// `body` for evaluation.
85+
///
86+
/// Generic types are not enumerated.
87+
///
88+
/// - Bug: Objective-C class lookups are not supported yet.
89+
@available(SwiftStdlib 9999, *)
90+
public func _enumerateTypes(
91+
fromImageAt imageAddress: UnsafeRawPointer? = nil,
92+
_ body: (_ typeRecord: _TypeRecord, _ stop: inout Bool) throws -> Void
93+
) rethrows {
94+
try _swift_enumerateTypes(
95+
fromImageAt: imageAddress
96+
) { name, descriptor, getType, stop in
97+
let typeRecord = _TypeRecord(
98+
_name: String(cString: name),
99+
instantiatingTypeUsing: {
100+
getType(descriptor).map { unsafeBitCast($0, to: Any.Type.self) }
101+
}
102+
)
103+
try body(typeRecord, &stop)
104+
}
105+
}

stdlib/public/runtime/ImageInspection.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,27 @@ void initializeTypeMetadataRecordLookup();
7474
void initializeDynamicReplacementLookup();
7575

7676
// Callbacks to register metadata from an image to the runtime.
77-
void addImageProtocolsBlockCallback(const void *start, uintptr_t size);
78-
void addImageProtocolsBlockCallbackUnsafe(const void *start, uintptr_t size);
79-
void addImageProtocolConformanceBlockCallback(const void *start,
77+
void addImageProtocolsBlockCallback(const void *image,
78+
const void *start,
79+
uintptr_t size);
80+
void addImageProtocolsBlockCallbackUnsafe(const void *image,
81+
const void *start,
82+
uintptr_t size);
83+
void addImageProtocolConformanceBlockCallback(const void *image,
84+
const void *start,
8085
uintptr_t size);
81-
void addImageProtocolConformanceBlockCallbackUnsafe(const void *start,
86+
void addImageProtocolConformanceBlockCallbackUnsafe(const void *image,
87+
const void *start,
8288
uintptr_t size);
83-
void addImageTypeMetadataRecordBlockCallback(const void *start,
89+
void addImageTypeMetadataRecordBlockCallback(const void *image,
90+
const void *start,
8491
uintptr_t size);
85-
void addImageTypeMetadataRecordBlockCallbackUnsafe(const void *start,
92+
void addImageTypeMetadataRecordBlockCallbackUnsafe(const void *image,
93+
const void *start,
8694
uintptr_t size);
87-
void addImageDynamicReplacementBlockCallback(const void *start, uintptr_t size,
95+
void addImageDynamicReplacementBlockCallback(const void *image,
96+
const void *start,
97+
uintptr_t size,
8898
const void *start2,
8999
uintptr_t size2);
90100

stdlib/public/runtime/ImageInspectionCommon.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void record(swift::MetadataSections *sections) {
4444
}
4545

4646
SWIFT_RUNTIME_EXPORT
47-
void swift_addNewDSOImage(const void *addr) {
47+
void swift_addNewDSOImage(const void *imageAddress, const void *addr) {
4848
// We cast off the const in order to update the linked list
4949
// data structure. This is safe to do since we don't touch
5050
// any other fields.
@@ -56,19 +56,23 @@ void swift_addNewDSOImage(const void *addr) {
5656
const auto &protocols_section = sections->swift5_protocols;
5757
const void *protocols = reinterpret_cast<void *>(protocols_section.start);
5858
if (protocols_section.length)
59-
swift::addImageProtocolsBlockCallback(protocols, protocols_section.length);
59+
swift::addImageProtocolsBlockCallback(image,
60+
protocols,
61+
protocols_section.length);
6062

6163
const auto &protocol_conformances = sections->swift5_protocol_conformances;
6264
const void *conformances =
6365
reinterpret_cast<void *>(protocol_conformances.start);
6466
if (protocol_conformances.length)
65-
swift::addImageProtocolConformanceBlockCallback(conformances,
67+
swift::addImageProtocolConformanceBlockCallback(image, conformances,
6668
protocol_conformances.length);
6769

6870
const auto &type_metadata = sections->swift5_type_metadata;
6971
const void *metadata = reinterpret_cast<void *>(type_metadata.start);
7072
if (type_metadata.length)
71-
swift::addImageTypeMetadataRecordBlockCallback(metadata, type_metadata.length);
73+
swift::addImageTypeMetadataRecordBlockCallback(image,
74+
metadata,
75+
type_metadata.length);
7276

7377
const auto &dynamic_replacements = sections->swift5_replace;
7478
const auto *replacements =
@@ -77,7 +81,7 @@ void swift_addNewDSOImage(const void *addr) {
7781
const auto &dynamic_replacements_some = sections->swift5_replac2;
7882
const auto *replacements_some =
7983
reinterpret_cast<void *>(dynamic_replacements_some.start);
80-
swift::addImageDynamicReplacementBlockCallback(
84+
swift::addImageDynamicReplacementBlockCallback(image,
8185
replacements, dynamic_replacements.length, replacements_some,
8286
dynamic_replacements_some.length);
8387
}
@@ -89,7 +93,7 @@ void swift::initializeProtocolLookup() {
8993
const swift::MetadataSectionRange &protocols =
9094
sections->swift5_protocols;
9195
if (protocols.length)
92-
addImageProtocolsBlockCallbackUnsafe(
96+
addImageProtocolsBlockCallbackUnsafe(image,
9397
reinterpret_cast<void *>(protocols.start), protocols.length);
9498

9599
if (sections->next == registered)
@@ -104,7 +108,7 @@ void swift::initializeProtocolConformanceLookup() {
104108
const swift::MetadataSectionRange &conformances =
105109
sections->swift5_protocol_conformances;
106110
if (conformances.length)
107-
addImageProtocolConformanceBlockCallbackUnsafe(
111+
addImageProtocolConformanceBlockCallbackUnsafe(image,
108112
reinterpret_cast<void *>(conformances.start), conformances.length);
109113

110114
if (sections->next == registered)
@@ -119,7 +123,7 @@ void swift::initializeTypeMetadataRecordLookup() {
119123
const swift::MetadataSectionRange &type_metadata =
120124
sections->swift5_type_metadata;
121125
if (type_metadata.length)
122-
addImageTypeMetadataRecordBlockCallbackUnsafe(
126+
addImageTypeMetadataRecordBlockCallbackUnsafe(image,
123127
reinterpret_cast<void *>(type_metadata.start), type_metadata.length);
124128

125129
if (sections->next == registered)
@@ -177,4 +181,4 @@ size_t swift_getMetadataSectionCount() {
177181

178182
#endif // !defined(__MACH__)
179183

180-
#endif // SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H
184+
#endif // SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H

stdlib/public/runtime/ImageInspectionCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct SectionInfo {
5959

6060
// Called by injected constructors when a dynamic library is loaded.
6161
SWIFT_RUNTIME_EXPORT
62-
void swift_addNewDSOImage(const void *addr);
62+
void swift_addNewDSOImage(const void *imageAddress, const void *addr);
6363

6464
#ifndef NDEBUG
6565

stdlib/public/runtime/ImageInspectionMachO.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ using mach_header_platform = mach_header;
5252
#endif
5353

5454
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
55-
void CONSUME_BLOCK(const void *start, uintptr_t size)>
55+
void CONSUME_BLOCK(const void *imageAddress,
56+
const void *start, uintptr_t size)>
5657
void addImageCallback(const mach_header *mh) {
5758
#if __POINTER_WIDTH__ == 64
5859
assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!");
@@ -68,17 +69,19 @@ void addImageCallback(const mach_header *mh) {
6869
if (!section)
6970
return;
7071

71-
CONSUME_BLOCK(section, size);
72+
CONSUME_BLOCK(mh, section, size);
7273
}
7374
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
74-
void CONSUME_BLOCK(const void *start, uintptr_t size)>
75+
void CONSUME_BLOCK(const void *imageAddress,
76+
const void *start, uintptr_t size)>
7577
void addImageCallback(const mach_header *mh, intptr_t vmaddr_slide) {
7678
addImageCallback<SEGMENT_NAME, SECTION_NAME, CONSUME_BLOCK>(mh);
7779
}
7880

7981
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
8082
const char *SEGMENT_NAME2, const char *SECTION_NAME2,
81-
void CONSUME_BLOCK(const void *start, uintptr_t size,
83+
void CONSUME_BLOCK(const void *imageAddress,
84+
const void *start, uintptr_t size,
8285
const void *start2, uintptr_t size2)>
8386
void addImageCallback2Sections(const mach_header *mh) {
8487
#if __POINTER_WIDTH__ == 64
@@ -104,11 +107,12 @@ void addImageCallback2Sections(const mach_header *mh) {
104107
if (!section2)
105108
size2 = 0;
106109

107-
CONSUME_BLOCK(section, size, section2, size2);
110+
CONSUME_BLOCK(mh, section, size, section2, size2);
108111
}
109112
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
110113
const char *SEGMENT_NAME2, const char *SECTION_NAME2,
111-
void CONSUME_BLOCK(const void *start, uintptr_t size,
114+
void CONSUME_BLOCK(const void *imageAddress,
115+
const void *start, uintptr_t size,
112116
const void *start2, uintptr_t size2)>
113117
void addImageCallback2Sections(const mach_header *mh, intptr_t vmaddr_slide) {
114118
addImageCallback2Sections<SEGMENT_NAME, SECTION_NAME,

0 commit comments

Comments
 (0)