Skip to content

Commit 5dc4156

Browse files
author
Davide Italiano
committed
[Reflection] Hoist computation of error existentials to the reader.
<rdar://problem/41546568>
1 parent 31f2c75 commit 5dc4156

File tree

2 files changed

+78
-59
lines changed

2 files changed

+78
-59
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 10 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,12 @@ class ReflectionContext
7777
public:
7878
using super::getBuilder;
7979
using super::readDemanglingForContextDescriptor;
80-
using super::readIsaMask;
81-
using super::readTypeFromMetadata;
8280
using super::readGenericArgFromMetadata;
81+
using super::readIsaMask;
82+
using super::readMetadataAndValueErrorExistential;
8383
using super::readMetadataAndValueOpaqueExistential;
8484
using super::readMetadataFromInstance;
85+
using super::readTypeFromMetadata;
8586
using typename super::StoredPointer;
8687

8788
explicit ReflectionContext(std::shared_ptr<MemoryReader> reader)
@@ -497,70 +498,21 @@ class ReflectionContext
497498
return true;
498499
}
499500
case RecordKind::ErrorExistential: {
500-
// We have a pointer to an error existential, which is always heap object.
501-
502-
auto MetadataAddress
503-
= readMetadataFromInstance(ExistentialAddress.getAddressData());
504-
505-
if (!MetadataAddress)
501+
auto OptMetaAndValue =
502+
readMetadataAndValueErrorExistential(ExistentialAddress);
503+
if (!OptMetaAndValue)
506504
return false;
507505

508-
bool isObjC = false;
509-
510-
// If we can determine the Objective-C class name, this is probably an
511-
// error existential with NSError-compatible layout.
512-
std::string ObjCClassName;
513-
if (readObjCClassName(*MetadataAddress, ObjCClassName)) {
514-
if (ObjCClassName == "_SwiftNativeNSError")
515-
isObjC = true;
516-
} else {
517-
// Otherwise, we can check to see if this is a class metadata with the
518-
// kind value's least significant bit set, which indicates a pure
519-
// Swift class.
520-
auto Meta = readMetadata(*MetadataAddress);
521-
auto ClassMeta = dyn_cast<TargetClassMetadata<Runtime>>(Meta);
522-
if (!ClassMeta)
523-
return false;
524-
525-
isObjC = ClassMeta->isPureObjC();
526-
}
527-
528-
// In addition to the isa pointer and two 32-bit reference counts, if the
529-
// error existential is layout-compatible with NSError, we also need to
530-
// skip over its three word-sized fields: the error code, the domain,
531-
// and userInfo.
532-
StoredPointer InstanceMetadataAddressAddress
533-
= ExistentialAddress.getAddressData() +
534-
(isObjC ? 5 : 2) * sizeof(StoredPointer);
535-
536-
// We need to get the instance's alignment info so we can get the exact
537-
// offset of the start of its data in the class.
538-
auto InstanceMetadataAddress =
539-
readMetadataFromInstance(InstanceMetadataAddressAddress);
540-
if (!InstanceMetadataAddress)
541-
return false;
506+
RemoteAddress InstanceMetadataAddress = OptMetaAndValue->first;
507+
RemoteAddress InstanceAddress = OptMetaAndValue->second;
542508

543-
auto InstanceTR = readTypeFromMetadata(*InstanceMetadataAddress);
509+
auto InstanceTR =
510+
readTypeFromMetadata(InstanceMetadataAddress.getAddressData());
544511
if (!InstanceTR)
545512
return false;
546513

547-
auto InstanceTI = getTypeInfo(InstanceTR);
548-
if (!InstanceTI)
549-
return false;
550-
551-
// Now we need to skip over the instance metadata pointer and instance's
552-
// conformance pointer for Swift.Error.
553-
StoredPointer InstanceAddress = InstanceMetadataAddressAddress +
554-
2 * sizeof(StoredPointer);
555-
556-
// Round up to alignment, and we have the start address of the
557-
// instance payload.
558-
auto Alignment = InstanceTI->getAlignment();
559-
InstanceAddress += Alignment - InstanceAddress % Alignment;
560-
561514
*OutInstanceTR = InstanceTR;
562515
*OutInstanceAddress = RemoteAddress(InstanceAddress);
563-
564516
return true;
565517
}
566518
default:

include/swift/Remote/MetadataReader.h

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ class MetadataReader {
265265
}
266266

267267
/// 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.
269270
llvm::Optional<TargetValueWitnessTable<Runtime>>
270271
readValueWitnessTable(StoredPointer MetadataAddress) {
271272
// The value witness table pointer is at offset -1 from the metadata
@@ -283,6 +284,72 @@ class MetadataReader {
283284
return VWT;
284285
}
285286

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+
286353
/// Given a known-opaque existential, attemp to discover the pointer to its
287354
/// metadata address and its value.
288355
llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>

0 commit comments

Comments
 (0)