|
18 | 18 | #define SWIFT_REMOTE_METADATAREADER_H |
19 | 19 |
|
20 | 20 |
|
| 21 | +#include "swift/ABI/Metadata.h" |
21 | 22 | #include "swift/Runtime/Metadata.h" |
22 | 23 | #include "swift/Remote/MemoryReader.h" |
23 | 24 | #include "swift/Demangling/Demangler.h" |
@@ -1451,135 +1452,107 @@ class MetadataReader { |
1451 | 1452 | if (address == 0) |
1452 | 1453 | return nullptr; |
1453 | 1454 |
|
| 1455 | + auto remoteAddress = RemoteAddress(address); |
| 1456 | + auto ptr = Reader->readBytes(remoteAddress, |
| 1457 | + sizeof(TargetContextDescriptor<Runtime>)); |
| 1458 | + if (!ptr) |
| 1459 | + return nullptr; |
| 1460 | + |
1454 | 1461 | auto cached = ContextDescriptorCache.find(address); |
1455 | 1462 | if (cached != ContextDescriptorCache.end()) |
1456 | 1463 | return ContextDescriptorRef( |
1457 | 1464 | address, reinterpret_cast<const TargetContextDescriptor<Runtime> *>( |
1458 | 1465 | cached->second.get())); |
1459 | 1466 |
|
1460 | | - // Read the flags to figure out how much space we should read. |
1461 | | - ContextDescriptorFlags flags; |
1462 | | - if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags, |
1463 | | - sizeof(flags))) |
1464 | | - return nullptr; |
1465 | | - |
1466 | | - TypeContextDescriptorFlags typeFlags(flags.getKindSpecificFlags()); |
1467 | | - uint64_t baseSize = 0; |
1468 | | - uint64_t genericHeaderSize = sizeof(GenericContextDescriptorHeader); |
1469 | | - uint64_t metadataInitSize = 0; |
1470 | | - bool hasVTable = false; |
1471 | | - |
1472 | | - auto readMetadataInitSize = [&]() -> unsigned { |
1473 | | - switch (typeFlags.getMetadataInitialization()) { |
1474 | | - case TypeContextDescriptorFlags::NoMetadataInitialization: |
1475 | | - return 0; |
1476 | | - case TypeContextDescriptorFlags::SingletonMetadataInitialization: |
1477 | | - // FIXME: classes |
1478 | | - return sizeof(TargetSingletonMetadataInitialization<Runtime>); |
1479 | | - case TypeContextDescriptorFlags::ForeignMetadataInitialization: |
1480 | | - return sizeof(TargetForeignMetadataInitialization<Runtime>); |
1481 | | - } |
1482 | | - return 0; |
1483 | | - }; |
1484 | | - |
1485 | | - switch (flags.getKind()) { |
| 1467 | + bool success = false; |
| 1468 | + switch ( |
| 1469 | + reinterpret_cast<const TargetContextDescriptor<Runtime> *>(ptr.get()) |
| 1470 | + ->getKind()) { |
1486 | 1471 | case ContextDescriptorKind::Module: |
1487 | | - baseSize = sizeof(TargetModuleContextDescriptor<Runtime>); |
| 1472 | + ptr = Reader->readBytes(remoteAddress, |
| 1473 | + sizeof(TargetModuleContextDescriptor<Runtime>)); |
| 1474 | + success = ptr != nullptr; |
1488 | 1475 | break; |
1489 | | - // TODO: Should we include trailing generic arguments in this load? |
1490 | 1476 | case ContextDescriptorKind::Extension: |
1491 | | - baseSize = sizeof(TargetExtensionContextDescriptor<Runtime>); |
| 1477 | + success = |
| 1478 | + readFullContextDescriptor<TargetExtensionContextDescriptor<Runtime>>( |
| 1479 | + remoteAddress, ptr); |
1492 | 1480 | break; |
1493 | 1481 | case ContextDescriptorKind::Anonymous: |
1494 | | - baseSize = sizeof(TargetAnonymousContextDescriptor<Runtime>); |
1495 | | - if (AnonymousContextDescriptorFlags(flags.getKindSpecificFlags()) |
1496 | | - .hasMangledName()) { |
1497 | | - metadataInitSize = sizeof(TargetMangledContextName<Runtime>); |
1498 | | - } |
| 1482 | + success = |
| 1483 | + readFullContextDescriptor<TargetAnonymousContextDescriptor<Runtime>>( |
| 1484 | + remoteAddress, ptr); |
1499 | 1485 | break; |
1500 | 1486 | case ContextDescriptorKind::Class: |
1501 | | - baseSize = sizeof(TargetClassDescriptor<Runtime>); |
1502 | | - genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); |
1503 | | - hasVTable = typeFlags.class_hasVTable(); |
1504 | | - metadataInitSize = readMetadataInitSize(); |
| 1487 | + success = readFullContextDescriptor<TargetClassDescriptor<Runtime>>( |
| 1488 | + remoteAddress, ptr); |
1505 | 1489 | break; |
1506 | 1490 | case ContextDescriptorKind::Enum: |
1507 | | - baseSize = sizeof(TargetEnumDescriptor<Runtime>); |
1508 | | - genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); |
1509 | | - metadataInitSize = readMetadataInitSize(); |
| 1491 | + success = readFullContextDescriptor<TargetEnumDescriptor<Runtime>>( |
| 1492 | + remoteAddress, ptr); |
1510 | 1493 | break; |
1511 | 1494 | case ContextDescriptorKind::Struct: |
1512 | | - baseSize = sizeof(TargetStructDescriptor<Runtime>); |
1513 | | - genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); |
1514 | | - metadataInitSize = readMetadataInitSize(); |
| 1495 | + success = readFullContextDescriptor<TargetStructDescriptor<Runtime>>( |
| 1496 | + remoteAddress, ptr); |
1515 | 1497 | break; |
1516 | 1498 | case ContextDescriptorKind::Protocol: |
1517 | | - baseSize = sizeof(TargetProtocolDescriptor<Runtime>); |
| 1499 | + success = readFullContextDescriptor<TargetProtocolDescriptor<Runtime>>( |
| 1500 | + remoteAddress, ptr); |
1518 | 1501 | break; |
1519 | 1502 | case ContextDescriptorKind::OpaqueType: |
1520 | | - baseSize = sizeof(TargetOpaqueTypeDescriptor<Runtime>); |
1521 | | - metadataInitSize = |
1522 | | - sizeof(typename Runtime::template RelativeDirectPointer<const char>) |
1523 | | - * flags.getKindSpecificFlags(); |
| 1503 | + success = readFullContextDescriptor<TargetOpaqueTypeDescriptor<Runtime>>( |
| 1504 | + remoteAddress, ptr); |
1524 | 1505 | break; |
1525 | 1506 | default: |
1526 | 1507 | // We don't know about this kind of context. |
1527 | 1508 | return nullptr; |
1528 | 1509 | } |
1529 | | - |
1530 | | - // Determine the full size of the descriptor. This is reimplementing a fair |
1531 | | - // bit of TrailingObjects but for out-of-process; maybe there's a way to |
1532 | | - // factor the layout stuff out... |
1533 | | - uint64_t genericsSize = 0; |
1534 | | - if (flags.isGeneric()) { |
1535 | | - GenericContextDescriptorHeader header; |
1536 | | - auto headerAddr = address |
1537 | | - + baseSize |
1538 | | - + genericHeaderSize |
1539 | | - - sizeof(header); |
1540 | | - |
1541 | | - if (!Reader->readBytes(RemoteAddress(headerAddr), |
1542 | | - (uint8_t*)&header, sizeof(header))) |
1543 | | - return nullptr; |
1544 | | - |
1545 | | - genericsSize = genericHeaderSize |
1546 | | - + (header.NumParams + 3u & ~3u) |
1547 | | - + header.NumRequirements |
1548 | | - * sizeof(TargetGenericRequirementDescriptor<Runtime>); |
1549 | | - } |
1550 | | - |
1551 | | - uint64_t vtableSize = 0; |
1552 | | - if (hasVTable) { |
1553 | | - TargetVTableDescriptorHeader<Runtime> header; |
1554 | | - auto headerAddr = address |
1555 | | - + baseSize |
1556 | | - + genericsSize |
1557 | | - + metadataInitSize; |
1558 | | - |
1559 | | - if (!Reader->readBytes(RemoteAddress(headerAddr), |
1560 | | - (uint8_t*)&header, sizeof(header))) |
1561 | | - return nullptr; |
1562 | | - |
1563 | | - vtableSize = sizeof(header) |
1564 | | - + header.VTableSize * sizeof(TargetMethodDescriptor<Runtime>); |
1565 | | - } |
1566 | | - |
1567 | | - uint64_t size = baseSize + genericsSize + metadataInitSize + vtableSize; |
1568 | | - if (size > MaxMetadataSize) |
1569 | | - return nullptr; |
1570 | | - auto readResult = Reader->readBytes(RemoteAddress(address), size); |
1571 | | - if (!readResult) |
| 1510 | + if (!success) |
1572 | 1511 | return nullptr; |
1573 | 1512 |
|
1574 | | - auto descriptor = |
1575 | | - reinterpret_cast<const TargetContextDescriptor<Runtime> *>( |
1576 | | - readResult.get()); |
1577 | | - |
1578 | | - ContextDescriptorCache.insert( |
1579 | | - std::make_pair(address, std::move(readResult))); |
| 1513 | + auto *descriptor = |
| 1514 | + reinterpret_cast<const TargetContextDescriptor<Runtime> *>(ptr.get()); |
| 1515 | + ContextDescriptorCache.insert(std::make_pair(address, std::move(ptr))); |
1580 | 1516 | return ContextDescriptorRef(address, descriptor); |
1581 | 1517 | } |
1582 | | - |
| 1518 | + |
| 1519 | + template <typename DescriptorTy> |
| 1520 | + bool readFullContextDescriptor(RemoteAddress address, |
| 1521 | + MemoryReader::ReadBytesResult &ptr) { |
| 1522 | + // Read the full base descriptor if it's bigger than what we have so far. |
| 1523 | + if (sizeof(DescriptorTy) > sizeof(TargetContextDescriptor<Runtime>)) { |
| 1524 | + ptr = Reader->readObj<DescriptorTy>(address); |
| 1525 | + if (!ptr) |
| 1526 | + return false; |
| 1527 | + } |
| 1528 | + |
| 1529 | + // We don't know how much memory we need to read to get all the trailing |
| 1530 | + // objects, but we need to read the memory to figure out how much memory we |
| 1531 | + // need to read. Handle this by reading incrementally. |
| 1532 | + // |
| 1533 | + // We rely on the fact that each trailing object's count depends only on |
| 1534 | + // that comes before it. If we've read the first N trailing objects, then we |
| 1535 | + // can safely compute the size with N+1 trailing objects. If that size is |
| 1536 | + // bigger than what we've read so far, re-read the descriptor with the new |
| 1537 | + // size. Once we've walked through all the trailing objects, we've read |
| 1538 | + // everything. |
| 1539 | + |
| 1540 | + size_t sizeSoFar = sizeof(DescriptorTy); |
| 1541 | + |
| 1542 | + for (size_t i = 0; i < DescriptorTy::trailingTypeCount(); i++) { |
| 1543 | + const DescriptorTy *descriptorSoFar = |
| 1544 | + reinterpret_cast<const DescriptorTy *>(ptr.get()); |
| 1545 | + size_t thisSize = descriptorSoFar->sizeWithTrailingTypeCount(i); |
| 1546 | + if (thisSize > sizeSoFar) { |
| 1547 | + ptr = Reader->readBytes(address, thisSize); |
| 1548 | + if (!ptr) |
| 1549 | + return false; |
| 1550 | + sizeSoFar = thisSize; |
| 1551 | + } |
| 1552 | + } |
| 1553 | + return true; |
| 1554 | + } |
| 1555 | + |
1583 | 1556 | /// Demangle the entity represented by a symbolic reference to a given symbol name. |
1584 | 1557 | Demangle::NodePointer |
1585 | 1558 | buildContextManglingForSymbol(StringRef symbol, Demangler &dem) { |
|
0 commit comments