@@ -86,6 +86,26 @@ struct delete_with_free {
86
86
}
87
87
};
88
88
89
+ // / A structure representing an opened existential type.
90
+ struct RemoteExistential {
91
+ // / The payload's concrete type metadata.
92
+ RemoteAddress MetadataAddress;
93
+
94
+ // / The address of the payload value.
95
+ RemoteAddress PayloadAddress;
96
+
97
+ // / True if this is an NSError instance transparently bridged to an Error
98
+ // / existential.
99
+ bool IsBridgedError;
100
+
101
+ RemoteExistential (RemoteAddress MetadataAddress,
102
+ RemoteAddress PayloadAddress,
103
+ bool IsBridgedError=false )
104
+ : MetadataAddress(MetadataAddress),
105
+ PayloadAddress (PayloadAddress),
106
+ IsBridgedError(IsBridgedError) {}
107
+ };
108
+
89
109
// / A generic reader of metadata.
90
110
// /
91
111
// / BuilderType must implement a particular interface which is currently
@@ -171,6 +191,38 @@ class MetadataReader {
171
191
StoredPointer IndexedClassesCountPointer;
172
192
StoredPointer LastIndexedClassesCount = 0 ;
173
193
194
+ enum class TaggedPointerEncodingKind {
195
+ // / We haven't checked yet.
196
+ Unknown,
197
+
198
+ // / There was an error trying to find out the tagged pointer encoding.
199
+ Error,
200
+
201
+ // / The "extended" encoding.
202
+ // /
203
+ // / 1 bit: is-tagged
204
+ // / 3 bits: class index (for objc_debug_taggedpointer_classes[])
205
+ // / 60 bits: payload
206
+ // /
207
+ // / Class index 0b111 represents 256 additional classes:
208
+ // /
209
+ // / 1 bit: is-tagged
210
+ // / 3 bits: 0b111
211
+ // / 8 bits: extended class index (for objc_debug_taggedpointer_ext_classes[])
212
+ // / 54 bits: payload
213
+ Extended
214
+ };
215
+ TaggedPointerEncodingKind TaggedPointerEncoding =
216
+ TaggedPointerEncodingKind::Unknown;
217
+ StoredPointer TaggedPointerMask;
218
+ StoredPointer TaggedPointerSlotShift;
219
+ StoredPointer TaggedPointerSlotMask;
220
+ StoredPointer TaggedPointerClasses;
221
+ StoredPointer TaggedPointerExtendedMask;
222
+ StoredPointer TaggedPointerExtendedSlotShift;
223
+ StoredPointer TaggedPointerExtendedSlotMask;
224
+ StoredPointer TaggedPointerExtendedClasses;
225
+
174
226
Demangle::NodeFactory Factory;
175
227
176
228
Demangle::NodeFactory &getNodeFactory () { return Factory; }
@@ -294,8 +346,10 @@ class MetadataReader {
294
346
}
295
347
296
348
// / Given a pointer to a known-error existential, attempt to discover the
297
- // / pointer to its metadata address and its value address.
298
- Optional<std::pair<RemoteAddress, RemoteAddress>>
349
+ // / pointer to its metadata address, its value address, and whether this
350
+ // / is a toll-free-bridged NSError or an actual Error existential wrapper
351
+ // / around a native Swift value.
352
+ Optional<RemoteExistential>
299
353
readMetadataAndValueErrorExistential (RemoteAddress ExistentialAddress) {
300
354
// An pointer to an error existential is always an heap object.
301
355
auto MetadataAddress =
@@ -304,13 +358,16 @@ class MetadataReader {
304
358
return None;
305
359
306
360
bool isObjC = false ;
361
+ bool isBridged = false ;
307
362
308
363
// If we can determine the Objective-C class name, this is probably an
309
364
// error existential with NSError-compatible layout.
310
365
std::string ObjCClassName;
311
366
if (readObjCClassName (*MetadataAddress, ObjCClassName)) {
312
367
if (ObjCClassName == " __SwiftNativeNSError" )
313
368
isObjC = true ;
369
+ else
370
+ isBridged = true ;
314
371
} else {
315
372
// Otherwise, we can check to see if this is a class metadata with the
316
373
// kind value's least significant bit set, which indicates a pure
@@ -323,6 +380,13 @@ class MetadataReader {
323
380
isObjC = ClassMeta->isPureObjC ();
324
381
}
325
382
383
+ if (isBridged) {
384
+ // NSError instances don't need to be unwrapped.
385
+ return RemoteExistential (RemoteAddress (*MetadataAddress),
386
+ ExistentialAddress,
387
+ isBridged);
388
+ }
389
+
326
390
// In addition to the isa pointer and two 32-bit reference counts, if the
327
391
// error existential is layout-compatible with NSError, we also need to
328
392
// skip over its three word-sized fields: the error code, the domain,
@@ -354,14 +418,15 @@ class MetadataReader {
354
418
auto Offset = (sizeof (HeapObject) + AlignmentMask) & ~AlignmentMask;
355
419
InstanceAddress += Offset;
356
420
357
- return Optional<std::pair<RemoteAddress, RemoteAddress>>(
358
- {RemoteAddress (*InstanceMetadataAddress),
359
- RemoteAddress (InstanceAddress)});
421
+ return RemoteExistential (
422
+ RemoteAddress (*InstanceMetadataAddress),
423
+ RemoteAddress (InstanceAddress),
424
+ isBridged);
360
425
}
361
426
362
427
// / Given a known-opaque existential, attemp to discover the pointer to its
363
428
// / metadata address and its value.
364
- Optional<std::pair<RemoteAddress, RemoteAddress> >
429
+ Optional<RemoteExistential >
365
430
readMetadataAndValueOpaqueExistential (RemoteAddress ExistentialAddress) {
366
431
// OpaqueExistentialContainer is the layout of an opaque existential.
367
432
// `Type` is the pointer to the metadata.
@@ -381,8 +446,8 @@ class MetadataReader {
381
446
// Inline representation (the value fits in the existential container).
382
447
// So, the value starts at the first word of the container.
383
448
if (VWT->isValueInline ())
384
- return Optional<std::pair< RemoteAddress, RemoteAddress>>(
385
- { RemoteAddress (MetadataAddress), ExistentialAddress} );
449
+ return RemoteExistential ( RemoteAddress (MetadataAddress),
450
+ ExistentialAddress);
386
451
387
452
// Non-inline (box'ed) representation.
388
453
// The first word of the container stores the address to the box.
@@ -393,8 +458,8 @@ class MetadataReader {
393
458
auto AlignmentMask = VWT->getAlignmentMask ();
394
459
auto Offset = (sizeof (HeapObject) + AlignmentMask) & ~AlignmentMask;
395
460
auto StartOfValue = BoxAddress + Offset;
396
- return Optional<std::pair< RemoteAddress, RemoteAddress>>(
397
- { RemoteAddress (MetadataAddress), RemoteAddress (StartOfValue)} );
461
+ return RemoteExistential ( RemoteAddress (MetadataAddress),
462
+ RemoteAddress (StartOfValue));
398
463
}
399
464
400
465
// / Read a protocol from a reference to said protocol.
@@ -463,10 +528,28 @@ class MetadataReader {
463
528
if (!Meta) return BuiltType ();
464
529
465
530
switch (Meta->getKind ()) {
466
- case MetadataKind::Class:
467
- if (!cast<TargetClassMetadata<Runtime>>(Meta)->isTypeMetadata ())
468
- return BuiltType ();
531
+ case MetadataKind::Class: {
532
+ auto classMeta = cast<TargetClassMetadata<Runtime>>(Meta);
533
+ if (!classMeta->isTypeMetadata ()) {
534
+ std::string className;
535
+ if (!readObjCClassName (MetadataAddress, className))
536
+ return BuiltType ();
537
+
538
+ BuiltType BuiltObjCClass = Builder.createObjCClassType (std::move (className));
539
+ if (!BuiltObjCClass) {
540
+ // Try the superclass.
541
+ if (!classMeta->Superclass )
542
+ return BuiltType ();
543
+
544
+ BuiltObjCClass = readTypeFromMetadata (classMeta->Superclass ,
545
+ skipArtificialSubclasses);
546
+ }
547
+
548
+ TypeCache[MetadataAddress] = BuiltObjCClass;
549
+ return BuiltObjCClass;
550
+ }
469
551
return readNominalTypeFromMetadata (Meta, skipArtificialSubclasses);
552
+ }
470
553
case MetadataKind::Struct:
471
554
case MetadataKind::Enum:
472
555
case MetadataKind::Optional:
@@ -657,10 +740,48 @@ class MetadataReader {
657
740
return buildContextMangling (context, Dem);
658
741
}
659
742
743
+ bool isTaggedPointer (StoredPointer objectAddress) {
744
+ if (getTaggedPointerEncoding () != TaggedPointerEncodingKind::Extended)
745
+ return false ;
746
+
747
+ return objectAddress & TaggedPointerMask;
748
+ }
749
+
750
+ // / Read the isa pointer of an Object-C tagged pointer value.
751
+ Optional<StoredPointer>
752
+ readMetadataFromTaggedPointer (StoredPointer objectAddress) {
753
+ auto readArrayElement = [&](StoredPointer base, StoredPointer tag)
754
+ -> Optional<StoredPointer> {
755
+ StoredPointer addr = base + tag * sizeof (StoredPointer);
756
+ StoredPointer isa;
757
+ if (!Reader->readInteger (RemoteAddress (addr), &isa))
758
+ return None;
759
+ return isa;
760
+ };
761
+
762
+ // Extended pointers have a tag of 0b111, using 8 additional bits
763
+ // to specify the class.
764
+ if (TaggedPointerExtendedMask != 0 &&
765
+ ((objectAddress & TaggedPointerExtendedMask)
766
+ == TaggedPointerExtendedMask)) {
767
+ auto tag = ((objectAddress >> TaggedPointerExtendedSlotShift) &
768
+ TaggedPointerExtendedSlotMask);
769
+ return readArrayElement (TaggedPointerExtendedClasses, tag);
770
+ }
771
+
772
+ // Basic tagged pointers use a 3 bit tag to specify the class.
773
+ auto tag = ((objectAddress >> TaggedPointerSlotShift) &
774
+ TaggedPointerSlotMask);
775
+ return readArrayElement (TaggedPointerClasses, tag);
776
+ }
777
+
660
778
// / Read the isa pointer of a class or closure context instance and apply
661
779
// / the isa mask.
662
780
Optional<StoredPointer>
663
781
readMetadataFromInstance (StoredPointer objectAddress) {
782
+ if (isTaggedPointer (objectAddress))
783
+ return readMetadataFromTaggedPointer (objectAddress);
784
+
664
785
StoredPointer isa;
665
786
if (!Reader->readInteger (RemoteAddress (objectAddress), &isa))
666
787
return None;
@@ -2290,9 +2411,71 @@ class MetadataReader {
2290
2411
}
2291
2412
}
2292
2413
2414
+ # undef tryFindSymbol
2415
+ # undef tryReadSymbol
2416
+ # undef tryFindAndReadSymbol
2417
+
2293
2418
return finish (IsaEncodingKind::None);
2294
2419
}
2295
2420
2421
+ TaggedPointerEncodingKind getTaggedPointerEncoding () {
2422
+ if (TaggedPointerEncoding != TaggedPointerEncodingKind::Unknown)
2423
+ return TaggedPointerEncoding;
2424
+
2425
+ auto finish = [&](TaggedPointerEncodingKind result)
2426
+ -> TaggedPointerEncodingKind {
2427
+ TaggedPointerEncoding = result;
2428
+ return result;
2429
+ };
2430
+
2431
+ // / Look up the given global symbol and bind 'varname' to its
2432
+ // / address if its exists.
2433
+ # define tryFindSymbol (varname, symbolName ) \
2434
+ auto varname = Reader->getSymbolAddress (symbolName); \
2435
+ if (!varname) \
2436
+ return finish (TaggedPointerEncodingKind::Error)
2437
+ // / Read from the given pointer into 'dest'.
2438
+ # define tryReadSymbol (varname, dest ) do { \
2439
+ if (!Reader->readInteger (varname, &dest)) \
2440
+ return finish (TaggedPointerEncodingKind::Error); \
2441
+ } while (0 )
2442
+ // / Read from the given global symbol into 'dest'.
2443
+ # define tryFindAndReadSymbol (dest, symbolName ) do { \
2444
+ tryFindSymbol (_address, symbolName); \
2445
+ tryReadSymbol (_address, dest); \
2446
+ } while (0 )
2447
+
2448
+ tryFindAndReadSymbol (TaggedPointerMask,
2449
+ " objc_debug_taggedpointer_mask" );
2450
+ tryFindAndReadSymbol (TaggedPointerSlotShift,
2451
+ " objc_debug_taggedpointer_slot_shift" );
2452
+ tryFindAndReadSymbol (TaggedPointerSlotMask,
2453
+ " objc_debug_taggedpointer_slot_mask" );
2454
+ tryFindSymbol (TaggedPointerClassesAddr,
2455
+ " objc_debug_taggedpointer_classes" );
2456
+ if (!TaggedPointerClassesAddr)
2457
+ finish (TaggedPointerEncodingKind::Error);
2458
+ TaggedPointerClasses = TaggedPointerClassesAddr.getAddressData ();
2459
+ tryFindAndReadSymbol (TaggedPointerExtendedMask,
2460
+ " objc_debug_taggedpointer_ext_mask" );
2461
+ tryFindAndReadSymbol (TaggedPointerExtendedSlotShift,
2462
+ " objc_debug_taggedpointer_ext_slot_shift" );
2463
+ tryFindAndReadSymbol (TaggedPointerExtendedSlotMask,
2464
+ " objc_debug_taggedpointer_ext_slot_mask" );
2465
+ tryFindSymbol (TaggedPointerExtendedClassesAddr,
2466
+ " objc_debug_taggedpointer_ext_classes" );
2467
+ if (!TaggedPointerExtendedClassesAddr)
2468
+ finish (TaggedPointerEncodingKind::Error);
2469
+ TaggedPointerExtendedClasses =
2470
+ TaggedPointerExtendedClassesAddr.getAddressData ();
2471
+
2472
+ # undef tryFindSymbol
2473
+ # undef tryReadSymbol
2474
+ # undef tryFindAndReadSymbol
2475
+
2476
+ return finish (TaggedPointerEncodingKind::Extended);
2477
+ }
2478
+
2296
2479
template <class T >
2297
2480
static constexpr T roundUpToAlignment (T offset, T alignment) {
2298
2481
return (offset + alignment - 1 ) & ~(alignment - 1 );
0 commit comments