@@ -265,7 +265,8 @@ class MetadataReader {
265
265
}
266
266
267
267
// / Given a pointer to the metadata, attempt to read the value
268
- // / witness table.
268
+ // / witness table. Note that it's not safe to access any non-mandatory
269
+ // / members of the value witness table, like extra inhabitants or enum members.
269
270
llvm::Optional<TargetValueWitnessTable<Runtime>>
270
271
readValueWitnessTable (StoredPointer MetadataAddress) {
271
272
// The value witness table pointer is at offset -1 from the metadata
@@ -283,6 +284,72 @@ class MetadataReader {
283
284
return VWT;
284
285
}
285
286
287
+ // / Given a pointer to a known-error existential, attempt to discover the
288
+ // / pointer to its metadata address and its value address.
289
+ llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>
290
+ readMetadataAndValueErrorExistential (RemoteAddress ExistentialAddress) {
291
+ // An pointer to an error existential is always an heap object.
292
+ auto MetadataAddress =
293
+ readMetadataFromInstance (ExistentialAddress.getAddressData ());
294
+ if (!MetadataAddress)
295
+ return llvm::None;
296
+
297
+ bool isObjC = false ;
298
+
299
+ // If we can determine the Objective-C class name, this is probably an
300
+ // error existential with NSError-compatible layout.
301
+ std::string ObjCClassName;
302
+ if (readObjCClassName (*MetadataAddress, ObjCClassName)) {
303
+ if (ObjCClassName == " _SwiftNativeNSError" )
304
+ isObjC = true ;
305
+ } else {
306
+ // Otherwise, we can check to see if this is a class metadata with the
307
+ // kind value's least significant bit set, which indicates a pure
308
+ // Swift class.
309
+ auto Meta = readMetadata (*MetadataAddress);
310
+ auto ClassMeta = dyn_cast<TargetClassMetadata<Runtime>>(Meta);
311
+ if (!ClassMeta)
312
+ return llvm::None;
313
+
314
+ isObjC = ClassMeta->isPureObjC ();
315
+ }
316
+
317
+ // In addition to the isa pointer and two 32-bit reference counts, if the
318
+ // error existential is layout-compatible with NSError, we also need to
319
+ // skip over its three word-sized fields: the error code, the domain,
320
+ // and userInfo.
321
+ StoredPointer InstanceMetadataAddressAddress =
322
+ ExistentialAddress.getAddressData () +
323
+ (isObjC ? 5 : 2 ) * sizeof (StoredPointer);
324
+
325
+ // We need to get the instance's alignment info so we can get the exact
326
+ // offset of the start of its data in the class.
327
+ auto InstanceMetadataAddress =
328
+ readMetadataFromInstance (InstanceMetadataAddressAddress);
329
+ if (!InstanceMetadataAddress)
330
+ return llvm::None;
331
+
332
+ // Read the value witness table.
333
+ auto VWT = readValueWitnessTable (*InstanceMetadataAddress);
334
+ if (!VWT)
335
+ return llvm::None;
336
+
337
+ // Now we need to skip over the instance metadata pointer and instance's
338
+ // conformance pointer for Swift.Error.
339
+ StoredPointer InstanceAddress =
340
+ InstanceMetadataAddressAddress + 2 * sizeof (StoredPointer);
341
+
342
+ // Round up to alignment, and we have the start address of the
343
+ // instance payload.
344
+ auto AlignmentMask = VWT->getAlignmentMask ();
345
+ auto Offset = (sizeof (HeapObject) + AlignmentMask) & ~AlignmentMask;
346
+ InstanceAddress += Offset;
347
+
348
+ return llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>(
349
+ {RemoteAddress (*InstanceMetadataAddress),
350
+ RemoteAddress (InstanceAddress)});
351
+ }
352
+
286
353
// / Given a known-opaque existential, attemp to discover the pointer to its
287
354
// / metadata address and its value.
288
355
llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>
0 commit comments