|
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