Skip to content

Commit 2fd9e93

Browse files
authored
Merge pull request #7199 from rjmccall/indexed-isa-metadata-reader-3.1
Fix MetadataReader's isa-chasing on platforms that use indexed isa.
2 parents 16fb513 + 064ffc2 commit 2fd9e93

File tree

1 file changed

+161
-23
lines changed

1 file changed

+161
-23
lines changed

include/swift/Remote/MetadataReader.h

Lines changed: 161 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,46 @@ class MetadataReader {
498498
using OwnedProtocolDescriptorRef =
499499
std::unique_ptr<const TargetProtocolDescriptor<Runtime>, delete_with_free>;
500500

501-
/// Cached isa mask.
502-
StoredPointer isaMask;
503-
bool hasIsaMask = false;
501+
enum class IsaEncodingKind {
502+
/// We haven't checked yet.
503+
Unknown,
504+
505+
/// There was an error trying to find out the isa encoding.
506+
Error,
507+
508+
/// There's no special isa encoding.
509+
None,
510+
511+
/// There's an unconditional mask to apply to the isa pointer.
512+
/// - IsaMask stores the mask.
513+
Masked,
514+
515+
/// Isa pointers are indexed. If applying a mask yields a magic value,
516+
/// applying a different mask and shifting yields an index into a global
517+
/// array of class pointers. Otherwise, the isa pointer is just a raw
518+
/// class pointer.
519+
/// - IsaIndexMask stores the index mask.
520+
/// - IsaIndexShift stores the index shift.
521+
/// - IsaMagicMask stores the magic value mask.
522+
/// - IsaMagicValue stores the magic value.
523+
/// - IndexedClassesPointer stores the pointer to the start of the
524+
/// indexed classes array; this is constant throughout the program.
525+
/// - IndexedClassesCountPointer stores a pointer to the number
526+
/// of elements in the indexed classes array.
527+
Indexed
528+
};
529+
530+
IsaEncodingKind IsaEncoding = IsaEncodingKind::Unknown;
531+
union {
532+
StoredPointer IsaMask;
533+
StoredPointer IsaIndexMask;
534+
};
535+
StoredPointer IsaIndexShift;
536+
StoredPointer IsaMagicMask;
537+
StoredPointer IsaMagicValue;
538+
StoredPointer IndexedClassesPointer;
539+
StoredPointer IndexedClassesCountPointer;
540+
StoredPointer LastIndexedClassesCount = 0;
504541

505542
public:
506543
BuilderType Builder;
@@ -535,15 +572,12 @@ class MetadataReader {
535572

536573
/// Get the remote process's swift_isaMask.
537574
std::pair<bool, StoredPointer> readIsaMask() {
538-
auto address = Reader->getSymbolAddress("swift_isaMask");
539-
if (!address)
540-
return {false, 0};
575+
auto encoding = getIsaEncoding();
576+
if (encoding != IsaEncodingKind::Masked)
577+
// Still return success if there's no isa encoding at all.
578+
return {encoding == IsaEncodingKind::None, 0};
541579

542-
if (!Reader->readInteger(address, &isaMask))
543-
return {false, 0};
544-
545-
hasIsaMask = true;
546-
return {true, isaMask};
580+
return {true, IsaMask};
547581
}
548582

549583
/// Given a remote pointer to metadata, attempt to discover its MetadataKind.
@@ -774,20 +808,64 @@ class MetadataReader {
774808

775809
/// Read the isa pointer of a class or closure context instance and apply
776810
/// the isa mask.
777-
std::pair<bool, StoredPointer> readMetadataFromInstance(
778-
StoredPointer ObjectAddress) {
779-
StoredPointer isaMaskValue = ~0;
780-
auto isaMask = readIsaMask();
781-
if (isaMask.first)
782-
isaMaskValue = isaMask.second;
783-
784-
StoredPointer MetadataAddress;
785-
if (!Reader->readBytes(RemoteAddress(ObjectAddress),
786-
(uint8_t*)&MetadataAddress,
787-
sizeof(StoredPointer)))
811+
std::pair<bool, StoredPointer>
812+
readMetadataFromInstance(StoredPointer objectAddress) {
813+
StoredPointer isa;
814+
if (!Reader->readInteger(RemoteAddress(objectAddress), &isa))
788815
return {false, 0};
789816

790-
return {true, MetadataAddress & isaMaskValue};
817+
switch (getIsaEncoding()) {
818+
case IsaEncodingKind::Unknown:
819+
case IsaEncodingKind::Error:
820+
return {false, 0};
821+
822+
case IsaEncodingKind::None:
823+
return {true, isa};
824+
825+
case IsaEncodingKind::Masked:
826+
return {true, isa & IsaMask};
827+
828+
case IsaEncodingKind::Indexed: {
829+
// If applying the magic mask doesn't give us the magic value,
830+
// it's not an indexed isa.
831+
if ((isa & IsaMagicMask) != IsaMagicValue)
832+
return {true, isa};
833+
834+
// Extract the index.
835+
auto classIndex = (isa & IsaIndexMask) >> IsaIndexShift;
836+
837+
// 0 is never a valid index.
838+
if (classIndex == 0) {
839+
return {false, 0};
840+
841+
// If the index is out of range, it's an error; but check for an
842+
// update first. (This will also trigger the first time because
843+
// we initialize LastIndexedClassesCount to 0).
844+
} else if (classIndex >= LastIndexedClassesCount) {
845+
StoredPointer count;
846+
if (!Reader->readInteger(RemoteAddress(IndexedClassesCountPointer),
847+
&count)) {
848+
return {false, 0};
849+
}
850+
851+
LastIndexedClassesCount = count;
852+
if (classIndex >= count) {
853+
return {false, 0};
854+
}
855+
}
856+
857+
// Find the address of the appropriate array element.
858+
RemoteAddress eltPointer =
859+
RemoteAddress(IndexedClassesPointer
860+
+ classIndex * sizeof(StoredPointer));
861+
StoredPointer metadataPointer;
862+
if (!Reader->readInteger(eltPointer, &metadataPointer)) {
863+
return {false, 0};
864+
}
865+
866+
return {true, metadataPointer};
867+
}
868+
}
791869
}
792870

793871
/// Read the parent type metadata from a nested nominal type metadata.
@@ -1241,6 +1319,66 @@ class MetadataReader {
12411319
return dataPtr;
12421320
}
12431321

1322+
IsaEncodingKind getIsaEncoding() {
1323+
if (IsaEncoding != IsaEncodingKind::Unknown)
1324+
return IsaEncoding;
1325+
1326+
auto finish = [&](IsaEncodingKind result) -> IsaEncodingKind {
1327+
IsaEncoding = result;
1328+
return result;
1329+
};
1330+
1331+
/// Look up the given global symbol and bind 'varname' to its
1332+
/// address if its exists.
1333+
# define tryFindSymbol(varname, symbolName) \
1334+
auto varname = Reader->getSymbolAddress(symbolName); \
1335+
if (!varname) \
1336+
return finish(IsaEncodingKind::Error)
1337+
/// Read from the given pointer into 'dest'.
1338+
# define tryReadSymbol(varname, dest) do { \
1339+
if (!Reader->readInteger(varname, &dest)) \
1340+
return finish(IsaEncodingKind::Error); \
1341+
} while (0)
1342+
/// Read from the given global symbol into 'dest'.
1343+
# define tryFindAndReadSymbol(dest, symbolName) do { \
1344+
tryFindSymbol(_address, symbolName); \
1345+
tryReadSymbol(_address, dest); \
1346+
} while (0)
1347+
1348+
// Check for the magic-mask symbol that indicates that the ObjC
1349+
// runtime is using indexed ISAs.
1350+
if (auto magicMaskAddress =
1351+
Reader->getSymbolAddress("objc_debug_indexed_isa_magic_mask")) {
1352+
tryReadSymbol(magicMaskAddress, IsaMagicMask);
1353+
if (IsaMagicMask != 0) {
1354+
tryFindAndReadSymbol(IsaMagicValue,
1355+
"objc_debug_indexed_isa_magic_value");
1356+
tryFindAndReadSymbol(IsaIndexMask,
1357+
"objc_debug_indexed_isa_index_mask");
1358+
tryFindAndReadSymbol(IsaIndexShift,
1359+
"objc_debug_indexed_isa_index_shift");
1360+
tryFindSymbol(indexedClasses, "objc_indexed_classes");
1361+
IndexedClassesPointer = indexedClasses.getAddressData();
1362+
tryFindSymbol(indexedClassesCount, "objc_indexed_classes_count");
1363+
IndexedClassesCountPointer = indexedClassesCount.getAddressData();
1364+
1365+
return finish(IsaEncodingKind::Indexed);
1366+
}
1367+
}
1368+
1369+
// Check for the ISA mask symbol. This has to come second because
1370+
// the standard library will define this even if the ObjC runtime
1371+
// doesn't use it.
1372+
if (auto maskAddress = Reader->getSymbolAddress("swift_isaMask")) {
1373+
tryReadSymbol(maskAddress, IsaMask);
1374+
if (IsaMask != 0) {
1375+
return finish(IsaEncodingKind::Masked);
1376+
}
1377+
}
1378+
1379+
return finish(IsaEncodingKind::None);
1380+
}
1381+
12441382
template <class T>
12451383
static constexpr T roundUpToAlignment(T offset, T alignment) {
12461384
return (offset + alignment - 1) & ~(alignment - 1);

0 commit comments

Comments
 (0)