Skip to content

Commit 31f2c75

Browse files
authored
Merge pull request #18172 from dcci/reflexist
[Reflection] Hoist computation of metadata/value for opaque existential to the reader
2 parents f3a5a9d + 055c789 commit 31f2c75

File tree

2 files changed

+68
-47
lines changed

2 files changed

+68
-47
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class ReflectionContext
8080
using super::readIsaMask;
8181
using super::readTypeFromMetadata;
8282
using super::readGenericArgFromMetadata;
83+
using super::readMetadataAndValueOpaqueExistential;
8384
using super::readMetadataFromInstance;
8485
using typename super::StoredPointer;
8586

@@ -479,59 +480,20 @@ class ReflectionContext
479480
*OutInstanceAddress = ExistentialAddress;
480481
return true;
481482

482-
// Opaque existentials fall under two cases:
483-
// If the value fits in three words, it starts at the beginning of the
484-
// container. If it doesn't, the first word is a pointer to a heap box.
485483
case RecordKind::OpaqueExistential: {
486-
auto Fields = ExistentialRecordTI->getFields();
487-
auto ExistentialMetadataField = std::find_if(Fields.begin(), Fields.end(),
488-
[](const FieldInfo &FI) -> bool {
489-
return FI.Name.compare("metadata") == 0;
490-
});
491-
if (ExistentialMetadataField == Fields.end())
484+
auto OptMetaAndValue =
485+
readMetadataAndValueOpaqueExistential(ExistentialAddress);
486+
if (!OptMetaAndValue)
492487
return false;
488+
RemoteAddress MetadataAddress = OptMetaAndValue->first;
489+
RemoteAddress ValueAddress = OptMetaAndValue->second;
493490

494-
// Get the metadata pointer for the contained instance type.
495-
// This is equivalent to:
496-
// auto PointerArray = reinterpret_cast<uintptr_t*>(ExistentialAddress);
497-
// uintptr_t MetadataAddress = PointerArray[Offset];
498-
auto MetadataAddressAddress
499-
= RemoteAddress(ExistentialAddress.getAddressData() +
500-
ExistentialMetadataField->Offset);
501-
502-
StoredPointer MetadataAddress = 0;
503-
if (!getReader().readInteger(MetadataAddressAddress, &MetadataAddress))
504-
return false;
505-
506-
auto InstanceTR = readTypeFromMetadata(MetadataAddress);
491+
auto InstanceTR = readTypeFromMetadata(MetadataAddress.getAddressData());
507492
if (!InstanceTR)
508493
return false;
509494

510495
*OutInstanceTR = InstanceTR;
511-
512-
auto InstanceTI = getTypeInfo(InstanceTR);
513-
if (!InstanceTI)
514-
return false;
515-
516-
if (InstanceTI->getSize() <= ExistentialMetadataField->Offset) {
517-
// The value fits in the existential container, so it starts at the
518-
// start of the container.
519-
*OutInstanceAddress = ExistentialAddress;
520-
} else {
521-
// Otherwise it's in a box somewhere off in the heap. The first word
522-
// of the container has the address to that box.
523-
StoredPointer BoxAddress = 0;
524-
525-
if (!getReader().readInteger(ExistentialAddress, &BoxAddress))
526-
return false;
527-
528-
// Address = BoxAddress + (sizeof(HeapObject) + alignMask) & ~alignMask)
529-
auto Alignment = InstanceTI->getAlignment();
530-
auto StartOfValue = BoxAddress + getSizeOfHeapObject();
531-
// Align.
532-
StartOfValue += Alignment - StartOfValue % Alignment;
533-
*OutInstanceAddress = RemoteAddress(StartOfValue);
534-
}
496+
*OutInstanceAddress = ValueAddress;
535497
return true;
536498
}
537499
case RecordKind::ErrorExistential: {

include/swift/Remote/MetadataReader.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include "swift/Basic/Defer.h"
2525
#include "swift/Basic/Range.h"
2626
#include "swift/Basic/LLVM.h"
27+
#include "swift/Runtime/ExistentialContainer.h"
28+
#include "swift/Runtime/HeapObject.h"
2729
#include "swift/Runtime/Unreachable.h"
2830

2931
#include <vector>
@@ -261,7 +263,64 @@ class MetadataReader {
261263

262264
return start;
263265
}
264-
266+
267+
/// Given a pointer to the metadata, attempt to read the value
268+
/// witness table.
269+
llvm::Optional<TargetValueWitnessTable<Runtime>>
270+
readValueWitnessTable(StoredPointer MetadataAddress) {
271+
// The value witness table pointer is at offset -1 from the metadata
272+
// pointer, that is, the pointer-sized word immediately before the
273+
// pointer's referenced address.
274+
TargetValueWitnessTable<Runtime> VWT;
275+
auto ValueWitnessTableAddrAddr = MetadataAddress - sizeof(StoredPointer);
276+
StoredPointer ValueWitnessTableAddr;
277+
if (!Reader->readInteger(RemoteAddress(ValueWitnessTableAddrAddr),
278+
&ValueWitnessTableAddr))
279+
return llvm::None;
280+
if (!Reader->readBytes(RemoteAddress(ValueWitnessTableAddr),
281+
(uint8_t *)&VWT, sizeof(VWT)))
282+
return llvm::None;
283+
return VWT;
284+
}
285+
286+
/// Given a known-opaque existential, attemp to discover the pointer to its
287+
/// metadata address and its value.
288+
llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>
289+
readMetadataAndValueOpaqueExistential(RemoteAddress ExistentialAddress) {
290+
// OpaqueExistentialContainer is the layout of an opaque existential.
291+
// `Type` is the pointer to the metadata.
292+
TargetOpaqueExistentialContainer<Runtime> Container;
293+
if (!Reader->readBytes(RemoteAddress(ExistentialAddress),
294+
(uint8_t *)&Container, sizeof(Container)))
295+
return llvm::None;
296+
auto MetadataAddress = reinterpret_cast<StoredPointer>(Container.Type);
297+
auto Metadata = readMetadata(MetadataAddress);
298+
if (!Metadata)
299+
return llvm::None;
300+
301+
auto VWT = readValueWitnessTable(MetadataAddress);
302+
if (!VWT)
303+
return llvm::None;
304+
305+
// Inline representation (the value fits in the existential container).
306+
// So, the value starts at the first word of the container.
307+
if (VWT->isValueInline())
308+
return llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>(
309+
{RemoteAddress(MetadataAddress), ExistentialAddress});
310+
311+
// Non-inline (box'ed) representation.
312+
// The first word of the container stores the address to the box.
313+
StoredPointer BoxAddress;
314+
if (!Reader->readInteger(ExistentialAddress, &BoxAddress))
315+
return llvm::None;
316+
317+
auto AlignmentMask = VWT->getAlignmentMask();
318+
auto Offset = (sizeof(HeapObject) + AlignmentMask) & ~AlignmentMask;
319+
auto StartOfValue = BoxAddress + Offset;
320+
return llvm::Optional<std::pair<RemoteAddress, RemoteAddress>>(
321+
{RemoteAddress(MetadataAddress), RemoteAddress(StartOfValue)});
322+
}
323+
265324
/// Given a remote pointer to metadata, attempt to turn it into a type.
266325
BuiltType readTypeFromMetadata(StoredPointer MetadataAddress,
267326
bool skipArtificialSubclasses = false) {

0 commit comments

Comments
 (0)