|
29 | 29 | #include "llvm/ADT/DenseMap.h"
|
30 | 30 | #include "../CompatibilityOverride/CompatibilityOverride.h"
|
31 | 31 | #include "ImageInspection.h"
|
| 32 | +#include "ImageInspectionCommon.h" |
32 | 33 | #include "Private.h"
|
| 34 | +#include "TypeDiscovery.h" |
33 | 35 |
|
34 | 36 | #include <vector>
|
35 | 37 |
|
| 38 | +#if defined(__MACH__) |
| 39 | +#include <mach-o/dyld.h> |
| 40 | +#include <mach-o/getsect.h> |
| 41 | +#endif |
| 42 | + |
36 | 43 | #if __has_include(<mach-o/dyld_priv.h>)
|
37 | 44 | #include <mach-o/dyld_priv.h>
|
38 | 45 | #define DYLD_EXPECTED_SWIFT_OPTIMIZATIONS_VERSION 1u
|
@@ -1271,5 +1278,188 @@ const Metadata *swift::findConformingSuperclass(
|
1271 | 1278 | return conformingType;
|
1272 | 1279 | }
|
1273 | 1280 |
|
| 1281 | +/// Walk the conformances in a \c ConformanceSection instance, check if they |
| 1282 | +/// specify conformance to all the specified protocols, and call \a body for the |
| 1283 | +/// types that match. |
| 1284 | +SWIFT_CC(swift) |
| 1285 | +static void _enumerateConformingTypesFromSection( |
| 1286 | + const ConformanceSection *section, |
| 1287 | + size_t count, |
| 1288 | + const llvm::ArrayRef<ProtocolDescriptorRef>& protocols, |
| 1289 | + TypeEnumerationFunction body, |
| 1290 | + void *bodyContext, |
| 1291 | + bool *stop, |
| 1292 | + SWIFT_CONTEXT void *context, |
| 1293 | + SWIFT_ERROR_RESULT SwiftError **error) { |
| 1294 | + |
| 1295 | + for (size_t i = 0; i < count; i++) { |
| 1296 | + for (const auto& record : *section) { |
| 1297 | + auto protocolDescriptor = record->getProtocol(); |
| 1298 | + auto metadata = record->getCanonicalTypeMetadata(); |
| 1299 | + if (!protocolDescriptor || !metadata) { |
| 1300 | + // This record does not contain the info we're interested in. |
| 1301 | + continue; |
| 1302 | + } |
| 1303 | + |
| 1304 | + for (const auto& protocol : protocols) { |
| 1305 | + const auto& swiftProtocol = protocol.getSwiftProtocol(); |
| 1306 | + if (!swift_conformsToProtocol(metadata, swiftProtocol)) { |
| 1307 | + // This type does not conform to the specified protocol(s), so skip. |
| 1308 | + continue; |
| 1309 | + } |
| 1310 | + } |
| 1311 | + |
| 1312 | + body(metadata, stop, bodyContext, error); |
| 1313 | + if (*stop || *error) { |
| 1314 | + return; |
| 1315 | + } |
| 1316 | + } |
| 1317 | + } |
| 1318 | +} |
| 1319 | + |
| 1320 | +#if defined(__MACH__) |
| 1321 | +/// Get the conformance section of a given Mach-O image. |
| 1322 | +/// |
| 1323 | +/// If the image does not have a conformance section, returns \c llvm::None. |
| 1324 | +static llvm::Optional<ConformanceSection> |
| 1325 | +_getConformanceSectionFromMachImage(const void *imageAddress) { |
| 1326 | + unsigned long sectionSize = 0; |
| 1327 | +#ifdef __LP64__ |
| 1328 | + typedef const mach_header_64 *MachHeaderAddress; |
| 1329 | +#else |
| 1330 | + typedef const mach_header *MachHeaderAddress; |
| 1331 | +#endif |
| 1332 | + const auto& sectionData = getsectiondata((MachHeaderAddress)imageAddress, |
| 1333 | + SEG_TEXT, |
| 1334 | + MachOProtocolConformancesSection, |
| 1335 | + §ionSize); |
| 1336 | + if (sectionData) { |
| 1337 | + return ConformanceSection(sectionData, sectionSize); |
| 1338 | + } |
| 1339 | + |
| 1340 | + return llvm::None; |
| 1341 | +} |
| 1342 | +#endif |
| 1343 | + |
| 1344 | +SWIFT_CC(swift) |
| 1345 | +void swift::swift_enumerateConformingTypesFromImage( |
| 1346 | + const void *imageAddress, |
| 1347 | + const Metadata *protocolMetadata, |
| 1348 | + TypeEnumerationFunction body, |
| 1349 | + void *bodyContext, |
| 1350 | + SWIFT_CONTEXT void *context, |
| 1351 | + SWIFT_ERROR_RESULT SwiftError **error) { |
| 1352 | + |
| 1353 | + // Find the protocol(s) requested by the caller. |
| 1354 | + auto existentialType = dyn_cast<ExistentialTypeMetadata>(protocolMetadata); |
| 1355 | + if (!existentialType) { |
| 1356 | + auto typeName = swift_getTypeName(protocolMetadata, true); |
| 1357 | + swift::fatalError( |
| 1358 | + 0, |
| 1359 | + "_enumerateTypes(fromImageAt:conformingTo:_:) can only test for " |
| 1360 | + "conformance to a protocol, but %.*s is not a protocol.", |
| 1361 | + (int)typeName.length, typeName.data); |
| 1362 | + } |
| 1363 | + const auto& protocols = existentialType->getProtocols(); |
| 1364 | + |
| 1365 | + if (protocols.empty()) { |
| 1366 | + swift::fatalError( |
| 1367 | + 0, |
| 1368 | + "Any is not a protocol and _enumerateTypes(fromImageAt:conformingTo:_:) " |
| 1369 | + "cannot test for conformance to it."); |
| 1370 | + } |
| 1371 | + |
| 1372 | +#if SWIFT_OBJC_INTEROP |
| 1373 | + // Check for any Objective-C protocols in the input. We do not currently |
| 1374 | + // support searching for Objective-C protocol conformances because they do not |
| 1375 | + // produce conformance records in the compiled binary. In the future, if we |
| 1376 | + // detect any such protocols, we can use objc_copyClassList() to add to the |
| 1377 | + // enumerated set (taking care not to enumerate a class twice if it conforms |
| 1378 | + // to an Objective-C protocol *and* a Swift protocol.) |
| 1379 | + for (const auto& protocol : protocols) { |
| 1380 | + if (protocol.isObjC()) { |
| 1381 | + swift::fatalError( |
| 1382 | + 0, |
| 1383 | + "_enumerateTypes(fromImageAt:conformingTo:_:) does not currently " |
| 1384 | + "support Objective-C protocols such as %s.", |
| 1385 | + protocol.getName()); |
| 1386 | + } |
| 1387 | + } |
| 1388 | +#endif |
| 1389 | + |
| 1390 | +#if defined(__WASM__) |
| 1391 | + // Swift+WASM does not support dynamic linking and #dsohandle is 0, so |
| 1392 | + // ignore the passed image address and iterate over any/all available |
| 1393 | + // sections. Presumably only one will be available. |
| 1394 | + imageAddress = nullptr; |
| 1395 | +#endif |
| 1396 | + |
| 1397 | + // Callback parameters (hoisted out of the loops.) |
| 1398 | + bool stop = false; |
| 1399 | + *error = nullptr; |
| 1400 | + |
| 1401 | +#if defined(__MACH__) |
| 1402 | + // This platform has dyld and we can use it instead of walking the section |
| 1403 | + // table. Takes care of the nuances of DYLD shared cache support. |
| 1404 | + if (imageAddress) { |
| 1405 | + if (auto section = _getConformanceSectionFromMachImage(imageAddress)) { |
| 1406 | + _enumerateConformingTypesFromSection(section.getPointer(), 1, |
| 1407 | + protocols, body, bodyContext, |
| 1408 | + &stop, context, error); |
| 1409 | + } |
| 1410 | + |
| 1411 | + } else { |
| 1412 | + // Walk all loaded images and consider each one in turn. The calls into dyld |
| 1413 | + // aren't thread-safe (another thread could modify the set of loaded images) |
| 1414 | + // but not in a "I'm going to crash" sense, just a "missed an image" sense. |
| 1415 | + auto count = _dyld_image_count(); |
| 1416 | + for (uint32_t i = 0; i < count; i++) { |
| 1417 | + const auto& imageAddress = _dyld_get_image_header(i); |
| 1418 | + if (!imageAddress) { |
| 1419 | + continue; |
| 1420 | + } |
| 1421 | + |
| 1422 | + if (auto section = _getConformanceSectionFromMachImage(imageAddress)) { |
| 1423 | + _enumerateConformingTypesFromSection(section.getPointer(), 1, |
| 1424 | + protocols, body, bodyContext, |
| 1425 | + &stop, context, error); |
| 1426 | + if (stop || *error) { |
| 1427 | + return; |
| 1428 | + } |
| 1429 | + } |
| 1430 | + } |
| 1431 | + } |
| 1432 | + |
| 1433 | +#else |
| 1434 | + // This platform doesn't have getsectiondata(), so walk all sections in the |
| 1435 | + // conformances table. |
| 1436 | + auto snapshot = Conformances.get().SectionsToScan.snapshot(); |
| 1437 | + |
| 1438 | + if (imageAddress) { |
| 1439 | + // FIXME: This operation is somewhat costly and could probably be optimized on a per-platform basis. |
| 1440 | + for (const auto& section : snapshot) { |
| 1441 | + // Check if this section came from the image of interest. |
| 1442 | + SymbolInfo info; |
| 1443 | + if (!lookupSymbol(section.begin(), &info)) { |
| 1444 | + continue; |
| 1445 | + } |
| 1446 | + |
| 1447 | + if (info.baseAddress == imageAddress) { |
| 1448 | + _enumerateConformingTypesFromSection(§ion, 1, |
| 1449 | + protocols, body, bodyContext, |
| 1450 | + &stop, context, error); |
| 1451 | + return; |
| 1452 | + } |
| 1453 | + } |
| 1454 | + |
| 1455 | + } else { |
| 1456 | + // Walk all sections. |
| 1457 | + _enumerateConformingTypesFromSection(snapshot.begin(), snapshot.count(), |
| 1458 | + protocols, body, bodyContext, |
| 1459 | + &stop, context, error); |
| 1460 | + } |
| 1461 | +#endif |
| 1462 | +} |
| 1463 | + |
1274 | 1464 | #define OVERRIDE_PROTOCOLCONFORMANCE COMPATIBILITY_OVERRIDE
|
1275 | 1465 | #include COMPATIBILITY_OVERRIDE_INCLUDE_PATH
|
0 commit comments