Skip to content

Commit 0e340e3

Browse files
authored
Merge pull request #5831 from slavapestov/fix-reflection-subclassing
Fix reflection subclassing
2 parents 527482c + 1c7a50d commit 0e340e3

File tree

13 files changed

+381
-97
lines changed

13 files changed

+381
-97
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ class ReflectionContext
9292
// Figure out where the stored properties of this class begin
9393
// by looking at the size of the superclass
9494
bool valid;
95-
unsigned size, align;
96-
std::tie(valid, size, align) =
97-
this->readInstanceSizeAndAlignmentFromClassMetadata(MetadataAddress);
95+
unsigned start;
96+
std::tie(valid, start) =
97+
this->readInstanceStartAndAlignmentFromClassMetadata(MetadataAddress);
9898

9999
// Perform layout
100100
if (valid)
101-
TI = TC.getClassInstanceTypeInfo(TR, size, align);
101+
TI = TC.getClassInstanceTypeInfo(TR, start);
102102

103103
break;
104104
}

include/swift/Reflection/TypeLowering.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,7 @@ class TypeConverter {
246246
///
247247
/// Not cached.
248248
const TypeInfo *getClassInstanceTypeInfo(const TypeRef *TR,
249-
unsigned start,
250-
unsigned align);
249+
unsigned start);
251250

252251
private:
253252
friend class swift::reflection::LowerType;

include/swift/Remote/MetadataReader.h

Lines changed: 15 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -561,94 +561,28 @@ class MetadataReader {
561561
}
562562

563563
/// Given a remote pointer to class metadata, attempt to discover its class
564-
/// instance size and alignment.
565-
std::tuple<bool, unsigned, unsigned>
566-
readInstanceSizeAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) {
564+
/// instance size and whether fields should use the resilient layout strategy.
565+
std::pair<bool, unsigned>
566+
readInstanceStartAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) {
567567
auto meta = readMetadata(MetadataAddress);
568568
if (!meta || meta->getKind() != MetadataKind::Class)
569-
return std::make_tuple(false, 0, 0);
570-
571-
auto classMeta = cast<TargetClassMetadata<Runtime>>(meta);
572-
573-
// See swift_initClassMetadata_UniversalStrategy()
574-
uint32_t size, align;
575-
576-
// If this class is defined in Objective-C, return the value of the
577-
// InstanceStart field from the ROData.
578-
if (!classMeta->isTypeMetadata()) {
579-
// The following algorithm only works on the non-fragile Apple runtime.
580-
581-
// Grab the RO-data pointer. This part is not ABI.
582-
StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress);
583-
if (!roDataPtr)
584-
return std::make_tuple(false, 0, 0);
585-
586-
// Get the address of the InstanceStart field.
587-
auto address = roDataPtr + sizeof(uint32_t) * 1;
588-
589-
align = 16;
590-
591-
if (!Reader->readInteger(RemoteAddress(address), &size))
592-
return std::make_tuple(false, 0, 0);
593-
594-
assert((size & (align - 1)) == 0);
595-
return std::make_tuple(true, size, align);
596-
}
597-
598-
// Otherwise, it is a Swift class. Get the superclass.
599-
auto superAddr = readSuperClassFromClassMetadata(MetadataAddress);
600-
if (superAddr) {
601-
auto superMeta = readMetadata(superAddr);
602-
if (!superMeta || superMeta->getKind() != MetadataKind::Class)
603-
return std::make_tuple(false, 0, 0);
604-
605-
auto superclassMeta = cast<TargetClassMetadata<Runtime>>(superMeta);
606-
607-
// If the superclass is an Objective-C class, we start layout
608-
// from the InstanceSize of the superclass, aligned up to
609-
// 16 bytes.
610-
if (superclassMeta->isTypeMetadata()) {
611-
// Superclass is a Swift class. Get the size of an instance,
612-
// and start layout from that.
613-
size = superclassMeta->getInstanceSize();
614-
align = 1;
615-
616-
return std::make_tuple(true, size, align);
617-
}
618-
619-
std::string superName;
620-
if (!readObjCClassName(superAddr, superName))
621-
return std::make_tuple(false, 0, 0);
622-
623-
if (superName != "SwiftObject") {
624-
// Grab the RO-data pointer. This part is not ABI.
625-
StoredPointer roDataPtr = readObjCRODataPtr(superAddr);
626-
if (!roDataPtr)
627-
return std::make_tuple(false, 0, 0);
628-
629-
// Get the address of the InstanceSize field.
630-
auto address = roDataPtr + sizeof(uint32_t) * 2;
631-
632-
// malloc alignment boundary.
633-
align = 16;
634-
635-
if (!Reader->readInteger(RemoteAddress(address), &size))
636-
return std::make_tuple(false, 0, 0);
569+
return std::make_pair(false, 0);
637570

638-
// Round up to the alignment boundary.
639-
size = (size + (align - 1)) & ~(align - 1);
571+
// The following algorithm only works on the non-fragile Apple runtime.
640572

641-
return std::make_tuple(true, size, align);
642-
}
573+
// Grab the RO-data pointer. This part is not ABI.
574+
StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress);
575+
if (!roDataPtr)
576+
return std::make_pair(false, 0);
643577

644-
// Fall through.
645-
}
578+
// Get the address of the InstanceStart field.
579+
auto address = roDataPtr + sizeof(uint32_t) * 1;
646580

647-
// No superclass, just an object header. 12 bytes on 32-bit, 16 on 64-bit
648-
size = Reader->getPointerSize() + sizeof(uint64_t);
649-
align = 1;
581+
unsigned start;
582+
if (!Reader->readInteger(RemoteAddress(address), &start))
583+
return std::make_pair(false, 0);
650584

651-
return std::make_tuple(true, size, align);
585+
return std::make_pair(true, start);
652586
}
653587

654588
/// Given a remote pointer to metadata, attempt to turn it into a type.

lib/IRGen/GenEnum.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5684,6 +5684,12 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
56845684
void IRGenModule::emitEnumDecl(EnumDecl *theEnum) {
56855685
emitEnumMetadata(*this, theEnum);
56865686
emitNestedTypeDecls(theEnum->getMembers());
5687+
5688+
if (shouldEmitOpaqueTypeMetadataRecord(theEnum)) {
5689+
emitOpaqueTypeMetadataRecord(theEnum);
5690+
return;
5691+
}
5692+
56875693
emitFieldMetadataRecord(theEnum);
56885694
}
56895695

lib/IRGen/GenReflection.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,17 @@ void IRGenModule::emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDec
557557
builder.emit();
558558
}
559559

560+
bool IRGenModule::shouldEmitOpaqueTypeMetadataRecord(
561+
const NominalTypeDecl *nominalDecl) {
562+
if (nominalDecl->getAttrs().hasAttribute<AlignmentAttr>()) {
563+
auto &ti = getTypeInfoForUnlowered(nominalDecl->getDeclaredTypeInContext());
564+
if (isa<FixedTypeInfo>(ti))
565+
return true;
566+
}
567+
568+
return false;
569+
}
570+
560571
/// Builds a constant LLVM struct describing the layout of a fixed-size
561572
/// SIL @box. These look like closure contexts, but without any necessary
562573
/// bindings or metadata sources, and only a single captured value.

lib/IRGen/GenStruct.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,12 @@ unsigned irgen::getPhysicalStructFieldIndex(IRGenModule &IGM, SILType baseType,
839839
void IRGenModule::emitStructDecl(StructDecl *st) {
840840
emitStructMetadata(*this, st);
841841
emitNestedTypeDecls(st->getMembers());
842+
843+
if (shouldEmitOpaqueTypeMetadataRecord(st)) {
844+
emitOpaqueTypeMetadataRecord(st);
845+
return;
846+
}
847+
842848
emitFieldMetadataRecord(st);
843849
}
844850

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,10 @@ class IRGenModule {
771771
/// from this module.
772772
void emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl);
773773

774+
/// Some nominal type declarations require us to emit a fixed-size type
775+
/// descriptor, because they have special layout considerations.
776+
bool shouldEmitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl);
777+
774778
/// Emit reflection metadata records for builtin and imported types referenced
775779
/// from this module.
776780
void emitBuiltinReflectionMetadata();

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,8 +1251,7 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) {
12511251
}
12521252

12531253
const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR,
1254-
unsigned start,
1255-
unsigned align) {
1254+
unsigned start) {
12561255
const FieldDescriptor *FD = getBuilder().getFieldTypeInfo(TR);
12571256
if (FD == nullptr) {
12581257
DEBUG(std::cerr << "No field descriptor: "; TR->dump());
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef SWIFT_TEST_OBJC_CLASSES_H
2+
#define SWIFT_TEST_OBJC_CLASSES_H
3+
4+
#import <Foundation/Foundation.h>
5+
6+
@interface FirstClass : NSObject
7+
@property void *x;
8+
@end
9+
10+
@interface SecondClass : NSObject
11+
@property void *x;
12+
@property void *y;
13+
@end
14+
15+
@interface ThirdClass : NSObject
16+
@property void *x;
17+
@property void *y;
18+
@property void *z;
19+
@end
20+
21+
#endif
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#import "ObjCClasses.h"
2+
3+
@implementation FirstClass : NSObject
4+
@synthesize x;
5+
@end
6+
7+
@implementation SecondClass : NSObject
8+
@synthesize x;
9+
@synthesize y;
10+
@end
11+
12+
@implementation ThirdClass : NSObject
13+
@synthesize x;
14+
@synthesize y;
15+
@synthesize z;
16+
@end

0 commit comments

Comments
 (0)