Skip to content

Commit dc3abd1

Browse files
authored
MetadataReader: Add support for Objective-C tagged pointers (swiftlang#22498)
This allows Remote Mirrors and RemoteAST to inspect existentials containing instances of imported classes.
1 parent b0fbbb3 commit dc3abd1

File tree

3 files changed

+197
-3
lines changed

3 files changed

+197
-3
lines changed

include/swift/Remote/MetadataReader.h

Lines changed: 153 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,38 @@ class MetadataReader {
171171
StoredPointer IndexedClassesCountPointer;
172172
StoredPointer LastIndexedClassesCount = 0;
173173

174+
enum class TaggedPointerEncodingKind {
175+
/// We haven't checked yet.
176+
Unknown,
177+
178+
/// There was an error trying to find out the tagged pointer encoding.
179+
Error,
180+
181+
/// The "extended" encoding.
182+
///
183+
/// 1 bit: is-tagged
184+
/// 3 bits: class index (for objc_debug_taggedpointer_classes[])
185+
/// 60 bits: payload
186+
///
187+
/// Class index 0b111 represents 256 additional classes:
188+
///
189+
/// 1 bit: is-tagged
190+
/// 3 bits: 0b111
191+
/// 8 bits: extended class index (for objc_debug_taggedpointer_ext_classes[])
192+
/// 54 bits: payload
193+
Extended
194+
};
195+
TaggedPointerEncodingKind TaggedPointerEncoding =
196+
TaggedPointerEncodingKind::Unknown;
197+
StoredPointer TaggedPointerMask;
198+
StoredPointer TaggedPointerSlotShift;
199+
StoredPointer TaggedPointerSlotMask;
200+
StoredPointer TaggedPointerClasses;
201+
StoredPointer TaggedPointerExtendedMask;
202+
StoredPointer TaggedPointerExtendedSlotShift;
203+
StoredPointer TaggedPointerExtendedSlotMask;
204+
StoredPointer TaggedPointerExtendedClasses;
205+
174206
Demangle::NodeFactory Factory;
175207

176208
Demangle::NodeFactory &getNodeFactory() { return Factory; }
@@ -463,10 +495,28 @@ class MetadataReader {
463495
if (!Meta) return BuiltType();
464496

465497
switch (Meta->getKind()) {
466-
case MetadataKind::Class:
467-
if (!cast<TargetClassMetadata<Runtime>>(Meta)->isTypeMetadata())
468-
return BuiltType();
498+
case MetadataKind::Class: {
499+
auto classMeta = cast<TargetClassMetadata<Runtime>>(Meta);
500+
if (!classMeta->isTypeMetadata()) {
501+
std::string className;
502+
if (!readObjCClassName(MetadataAddress, className))
503+
return BuiltType();
504+
505+
auto BuiltObjCClass = Builder.createObjCClassType(std::move(className));
506+
if (!BuiltObjCClass) {
507+
// Try the superclass.
508+
if (!classMeta->Superclass)
509+
return BuiltType();
510+
511+
return readTypeFromMetadata(classMeta->Superclass,
512+
skipArtificialSubclasses);
513+
}
514+
515+
TypeCache[MetadataAddress] = BuiltObjCClass;
516+
return BuiltObjCClass;
517+
}
469518
return readNominalTypeFromMetadata(Meta, skipArtificialSubclasses);
519+
}
470520
case MetadataKind::Struct:
471521
case MetadataKind::Enum:
472522
case MetadataKind::Optional:
@@ -657,10 +707,48 @@ class MetadataReader {
657707
return buildContextMangling(context, Dem);
658708
}
659709

710+
bool isTaggedPointer(StoredPointer objectAddress) {
711+
if (getTaggedPointerEncoding() != TaggedPointerEncodingKind::Extended)
712+
return false;
713+
714+
return objectAddress & TaggedPointerMask;
715+
}
716+
717+
/// Read the isa pointer of an Object-C tagged pointer value.
718+
Optional<StoredPointer>
719+
readMetadataFromTaggedPointer(StoredPointer objectAddress) {
720+
auto readArrayElement = [&](StoredPointer base, StoredPointer tag)
721+
-> Optional<StoredPointer> {
722+
StoredPointer addr = base + tag * sizeof(StoredPointer);
723+
StoredPointer isa;
724+
if (!Reader->readInteger(RemoteAddress(addr), &isa))
725+
return None;
726+
return isa;
727+
};
728+
729+
// Extended pointers have a tag of 0b111, using 8 additional bits
730+
// to specify the class.
731+
if (TaggedPointerExtendedMask != 0 &&
732+
((objectAddress & TaggedPointerExtendedMask)
733+
== TaggedPointerExtendedMask)) {
734+
auto tag = ((objectAddress >> TaggedPointerExtendedSlotShift) &
735+
TaggedPointerExtendedSlotMask);
736+
return readArrayElement(TaggedPointerExtendedClasses, tag);
737+
}
738+
739+
// Basic tagged pointers use a 3 bit tag to specify the class.
740+
auto tag = ((objectAddress >> TaggedPointerSlotShift) &
741+
TaggedPointerSlotMask);
742+
return readArrayElement(TaggedPointerClasses, tag);
743+
}
744+
660745
/// Read the isa pointer of a class or closure context instance and apply
661746
/// the isa mask.
662747
Optional<StoredPointer>
663748
readMetadataFromInstance(StoredPointer objectAddress) {
749+
if (isTaggedPointer(objectAddress))
750+
return readMetadataFromTaggedPointer(objectAddress);
751+
664752
StoredPointer isa;
665753
if (!Reader->readInteger(RemoteAddress(objectAddress), &isa))
666754
return None;
@@ -2290,9 +2378,71 @@ class MetadataReader {
22902378
}
22912379
}
22922380

2381+
# undef tryFindSymbol
2382+
# undef tryReadSymbol
2383+
# undef tryFindAndReadSymbol
2384+
22932385
return finish(IsaEncodingKind::None);
22942386
}
22952387

2388+
TaggedPointerEncodingKind getTaggedPointerEncoding() {
2389+
if (TaggedPointerEncoding != TaggedPointerEncodingKind::Unknown)
2390+
return TaggedPointerEncoding;
2391+
2392+
auto finish = [&](TaggedPointerEncodingKind result)
2393+
-> TaggedPointerEncodingKind {
2394+
TaggedPointerEncoding = result;
2395+
return result;
2396+
};
2397+
2398+
/// Look up the given global symbol and bind 'varname' to its
2399+
/// address if its exists.
2400+
# define tryFindSymbol(varname, symbolName) \
2401+
auto varname = Reader->getSymbolAddress(symbolName); \
2402+
if (!varname) \
2403+
return finish(TaggedPointerEncodingKind::Error)
2404+
/// Read from the given pointer into 'dest'.
2405+
# define tryReadSymbol(varname, dest) do { \
2406+
if (!Reader->readInteger(varname, &dest)) \
2407+
return finish(TaggedPointerEncodingKind::Error); \
2408+
} while (0)
2409+
/// Read from the given global symbol into 'dest'.
2410+
# define tryFindAndReadSymbol(dest, symbolName) do { \
2411+
tryFindSymbol(_address, symbolName); \
2412+
tryReadSymbol(_address, dest); \
2413+
} while (0)
2414+
2415+
tryFindAndReadSymbol(TaggedPointerMask,
2416+
"objc_debug_taggedpointer_mask");
2417+
tryFindAndReadSymbol(TaggedPointerSlotShift,
2418+
"objc_debug_taggedpointer_slot_shift");
2419+
tryFindAndReadSymbol(TaggedPointerSlotMask,
2420+
"objc_debug_taggedpointer_slot_mask");
2421+
tryFindSymbol(TaggedPointerClassesAddr,
2422+
"objc_debug_taggedpointer_classes");
2423+
if (!TaggedPointerClassesAddr)
2424+
finish(TaggedPointerEncodingKind::Error);
2425+
TaggedPointerClasses = TaggedPointerClassesAddr.getAddressData();
2426+
tryFindAndReadSymbol(TaggedPointerExtendedMask,
2427+
"objc_debug_taggedpointer_ext_mask");
2428+
tryFindAndReadSymbol(TaggedPointerExtendedSlotShift,
2429+
"objc_debug_taggedpointer_ext_slot_shift");
2430+
tryFindAndReadSymbol(TaggedPointerExtendedSlotMask,
2431+
"objc_debug_taggedpointer_ext_slot_mask");
2432+
tryFindSymbol(TaggedPointerExtendedClassesAddr,
2433+
"objc_debug_taggedpointer_ext_classes");
2434+
if (!TaggedPointerExtendedClassesAddr)
2435+
finish(TaggedPointerEncodingKind::Error);
2436+
TaggedPointerExtendedClasses =
2437+
TaggedPointerExtendedClassesAddr.getAddressData();
2438+
2439+
# undef tryFindSymbol
2440+
# undef tryReadSymbol
2441+
# undef tryFindAndReadSymbol
2442+
2443+
return finish(TaggedPointerEncodingKind::Extended);
2444+
}
2445+
22962446
template <class T>
22972447
static constexpr T roundUpToAlignment(T offset, T alignment) {
22982448
return (offset + alignment - 1) & ~(alignment - 1);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-remoteast-test-with-sdk %s | %FileCheck %s
2+
3+
// REQUIRES: swift-remoteast-test
4+
// REQUIRES: objc_interop
5+
6+
import Foundation
7+
8+
@_silgen_name("printDynamicTypeAndAddressForExistential")
9+
func printDynamicTypeAndAddressForExistential<T>(_: T)
10+
11+
// CHECK: NSObject
12+
printDynamicTypeAndAddressForExistential(NSObject() as AnyObject)
13+
14+
// CHECK: NSNumber
15+
printDynamicTypeAndAddressForExistential(NSNumber(123) as AnyObject)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/existentials_objc
3+
// RUN: %target-codesign %t/existentials_objc
4+
// RUN: %target-run %target-swift-reflection-test %t/existentials_objc | %FileCheck %s
5+
6+
// REQUIRES: objc_interop
7+
// REQUIRES: executable_test
8+
9+
import Foundation
10+
11+
/*
12+
This file pokes at the swift_reflection_projectExistential API
13+
of the SwiftRemoteMirror library.
14+
*/
15+
16+
import SwiftReflectionTest
17+
18+
// Imported class wrapped in AnyObject
19+
20+
// CHECK: Type reference:
21+
// CHECK: (objective_c_class name=NSObject)
22+
reflect(object: NSObject())
23+
24+
// Tagged pointer wrapped in AnyObject
25+
// CHECK: Type reference:
26+
// CHECK: (objective_c_class name=__NSCFNumber)
27+
reflect(object: NSNumber(123))
28+
29+
doneReflecting()

0 commit comments

Comments
 (0)