From 78d11de3962354f697375d0de667e9134b4cffa8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 15 Nov 2016 18:51:47 -0800 Subject: [PATCH 1/2] IRGen: Emit fixed type descriptors for structs and enums with @_alignment attributes This attribute is used in the simd overlay. To ensure we can layout SIMD types correctly, emit a fixed type descriptor instead of a field type descriptor for these types. --- lib/IRGen/GenEnum.cpp | 6 ++++++ lib/IRGen/GenReflection.cpp | 11 +++++++++++ lib/IRGen/GenStruct.cpp | 6 ++++++ lib/IRGen/IRGenModule.h | 4 ++++ 4 files changed, 27 insertions(+) diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index 6c02246b924d3..865cec2cbf6ea 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -5684,6 +5684,12 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type, void IRGenModule::emitEnumDecl(EnumDecl *theEnum) { emitEnumMetadata(*this, theEnum); emitNestedTypeDecls(theEnum->getMembers()); + + if (shouldEmitOpaqueTypeMetadataRecord(theEnum)) { + emitOpaqueTypeMetadataRecord(theEnum); + return; + } + emitFieldMetadataRecord(theEnum); } diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 812a4ebeae097..b85d0f9285bc9 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -557,6 +557,17 @@ void IRGenModule::emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDec builder.emit(); } +bool IRGenModule::shouldEmitOpaqueTypeMetadataRecord( + const NominalTypeDecl *nominalDecl) { + if (nominalDecl->getAttrs().hasAttribute()) { + auto &ti = getTypeInfoForUnlowered(nominalDecl->getDeclaredTypeInContext()); + if (isa(ti)) + return true; + } + + return false; +} + /// Builds a constant LLVM struct describing the layout of a fixed-size /// SIL @box. These look like closure contexts, but without any necessary /// bindings or metadata sources, and only a single captured value. diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index f06fbac8c4bf8..7b033b16930ce 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -839,6 +839,12 @@ unsigned irgen::getPhysicalStructFieldIndex(IRGenModule &IGM, SILType baseType, void IRGenModule::emitStructDecl(StructDecl *st) { emitStructMetadata(*this, st); emitNestedTypeDecls(st->getMembers()); + + if (shouldEmitOpaqueTypeMetadataRecord(st)) { + emitOpaqueTypeMetadataRecord(st); + return; + } + emitFieldMetadataRecord(st); } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 057b079985347..4d9151025f930 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -771,6 +771,10 @@ class IRGenModule { /// from this module. void emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl); + /// Some nominal type declarations require us to emit a fixed-size type + /// descriptor, because they have special layout considerations. + bool shouldEmitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl); + /// Emit reflection metadata records for builtin and imported types referenced /// from this module. void emitBuiltinReflectionMetadata(); From 1c7a50dcc52aeea132e6289ddfd905ff9dac2e5c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 15 Nov 2016 15:19:26 -0800 Subject: [PATCH 2/2] Reflection: Fix class layout, again There were a few problems here with subclasses of Objective-C classes. Use the InstanceStart field from rodata to correctly lay out instance variables, and verify the results match with dynamic and static layout. Better fix for . --- include/swift/Reflection/ReflectionContext.h | 8 +- include/swift/Reflection/TypeLowering.h | 3 +- include/swift/Remote/MetadataReader.h | 96 ++------- stdlib/public/Reflection/TypeLowering.cpp | 3 +- .../Inputs/ObjCClasses/ObjCClasses.h | 21 ++ .../Inputs/ObjCClasses/ObjCClasses.m | 16 ++ .../Reflection/Inputs/ObjCClasses/module.map | 3 + .../Reflection/inherits_NSObject.swift | 119 +++++++++++- .../Reflection/inherits_ObjCClasses.swift | 182 ++++++++++++++++++ 9 files changed, 354 insertions(+), 97 deletions(-) create mode 100644 validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.h create mode 100644 validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.m create mode 100644 validation-test/Reflection/Inputs/ObjCClasses/module.map create mode 100644 validation-test/Reflection/inherits_ObjCClasses.swift diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 0025bc01457b9..4472d97daf52a 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -92,13 +92,13 @@ class ReflectionContext // Figure out where the stored properties of this class begin // by looking at the size of the superclass bool valid; - unsigned size, align; - std::tie(valid, size, align) = - this->readInstanceSizeAndAlignmentFromClassMetadata(MetadataAddress); + unsigned start; + std::tie(valid, start) = + this->readInstanceStartAndAlignmentFromClassMetadata(MetadataAddress); // Perform layout if (valid) - TI = TC.getClassInstanceTypeInfo(TR, size, align); + TI = TC.getClassInstanceTypeInfo(TR, start); break; } diff --git a/include/swift/Reflection/TypeLowering.h b/include/swift/Reflection/TypeLowering.h index 913621bfc476a..7eaa4e4f8ee6c 100644 --- a/include/swift/Reflection/TypeLowering.h +++ b/include/swift/Reflection/TypeLowering.h @@ -246,8 +246,7 @@ class TypeConverter { /// /// Not cached. const TypeInfo *getClassInstanceTypeInfo(const TypeRef *TR, - unsigned start, - unsigned align); + unsigned start); private: friend class swift::reflection::LowerType; diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index d379ac6f3f770..6a3d6f8bd54b8 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -561,94 +561,28 @@ class MetadataReader { } /// Given a remote pointer to class metadata, attempt to discover its class - /// instance size and alignment. - std::tuple - readInstanceSizeAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) { + /// instance size and whether fields should use the resilient layout strategy. + std::pair + readInstanceStartAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::Class) - return std::make_tuple(false, 0, 0); - - auto classMeta = cast>(meta); - - // See swift_initClassMetadata_UniversalStrategy() - uint32_t size, align; - - // If this class is defined in Objective-C, return the value of the - // InstanceStart field from the ROData. - if (!classMeta->isTypeMetadata()) { - // The following algorithm only works on the non-fragile Apple runtime. - - // Grab the RO-data pointer. This part is not ABI. - StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress); - if (!roDataPtr) - return std::make_tuple(false, 0, 0); - - // Get the address of the InstanceStart field. - auto address = roDataPtr + sizeof(uint32_t) * 1; - - align = 16; - - if (!Reader->readInteger(RemoteAddress(address), &size)) - return std::make_tuple(false, 0, 0); - - assert((size & (align - 1)) == 0); - return std::make_tuple(true, size, align); - } - - // Otherwise, it is a Swift class. Get the superclass. - auto superAddr = readSuperClassFromClassMetadata(MetadataAddress); - if (superAddr) { - auto superMeta = readMetadata(superAddr); - if (!superMeta || superMeta->getKind() != MetadataKind::Class) - return std::make_tuple(false, 0, 0); - - auto superclassMeta = cast>(superMeta); - - // If the superclass is an Objective-C class, we start layout - // from the InstanceSize of the superclass, aligned up to - // 16 bytes. - if (superclassMeta->isTypeMetadata()) { - // Superclass is a Swift class. Get the size of an instance, - // and start layout from that. - size = superclassMeta->getInstanceSize(); - align = 1; - - return std::make_tuple(true, size, align); - } - - std::string superName; - if (!readObjCClassName(superAddr, superName)) - return std::make_tuple(false, 0, 0); - - if (superName != "SwiftObject") { - // Grab the RO-data pointer. This part is not ABI. - StoredPointer roDataPtr = readObjCRODataPtr(superAddr); - if (!roDataPtr) - return std::make_tuple(false, 0, 0); - - // Get the address of the InstanceSize field. - auto address = roDataPtr + sizeof(uint32_t) * 2; - - // malloc alignment boundary. - align = 16; - - if (!Reader->readInteger(RemoteAddress(address), &size)) - return std::make_tuple(false, 0, 0); + return std::make_pair(false, 0); - // Round up to the alignment boundary. - size = (size + (align - 1)) & ~(align - 1); + // The following algorithm only works on the non-fragile Apple runtime. - return std::make_tuple(true, size, align); - } + // Grab the RO-data pointer. This part is not ABI. + StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress); + if (!roDataPtr) + return std::make_pair(false, 0); - // Fall through. - } + // Get the address of the InstanceStart field. + auto address = roDataPtr + sizeof(uint32_t) * 1; - // No superclass, just an object header. 12 bytes on 32-bit, 16 on 64-bit - size = Reader->getPointerSize() + sizeof(uint64_t); - align = 1; + unsigned start; + if (!Reader->readInteger(RemoteAddress(address), &start)) + return std::make_pair(false, 0); - return std::make_tuple(true, size, align); + return std::make_pair(true, start); } /// Given a remote pointer to metadata, attempt to turn it into a type. diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index 84175a9990693..268720d94f310 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -1251,8 +1251,7 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) { } const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, - unsigned start, - unsigned align) { + unsigned start) { const FieldDescriptor *FD = getBuilder().getFieldTypeInfo(TR); if (FD == nullptr) { DEBUG(std::cerr << "No field descriptor: "; TR->dump()); diff --git a/validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.h b/validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.h new file mode 100644 index 0000000000000..3545b32ef5a4c --- /dev/null +++ b/validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.h @@ -0,0 +1,21 @@ +#ifndef SWIFT_TEST_OBJC_CLASSES_H +#define SWIFT_TEST_OBJC_CLASSES_H + +#import + +@interface FirstClass : NSObject +@property void *x; +@end + +@interface SecondClass : NSObject +@property void *x; +@property void *y; +@end + +@interface ThirdClass : NSObject +@property void *x; +@property void *y; +@property void *z; +@end + +#endif diff --git a/validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.m b/validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.m new file mode 100644 index 0000000000000..078b5e981fe94 --- /dev/null +++ b/validation-test/Reflection/Inputs/ObjCClasses/ObjCClasses.m @@ -0,0 +1,16 @@ +#import "ObjCClasses.h" + +@implementation FirstClass : NSObject +@synthesize x; +@end + +@implementation SecondClass : NSObject +@synthesize x; +@synthesize y; +@end + +@implementation ThirdClass : NSObject +@synthesize x; +@synthesize y; +@synthesize z; +@end diff --git a/validation-test/Reflection/Inputs/ObjCClasses/module.map b/validation-test/Reflection/Inputs/ObjCClasses/module.map new file mode 100644 index 0000000000000..6a802414978cf --- /dev/null +++ b/validation-test/Reflection/Inputs/ObjCClasses/module.map @@ -0,0 +1,3 @@ +module ObjCClasses { + header "ObjCClasses.h" +} diff --git a/validation-test/Reflection/inherits_NSObject.swift b/validation-test/Reflection/inherits_NSObject.swift index df58df469335e..2582e26a7d2ae 100644 --- a/validation-test/Reflection/inherits_NSObject.swift +++ b/validation-test/Reflection/inherits_NSObject.swift @@ -6,6 +6,7 @@ // REQUIRES: executable_test import Foundation +import simd import SwiftReflectionTest @@ -14,11 +15,6 @@ class BaseNSClass : NSObject { var x: Bool = false } -class DerivedNSClass : BaseNSClass { - var y: Bool = false - var z: Int = 0 -} - let baseClass = BaseNSClass() reflect(object: baseClass) @@ -42,16 +38,21 @@ reflect(object: baseClass) // CHECK-32: (class inherits_NSObject.BaseNSClass) // CHECK-32: Type info: -// CHECK-32-NEXT: (class_instance size=21 alignment=4 stride=24 num_extra_inhabitants=0 -// CHECK-32-NEXT: (field name=w offset=16 +// CHECK-32-NEXT: (class_instance size=17 alignment=4 stride=20 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=w offset=12 // CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32-NEXT: (field name=x offset=20 +// CHECK-32-NEXT: (field name=x offset=16 // CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))) +class DerivedNSClass : BaseNSClass { + var y: Bool = false + var z: Int = 0 +} + let derivedClass = DerivedNSClass() reflect(object: derivedClass) @@ -85,4 +86,106 @@ reflect(object: derivedClass) // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) +// Note: dynamic layout starts at offset 8, not 16 +class GenericBaseNSClass : NSObject { + var w: T = 0 as! T +} + +let genericBaseClass = GenericBaseNSClass() +reflect(object: genericBaseClass) + +// CHECK-64: Reflecting an object. +// CHECK-64: Type reference: +// CHECK-64: (bound_generic_class inherits_NSObject.GenericBaseNSClass +// CHECK-64: (struct Swift.Int)) + +// CHECK-64: Type info: +// CHECK-64-NEXT: (class_instance size=16 alignment=8 stride=16 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=w offset=8 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (bound_generic_class inherits_NSObject.GenericBaseNSClass +// CHECK-32: (struct Swift.Int)) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=8 alignment=4 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=w offset=4 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) + +class AlignedNSClass : NSObject { + var w: Int = 0 + var x: int4 = [1,2,3,4] +} + +let alignedClass = AlignedNSClass() +reflect(object: alignedClass) + +// CHECK-64: Reflecting an object. +// CHECK-64: Type reference: +// CHECK-64: (class inherits_NSObject.AlignedNSClass) + +// CHECK-64: Type info: +// CHECK-64-NEXT: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=w offset=16 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=x offset=32 +// CHECK-64-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_NSObject.AlignedNSClass) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=w offset=12 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=x offset=16 +// CHECK-32-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +class GenericAlignedNSClass : NSObject { + var w: T = 0 as! T + var x: int4 = [1,2,3,4] +} + +let genericAlignedClass = GenericAlignedNSClass() +reflect(object: genericAlignedClass) + +// CHECK-64: Reflecting an object. +// CHECK-64: Type reference: +// CHECK-64: (bound_generic_class inherits_NSObject.GenericAlignedNSClass +// CHECK-64: (struct Swift.Int)) + +// CHECK-64: Type info: +// CHECK-64-NEXT: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=w offset=16 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=x offset=32 +// CHECK-64-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (bound_generic_class inherits_NSObject.GenericAlignedNSClass +// CHECK-32: (struct Swift.Int)) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=w offset=16 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=x offset=32 +// CHECK-32-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + doneReflecting() diff --git a/validation-test/Reflection/inherits_ObjCClasses.swift b/validation-test/Reflection/inherits_ObjCClasses.swift new file mode 100644 index 0000000000000..40d76f7ae2c40 --- /dev/null +++ b/validation-test/Reflection/inherits_ObjCClasses.swift @@ -0,0 +1,182 @@ +// RUN: rm -rf %t && mkdir -p %t + +// RUN: %clang %target-cc-options -isysroot %sdk -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o +// RUN: %target-build-swift -I %S/Inputs/ObjCClasses/ -lswiftSwiftReflectionTest %t/ObjCClasses.o %s -o %t/inherits_ObjCClasses +// RUN: %target-run %target-swift-reflection-test %t/inherits_ObjCClasses | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +import simd +import ObjCClasses +import SwiftReflectionTest + +//// FirstClass -- base class, has one word-sized ivar + +// Variant A: 16 byte alignment +class FirstClassA : FirstClass { + var xx: int4 = [1,2,3,4] +} + +let firstClassA = FirstClassA() +reflect(object: firstClassA) + +// CHECK-64: Type reference: +// CHECK-64: (class inherits_ObjCClasses.FirstClassA) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 +// CHECK-64: (field name=xx offset=16 +// CHECK-64: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_ObjCClasses.FirstClassA) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=xx offset=16 +// CHECK-32-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// Variant B: word size alignment +class FirstClassB : FirstClass { + var zz: Int = 0 +} + +let firstClassB = FirstClassB() +reflect(object: firstClassB) + +// CHECK-64: Type reference: +// CHECK-64: (class inherits_ObjCClasses.FirstClassB) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=24 alignment=8 stride=24 num_extra_inhabitants=0 +// CHECK-64: (field name=zz offset=16 +// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64: (field name=_value offset=0 +// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_ObjCClasses.FirstClassB) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=16 alignment=4 stride=16 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=zz offset=12 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) + +//// SecondClass -- base class, has two word-sized ivars + +// Variant A: 16 byte alignment +class SecondClassA : SecondClass { + var xx: int4 = [1,2,3,4] +} + +let secondClassA = SecondClassA() +reflect(object: secondClassA) + +// CHECK-64: Type reference: +// CHECK-64: (class inherits_ObjCClasses.SecondClassA) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0 +// CHECK-64: (field name=xx offset=32 +// CHECK-64: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_ObjCClasses.SecondClassA) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=xx offset=16 +// CHECK-32-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// Variant B: word size alignment +class SecondClassB : SecondClass { + var zz: Int = 0 +} + +let secondClassB = SecondClassB() +reflect(object: secondClassB) + +// CHECK-64: Type reference: +// CHECK-64: (class inherits_ObjCClasses.SecondClassB) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=32 alignment=8 stride=32 num_extra_inhabitants=0 +// CHECK-64: (field name=zz offset=24 +// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64: (field name=_value offset=0 +// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_ObjCClasses.SecondClassB) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=16 alignment=4 stride=16 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=zz offset=12 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) + +//// ThirdClass -- base class, has three word-sized ivars + +// Variant A: 16 byte alignment +class ThirdClassA : ThirdClass { + var xx: int4 = [1,2,3,4] +} + +let thirdClassA = ThirdClassA() +reflect(object: thirdClassA) + +// CHECK-64: Type reference: +// CHECK-64: (class inherits_ObjCClasses.ThirdClassA) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0 +// CHECK-64: (field name=xx offset=32 +// CHECK-64: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_ObjCClasses.ThirdClassA) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=xx offset=16 +// CHECK-32-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) + +// Variant B: word size alignment +class ThirdClassB : ThirdClass { + var zz: Int = 0 +} + +let thirdClassB = ThirdClassB() +reflect(object: thirdClassB) + +// CHECK-64: Type reference: +// CHECK-64: (class inherits_ObjCClasses.ThirdClassB) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=40 alignment=8 stride=40 num_extra_inhabitants=0 +// CHECK-64: (field name=zz offset=32 +// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64: (field name=_value offset=0 +// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Type reference: +// CHECK-32: (class inherits_ObjCClasses.ThirdClassB) + +// CHECK-32: Type info: +// CHECK-32-NEXT: (class_instance size=20 alignment=4 stride=20 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=zz offset=16 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) + +doneReflecting()