From 4a23d3cc6c1f6dec4859ea921a6cfc72dfa0f15c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 22 Aug 2018 11:16:24 -0700 Subject: [PATCH 1/4] IRGen: Rename emitInitializeMetadata() to emitInitializeValueMetadata() Small cleanup suggested by John in review. --- lib/IRGen/GenMeta.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index c290299a1cd8a..4d055a5551170 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1617,11 +1617,11 @@ static void emitInitializeFieldOffsetVector(IRGenFunction &IGF, IGF.IGM.getPointerSize() * storedProperties.size()); } -static void emitInitializeMetadata(IRGenFunction &IGF, - NominalTypeDecl *nominalDecl, - llvm::Value *metadata, - bool isVWTMutable, - MetadataDependencyCollector *collector) { +static void emitInitializeValueMetadata(IRGenFunction &IGF, + NominalTypeDecl *nominalDecl, + llvm::Value *metadata, + bool isVWTMutable, + MetadataDependencyCollector *collector) { auto loweredTy = IGF.IGM.getLoweredType(nominalDecl->getDeclaredTypeInContext()); @@ -1992,7 +1992,8 @@ template llvm::Value *metadata, bool isVWTMutable, MetadataDependencyCollector *collector) { - ::emitInitializeMetadata(IGF, Target, metadata, isVWTMutable, collector); + emitInitializeValueMetadata(IGF, Target, metadata, + isVWTMutable, collector); } }; } // end anonymous namespace @@ -2803,7 +2804,8 @@ namespace { bool isVWTMutable, MetadataDependencyCollector *collector) { assert(!HasDependentVWT && "class should never have dependent VWT"); - emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata, collector); + emitInitializeClassMetadata(IGF, Target, FieldLayout, + metadata, collector); } }; } // end anonymous namespace @@ -3021,8 +3023,8 @@ namespace { emitMetadataCompletionFunction(IGM, Target, [&](IRGenFunction &IGF, llvm::Value *metadata, MetadataDependencyCollector *collector) { - emitInitializeMetadata(IGF, Target, metadata, /*vwt mutable*/true, - collector); + emitInitializeValueMetadata(IGF, Target, metadata, + /*vwt mutable*/true, collector); }); } }; From d56234416dfffe32b77e2015588c00b03ea5ba3b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Aug 2018 23:12:29 -0700 Subject: [PATCH 2/4] IRGen: Another small cleanup for class metadata emission --- lib/IRGen/GenMeta.cpp | 75 +++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 4d055a5551170..6c51f0e1cb4b3 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2020,6 +2020,23 @@ createInPlaceInitializationMetadataAccessFunction(IRGenModule &IGM, }); } +/// Create an access function for the given non-generic type. +static void createNonGenericMetadataAccessFunction(IRGenModule &IGM, + NominalTypeDecl *typeDecl) { + assert(!typeDecl->isGenericContext()); + auto type = typeDecl->getDeclaredType()->getCanonicalType(); + + // If the type requires the in-place initialization pattern, use it. + if (needsInPlaceMetadataInitialization(IGM, typeDecl)) { + createInPlaceInitializationMetadataAccessFunction(IGM, typeDecl, type); + return; + } + + // Otherwise, use the lazy pattern, which should be emitted using a + // direct reference to the metadata. + createDirectTypeMetadataAccessFunction(IGM, type, /*allow existing*/ false); +} + // Classes /// Emit the base-offset variable for the class. @@ -2170,13 +2187,7 @@ namespace { } void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) { - for (unsigned i = 0, - e = placeholder->getNumberOfFieldOffsetVectorEntries(); - i < e; ++i) { - // Emit placeholder values for some number of stored properties we - // know exist but aren't able to reference directly. - B.addInt(IGM.SizeTy, 0); - } + llvm_unreachable("Fixed class metadata cannot have missing members"); } void addMethod(SILDeclRef fn) { @@ -2320,11 +2331,7 @@ namespace { void noteResilientSuperclass() {} - void noteStartOfImmediateMembers(ClassDecl *theClass) { - if (theClass == Target) { - emitClassMetadataBaseOffset(IGM, theClass); - } - } + void noteStartOfImmediateMembers(ClassDecl *theClass) {} /// The 'metadata flags' field in a class is actually a pointer to /// the metaclass object for the class. @@ -2530,26 +2537,19 @@ namespace { void createMetadataAccessFunction() { assert(!Target->isGenericContext()); - auto type =cast(Target->getDeclaredType()->getCanonicalType()); + emitClassMetadataBaseOffset(IGM, Target); + createNonGenericMetadataAccessFunction(IGM, Target); - // Fixed case. - if (!doesClassMetadataRequireInitialization(IGM, Target)) { - (void) createDirectTypeMetadataAccessFunction(IGM, type, - /*allowExisting*/ false); - return; + if (doesClassMetadataRequireInitialization(IGM, Target)) { + emitMetadataCompletionFunction( + IGM, Target, + [&](IRGenFunction &IGF, llvm::Value *metadata, + MetadataDependencyCollector *collector) { + emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata, + collector); + }); } - // Otherwise, we have to initialize metadata at runtime. - createInPlaceInitializationMetadataAccessFunction(IGM, Target, type); - - emitMetadataCompletionFunction( - IGM, Target, - [&](IRGenFunction &IGF, llvm::Value *metadata, - MetadataDependencyCollector *collector) { - emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata, - collector); - }); - // If the class has resilient ancestry we also need a relocation // function. if (doesClassMetadataRequireRelocation(IGM, Target)) @@ -3030,23 +3030,6 @@ namespace { }; } -/// Create an access function for the given non-generic type. -static void createNonGenericMetadataAccessFunction(IRGenModule &IGM, - NominalTypeDecl *typeDecl) { - assert(!typeDecl->isGenericContext()); - auto type = typeDecl->getDeclaredType()->getCanonicalType(); - - // If the type requires the in-place initialization pattern, use it. - if (needsInPlaceMetadataInitialization(IGM, typeDecl)) { - createInPlaceInitializationMetadataAccessFunction(IGM, typeDecl, type); - return; - } - - // Otherwise, use the lazy pattern, which should be emitted using a - // direct reference to the metadata. - createDirectTypeMetadataAccessFunction(IGM, type, /*allow existing*/ false); -} - //===----------------------------------------------------------------------===// // Structs From 120be251dbe4abd0e0602a1bf98f9ec0c72cf5a3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 23 Aug 2018 12:14:15 -0700 Subject: [PATCH 3/4] IRGen: Metadata patterns are always true-const They were, already, but remove the isConstant parameter to getAddrOfTypeMetadataPattern(), and just assert that its true for patterns in defineTypeMetadata() instead. Also, metadata patterns are i8*, not i8**. In fact they don't contain any absolute pointers at all. Should be NFC other than the LLVM type change. --- include/swift/Runtime/RuntimeFunctions.def | 8 ++++---- lib/IRGen/GenDecl.cpp | 10 +++++----- lib/IRGen/GenMeta.cpp | 6 +++--- lib/IRGen/IRGenModule.h | 1 - test/IRGen/class_resilience.swift | 4 ++-- test/IRGen/enum.sil | 4 ++-- test/IRGen/enum_dynamic_multi_payload.sil | 2 +- test/IRGen/enum_value_semantics.sil | 2 +- test/IRGen/generic_classes.sil | 16 ++++++++-------- test/IRGen/generic_structs.sil | 8 ++++---- test/IRGen/generic_types.swift | 8 ++++---- test/IRGen/generic_vtable.swift | 4 ++-- .../require-layout-generic-arg-closure.swift | 2 +- .../require-layout-generic-arg-subscript.swift | 2 +- test/multifile/require-layout-generic-arg.swift | 2 +- 15 files changed, 39 insertions(+), 40 deletions(-) diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 70dcc955281ac..9c39f3e78abb9 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -670,19 +670,19 @@ FUNCTION(GetGenericMetadata, swift_getGenericMetadata, SwiftCC, // Metadata *swift_allocateGenericClassMetadata(ClassDescriptor *type, // const void * const *arguments, -// const void * const *template); +// const void *template); FUNCTION(AllocateGenericClassMetadata, swift_allocateGenericClassMetadata, C_CC, RETURNS(TypeMetadataPtrTy), - ARGS(TypeContextDescriptorPtrTy, Int8PtrPtrTy, Int8PtrPtrTy), + ARGS(TypeContextDescriptorPtrTy, Int8PtrPtrTy, Int8PtrTy), ATTRS(NoUnwind)) // Metadata *swift_allocateGenericValueMetadata(ValueTypeDescriptor *type, // const void * const *arguments, -// const void * const *template, +// const void *template, // size_t extraSize); FUNCTION(AllocateGenericValueMetadata, swift_allocateGenericValueMetadata, C_CC, RETURNS(TypeMetadataPtrTy), - ARGS(TypeContextDescriptorPtrTy, Int8PtrPtrTy, Int8PtrPtrTy, SizeTy), + ARGS(TypeContextDescriptorPtrTy, Int8PtrPtrTy, Int8PtrTy, SizeTy), ATTRS(NoUnwind)) // MetadataResponse swift_checkMetadataState(MetadataRequest request, diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 8d620e9c08cfb..32a7625868916 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3282,8 +3282,9 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, assert(init); if (isPattern) { + assert(isConstant && "Type metadata patterns must be constant"); auto addr = getAddrOfTypeMetadataPattern(concreteType->getAnyNominal(), - isConstant, init, section); + init, section); return cast(addr); } @@ -3488,12 +3489,11 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType, llvm::Constant * IRGenModule::getAddrOfTypeMetadataPattern(NominalTypeDecl *D) { - return getAddrOfTypeMetadataPattern(D, false, ConstantInit(), ""); + return getAddrOfTypeMetadataPattern(D, ConstantInit(), ""); } llvm::Constant * IRGenModule::getAddrOfTypeMetadataPattern(NominalTypeDecl *D, - bool isConstant, ConstantInit init, StringRef section) { if (!init) @@ -3502,7 +3502,7 @@ IRGenModule::getAddrOfTypeMetadataPattern(NominalTypeDecl *D, auto alignment = getPointerAlignment(); LinkEntity entity = LinkEntity::forTypeMetadataPattern(D); auto addr = getAddrOfLLVMVariable(entity, alignment, init, - Int8PtrTy, DebugTypeInfo()); + Int8Ty, DebugTypeInfo()); if (init) { auto var = cast(addr); @@ -3565,7 +3565,7 @@ IRGenModule::getAddrOfTypeMetadataInstantiationFunction(NominalTypeDecl *D, /// Generic arguments. Int8PtrPtrTy, /// Generic metadata pattern. - Int8PtrPtrTy + Int8PtrTy }; fnType = llvm::FunctionType::get(TypeMetadataPtrTy, argTys, diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 6c51f0e1cb4b3..5627842919219 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2854,7 +2854,7 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, GenericClassMetadataBuilder builder(IGM, classDecl, init, fieldLayout); builder.layout(); - canBeConstant = false; + canBeConstant = true; builder.createMetadataAccessFunction(); } else if (doesClassMetadataRequireRelocation(IGM, classDecl)) { @@ -3255,7 +3255,7 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) { GenericStructMetadataBuilder builder(IGM, structDecl, init); builder.layout(); isPattern = true; - canBeConstant = false; + canBeConstant = true; builder.createMetadataAccessFunction(); } else { @@ -3450,7 +3450,7 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) { GenericEnumMetadataBuilder builder(IGM, theEnum, init); builder.layout(); isPattern = true; - canBeConstant = false; + canBeConstant = true; builder.createMetadataAccessFunction(); } else { diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 336a432b509d2..e813024ab11e6 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1168,7 +1168,6 @@ private: \ SymbolReferenceKind kind); llvm::Constant *getAddrOfTypeMetadataPattern(NominalTypeDecl *D); llvm::Constant *getAddrOfTypeMetadataPattern(NominalTypeDecl *D, - bool isConstant, ConstantInit init, StringRef section); llvm::Function *getAddrOfTypeMetadataCompletionFunction(NominalTypeDecl *D, diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift index dcc0a26f9a0b4..9f72a42d8ee04 100644 --- a/test/IRGen/class_resilience.swift +++ b/test/IRGen/class_resilience.swift @@ -518,8 +518,8 @@ extension ResilientGenericOutsideParent { // ResilientGenericChild metadata initialization function -// CHECK-LABEL: define internal %swift.type* @"$S16class_resilience21ResilientGenericChildCMi"(%swift.type_descriptor*, i8**, i8**) -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK-LABEL: define internal %swift.type* @"$S16class_resilience21ResilientGenericChildCMi"(%swift.type_descriptor*, i8**, i8*) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK: ret %swift.type* [[METADATA]] // CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$S16class_resilience21ResilientGenericChildCMr" diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil index 5076f51f828ef..18b4e891a8e3c 100644 --- a/test/IRGen/enum.sil +++ b/test/IRGen/enum.sil @@ -2633,10 +2633,10 @@ entry(%x : $*MyOptional): } // -- Fill function for dynamic singleton. -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S4enum16DynamicSingletonOMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S4enum16DynamicSingletonOMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { // CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type** // CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]], -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2, [[WORD]] {{4|8}}) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2, [[WORD]] {{4|8}}) // CHECK-NEXT: ret %swift.type* [[METADATA]] // CHECK-LABEL: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$S4enum16DynamicSingletonOMr" diff --git a/test/IRGen/enum_dynamic_multi_payload.sil b/test/IRGen/enum_dynamic_multi_payload.sil index 331f184d71526..2a2080dc277bc 100644 --- a/test/IRGen/enum_dynamic_multi_payload.sil +++ b/test/IRGen/enum_dynamic_multi_payload.sil @@ -417,7 +417,7 @@ entry(%a : $*EitherOr, %b : $*EitherOr): return undef : $() } -// CHECK: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S26enum_dynamic_multi_payload8EitherOrOMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { +// CHECK: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S26enum_dynamic_multi_payload8EitherOrOMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata // CHECK: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$S26enum_dynamic_multi_payload8EitherOrOMr" diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil index 4ce6124c536bc..8cba4d2cfa8f8 100644 --- a/test/IRGen/enum_value_semantics.sil +++ b/test/IRGen/enum_value_semantics.sil @@ -167,7 +167,7 @@ enum GenericFixedLayout { // CHECK-LABEL: @"$S20enum_value_semantics18GenericFixedLayoutOMP" = internal constant <{ {{.*}} }> <{ // Instantiation function. -// CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (%swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S20enum_value_semantics18GenericFixedLayoutOMi" to i64), i64 ptrtoint (<{ i32, i32, i32, i32 }>* @"$S20enum_value_semantics18GenericFixedLayoutOMP" to i64)) to i32), +// CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (%swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$S20enum_value_semantics18GenericFixedLayoutOMi" to i64), i64 ptrtoint (<{ i32, i32, i32, i32 }>* @"$S20enum_value_semantics18GenericFixedLayoutOMP" to i64)) to i32), // Completion function. // CHECK-SAME: i32 0, // Pattern flags. 0x4020_0000 == (MetadataKind::Enum << 21). diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil index 407da219b0760..e1eb79471e191 100644 --- a/test/IRGen/generic_classes.sil +++ b/test/IRGen/generic_classes.sil @@ -44,7 +44,7 @@ import Swift // CHECK-LABEL: @"$S15generic_classes11RootGenericCMP" = internal constant // CHECK-SAME: <{ // -- template instantiation function -// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S15generic_classes11RootGenericCMi" +// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$S15generic_classes11RootGenericCMi" // -- heap destructor // CHECK-SAME: @"$S15generic_classes11RootGenericCfD" // -- ivar destroyer @@ -113,7 +113,7 @@ import Swift // CHECK: @"$S15generic_classes015GenericInheritsC0CMP" = internal constant // -- template instantiation function -// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S15generic_classes015GenericInheritsC0CMi" +// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$S15generic_classes015GenericInheritsC0CMi" // -- pattern flags (1 == has extra data pattern) // CHECK-SAME-native: i32 0, // CHECK-SAME-objc: i32 1, @@ -339,8 +339,8 @@ entry(%c : $RootGeneric): } */ -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S15generic_classes11RootGenericCMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { -// CHECK: [[METADATA:%.*]] = call{{( tail)?}} %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S15generic_classes11RootGenericCMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { +// CHECK: [[METADATA:%.*]] = call{{( tail)?}} %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal swiftcc %swift.metadata_response @"$S15generic_classes11RootGenericCMr" // CHECK-SAME: (%swift.type* [[METADATA:%.*]], i8*, i8**) {{.*}} { @@ -348,22 +348,22 @@ entry(%c : $RootGeneric): // CHECK: call void @swift_initClassMetadata(%swift.type* [[METADATA]], %swift.type* null, i64 0, i64 3, i8*** {{%.*}}, i64* {{%.*}}) // CHECK: } -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S15generic_classes22RootGenericFixedLayoutCMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { -// CHECK: [[METADATA:%.*]] ={{( tail)?}} call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S15generic_classes22RootGenericFixedLayoutCMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { +// CHECK: [[METADATA:%.*]] ={{( tail)?}} call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal swiftcc %swift.metadata_response @"$S15generic_classes22RootGenericFixedLayoutCMr" // CHECK-SAME: (%swift.type* [[METADATA:%.*]], i8*, i8**) {{.*}} { // CHECK: call void @swift_initClassMetadata(%swift.type* [[METADATA]], %swift.type* null, i64 0, i64 3, i8*** {{%.*}}, i64* {{%.*}}) // CHECK: } -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S15generic_classes015GenericInheritsC0CMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S15generic_classes015GenericInheritsC0CMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { // Bind the generic parameters. // CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type** // CHECK: %A = load %swift.type*, %swift.type** [[T0]] // CHECK: [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i32 1 // CHECK: %B = load %swift.type*, %swift.type** [[T1]] // Construct the class. -// CHECK: [[METADATA:%.*]] ={{( tail)?}} call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK: [[METADATA:%.*]] ={{( tail)?}} call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK-NEXT: ret %swift.type* [[METADATA]] // CHECK-LABEL: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$S15generic_classes015GenericInheritsC0CMr" diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil index 00e30a059c3cf..eba7d27ad26c6 100644 --- a/test/IRGen/generic_structs.sil +++ b/test/IRGen/generic_structs.sil @@ -11,7 +11,7 @@ import Builtin // CHECK: [[PATTERN:@.*]] = internal constant [4 x i32] [i32 0, i32 1, i32 8, i32 0] // CHECK-LABEL: @"$S15generic_structs18FixedLayoutGenericVMP" = internal constant <{ {{.*}} }> <{ // -- instantiation function -// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S15generic_structs18FixedLayoutGenericVMi" +// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$S15generic_structs18FixedLayoutGenericVMi" // -- completion function // CHECK-SAME: i32 0, // -- pattern flags @@ -56,7 +56,7 @@ import Builtin // CHECK-SAME: }> // CHECK: @"$S15generic_structs13SingleDynamicVMP" = internal constant <{ {{.*}} }> <{ // -- instantiation function -// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S15generic_structs13SingleDynamicVMi" +// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$S15generic_structs13SingleDynamicVMi" // -- vwtable pointer // CHECK-SAME: @"$S15generic_structs13SingleDynamicVWV" @@ -195,10 +195,10 @@ entry(%0 : $*ComplexDynamic, %1 : $*Byteful, %2 : $*A, %3 : $*B, %4 : $*Ch return %v : $() } -// CHECK-LABEL: define{{( protected)?}} internal %swift.type* @"$S15generic_structs13SingleDynamicVMi"(%swift.type_descriptor*, i8**, i8**) +// CHECK-LABEL: define{{( protected)?}} internal %swift.type* @"$S15generic_structs13SingleDynamicVMi"(%swift.type_descriptor*, i8**, i8*) // CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type** // CHECK: %T = load %swift.type*, %swift.type** [[T0]], align 8 -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2, i64 16) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2, i64 16) // CHECK-NEXT: ret %swift.type* [[METADATA]] // CHECK: } diff --git a/test/IRGen/generic_types.swift b/test/IRGen/generic_types.swift index d8b5df070acad..d93d05e162ef5 100644 --- a/test/IRGen/generic_types.swift +++ b/test/IRGen/generic_types.swift @@ -93,17 +93,17 @@ // CHECK-SAME: i32 {{3|2}}, // CHECK-SAME: } -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S13generic_types1ACMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S13generic_types1ACMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { // CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type** // CHECK: %T = load %swift.type*, %swift.type** [[T0]], -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK-NEXT: ret %swift.type* [[METADATA]] // CHECK: } -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S13generic_types1BCMi"(%swift.type_descriptor*, i8**, i8**) {{.*}} { +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$S13generic_types1BCMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} { // CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type** // CHECK: %T = load %swift.type*, %swift.type** [[T0]], -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK-NEXT: ret %swift.type* [[METADATA]] // CHECK: } diff --git a/test/IRGen/generic_vtable.swift b/test/IRGen/generic_vtable.swift index 3a49a063a23e9..e8c15f805f4d0 100644 --- a/test/IRGen/generic_vtable.swift +++ b/test/IRGen/generic_vtable.swift @@ -110,12 +110,12 @@ public class Concrete : Derived { //// Metadata initialization function for 'Derived' copies superclass vtable //// and installs overrides for 'm2()' and 'init()'. -// CHECK-LABEL: define internal %swift.type* @"$S14generic_vtable7DerivedCMi"(%swift.type_descriptor*, i8**, i8**) +// CHECK-LABEL: define internal %swift.type* @"$S14generic_vtable7DerivedCMi"(%swift.type_descriptor*, i8**, i8*) // - 2 immediate members: // - type metadata for generic parameter T, // - and vtable entry for 'm3()' -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8** %2) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) // CHECK: ret %swift.type* [[METADATA]] // CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$S14generic_vtable7DerivedCMr" diff --git a/test/multifile/require-layout-generic-arg-closure.swift b/test/multifile/require-layout-generic-arg-closure.swift index 49b7bf2739311..6d7b299e4b3ae 100644 --- a/test/multifile/require-layout-generic-arg-closure.swift +++ b/test/multifile/require-layout-generic-arg-closure.swift @@ -17,7 +17,7 @@ public func requestType2(x: T) { requestTypeThrough(closure: { x in print(x) }, arg: x) } -// FILE2-LABEL: define internal %swift.type* @"$S4test3SubCMi"(%swift.type_descriptor*, i8**, i8**) +// FILE2-LABEL: define internal %swift.type* @"$S4test3SubCMi"(%swift.type_descriptor*, i8**, i8*) // FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type** // FILE2: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]] // FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata diff --git a/test/multifile/require-layout-generic-arg-subscript.swift b/test/multifile/require-layout-generic-arg-subscript.swift index fe8e1e2401a66..7eb7f650729e7 100644 --- a/test/multifile/require-layout-generic-arg-subscript.swift +++ b/test/multifile/require-layout-generic-arg-subscript.swift @@ -21,7 +21,7 @@ public class AccessorTest { } } -// FILE2-LABEL: define internal %swift.type* @"$S4test3SubCMi"(%swift.type_descriptor*, i8**, i8**) +// FILE2-LABEL: define internal %swift.type* @"$S4test3SubCMi"(%swift.type_descriptor*, i8**, i8*) // FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type** // FILE2: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]] // FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata diff --git a/test/multifile/require-layout-generic-arg.swift b/test/multifile/require-layout-generic-arg.swift index 0f2ebc06a7c07..9c7af0c5c6b45 100644 --- a/test/multifile/require-layout-generic-arg.swift +++ b/test/multifile/require-layout-generic-arg.swift @@ -15,7 +15,7 @@ public func requestType(_ c: Sub) { print(T.self) } -// FILE2-LABEL: define internal %swift.type* @"$S4test3SubCMi"(%swift.type_descriptor*, i8**, i8**) +// FILE2-LABEL: define internal %swift.type* @"$S4test3SubCMi"(%swift.type_descriptor*, i8**, i8*) // FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type** // FILE2: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]] // FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata From 03cb6d1ff439a9385f49a9e75850f6f5ab5eecf0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Aug 2018 23:49:49 -0700 Subject: [PATCH 4/4] IRGen/Runtime: Use a true-const pattern to initialize non-generic resilient class metadata Previously we would emit class metadata for classes with resilient ancestry, and relocate it at runtime once the correct size was known. However most of the fields were blank, so it makes more sense to construct the metadata from scratch, and store the few bits that we do need in a true-const pattern where we can use relative pointers. --- include/swift/ABI/Metadata.h | 49 ++++- include/swift/Runtime/Metadata.h | 10 +- include/swift/Runtime/RuntimeFunctions.def | 5 +- lib/IRGen/GenDecl.cpp | 2 + lib/IRGen/GenMeta.cpp | 209 +++++++++++++-------- stdlib/public/runtime/Metadata.cpp | 90 +++++++-- test/IRGen/class_resilience.swift | 82 +++++--- 7 files changed, 308 insertions(+), 139 deletions(-) diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index bd2fc60701e9d..51ed926945a88 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -3085,7 +3085,7 @@ class TargetGenericMetadataPatternTrailingObjects : } }; -/// An instantiation pattern for class metadata. +/// An instantiation pattern for generic class metadata. template struct TargetGenericClassMetadataPattern final : TargetGenericMetadataPattern, @@ -3138,7 +3138,7 @@ struct TargetGenericClassMetadataPattern final : using GenericClassMetadataPattern = TargetGenericClassMetadataPattern; -/// An instantiation pattern for value metadata. +/// An instantiation pattern for generic value metadata. template struct TargetGenericValueMetadataPattern final : TargetGenericMetadataPattern, @@ -3316,10 +3316,43 @@ struct TargetInPlaceValueMetadataCache { using InPlaceValueMetadataCache = TargetInPlaceValueMetadataCache; +template +struct TargetResilientClassMetadataPattern; + /// An instantiation pattern for non-generic resilient class metadata. /// Used in conjunction with InPlaceValueMetadataInitialization. using MetadataRelocator = - Metadata *(const TargetTypeContextDescriptor *description); + Metadata *(const TargetTypeContextDescriptor *type, + const TargetResilientClassMetadataPattern *pattern); + +/// An instantiation pattern for non-generic resilient class metadata. +template +struct TargetResilientClassMetadataPattern { + /// If the class descriptor's hasResilientSuperclass() flag is set, + /// this field instead points at a function that allocates metadata + /// with the correct size at runtime. + TargetRelativeDirectPointer RelocationFunction; + + /// The heap-destructor function. + TargetRelativeDirectPointer Destroy; + + /// The ivar-destructor function. + TargetRelativeDirectPointer IVarDestroyer; + + /// The class flags. + ClassFlags Flags; + + // The following fields are only present in ObjC interop. + + /// Our ClassROData. + TargetRelativeDirectPointer Data; + + /// Our metaclass. + TargetRelativeDirectPointer> Metaclass; +}; + +using ResilientClassMetadataPattern = + TargetResilientClassMetadataPattern; /// The control structure for performing non-trivial initialization of /// singleton value metadata, which is required when e.g. a non-generic @@ -3340,8 +3373,8 @@ struct TargetInPlaceValueMetadataInitialization { /// If the class descriptor's hasResilientSuperclass() flag is set, /// this field instead points at a function that allocates metadata /// with the correct size at runtime. - TargetRelativeDirectPointer - RelocationFunction; + TargetRelativeDirectPointer> + ResilientPattern; }; /// The completion function. The pattern will always be null. @@ -3358,8 +3391,10 @@ struct TargetInPlaceValueMetadataInitialization { TargetMetadata *allocate( const TargetTypeContextDescriptor *description) const { - if (hasRelocationFunction(description)) - return RelocationFunction(description); + if (hasRelocationFunction(description)) { + return ResilientPattern->RelocationFunction(description, + ResilientPattern.get()); + } return IncompleteMetadata.get(); } }; diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 177ef2f57524c..13580c3fc43d9 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -574,15 +574,13 @@ void swift_initStructMetadata(StructMetadata *self, const TypeLayout * const *fieldTypes, uint32_t *fieldOffsets); -/// Relocate the metadata for a class and copy fields from the given template. -/// The final size of the metadata is calculated at runtime from the size of -/// the superclass metadata together with the given number of immediate -/// members. +/// Allocate the metadata for a class and copy fields from the given pattern. +/// The final size of the metadata is calculated at runtime from the metadata +/// bounds in the class descriptor. SWIFT_RUNTIME_EXPORT ClassMetadata * swift_relocateClassMetadata(ClassDescriptor *descriptor, - ClassMetadata *pattern, - size_t patternSize); + ResilientClassMetadataPattern *pattern); /// Initialize the field offset vector for a dependent-layout class, using the /// "Universal" layout strategy. diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 9c39f3e78abb9..b9db24bae04f0 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -809,12 +809,11 @@ FUNCTION(GetExistentialMetadata, ATTRS(NoUnwind, ReadOnly)) // Metadata *swift_relocateClassMetadata(TypeContextDescriptor *descriptor, -// Metadata *pattern, -// size_t patternSize); +// const void *pattern); FUNCTION(RelocateClassMetadata, swift_relocateClassMetadata, C_CC, RETURNS(TypeMetadataPtrTy), - ARGS(TypeContextDescriptorPtrTy, TypeMetadataPtrTy, SizeTy), + ARGS(TypeContextDescriptorPtrTy, Int8PtrTy), ATTRS(NoUnwind)) // struct FieldInfo { size_t Size; size_t AlignMask; }; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 32a7625868916..efcff0de5c0e5 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3577,6 +3577,8 @@ IRGenModule::getAddrOfTypeMetadataInstantiationFunction(NominalTypeDecl *D, llvm::Type *argTys[] = { /// Type descriptor. TypeContextDescriptorPtrTy, + /// Resilient metadata pattern. + Int8PtrTy }; fnType = llvm::FunctionType::get(TypeMetadataPtrTy, argTys, diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 5627842919219..8c21133f53266 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1245,10 +1245,8 @@ namespace { return; } - llvm::Function *relocationFunction = - IGM.getAddrOfTypeMetadataInstantiationFunction(getType(), - NotForDefinition); - B.addRelativeAddress(relocationFunction); + auto *pattern = IGM.getAddrOfTypeMetadataPattern(Type); + B.addRelativeAddress(pattern); } ContextDescriptorKind getContextKind() { @@ -2273,26 +2271,6 @@ namespace { } }; - /// Utility class for building member metadata for classes with resilient - /// ancestry. The total size of the class metadata is not known at compile - /// time, and requires relocation. - class ResilientClassMemberBuilder { - public: - ResilientClassMemberBuilder(IRGenModule &IGM, - ConstantStructBuilder &builder, - SILVTable *vtable) {} - - void addFieldOffset(VarDecl *var) {} - - void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {} - - void addMethod(SILDeclRef fn) {} - - void addGenericArgument(ClassDecl *forClass) {} - - void addGenericWitnessTable(ClassDecl *forClass) {} - }; - /// Base class for layout of non-generic class metadata. template class ClassMetadataBuilderBase : public ClassMetadataVisitor { @@ -2540,54 +2518,16 @@ namespace { emitClassMetadataBaseOffset(IGM, Target); createNonGenericMetadataAccessFunction(IGM, Target); - if (doesClassMetadataRequireInitialization(IGM, Target)) { - emitMetadataCompletionFunction( - IGM, Target, - [&](IRGenFunction &IGF, llvm::Value *metadata, - MetadataDependencyCollector *collector) { - emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata, - collector); - }); - } - - // If the class has resilient ancestry we also need a relocation - // function. - if (doesClassMetadataRequireRelocation(IGM, Target)) - emitRelocationFunction(); - } - - private: - /// Emit the create function for a class with resilient ancestry. - void emitRelocationFunction() { - // using MetadataRelocator = - // Metadata *(TypeContextDescriptor *type, - // Metadata *metadata); - llvm::Function *f = - IGM.getAddrOfTypeMetadataInstantiationFunction(Target, ForDefinition); - f->setAttributes(IGM.constructInitialAttributes()); - - IRGenFunction IGF(IGM, f); - - // Skip instrumentation when building for TSan to avoid false positives. - // The synchronization for this happens in the Runtime and we do not see it. - if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread) - f->removeFnAttr(llvm::Attribute::SanitizeThread); - - if (IGM.DebugInfo) - IGM.DebugInfo->emitArtificialFunction(IGF, f); - - Explosion params = IGF.collectParameters(); - llvm::Value *descriptor = params.claimNext(); - - llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata( - Target->getDeclaredType()->getCanonicalType()); - - // Relocate the metadata. - auto patternSize = IGM.getSize(Size(B.getNextOffsetFromGlobal())); - metadata = IGF.Builder.CreateCall(IGF.IGM.getRelocateClassMetadataFn(), - {descriptor, metadata, patternSize}); + if (!doesClassMetadataRequireInitialization(IGM, Target)) + return; - IGF.Builder.CreateRet(metadata); + emitMetadataCompletionFunction( + IGM, Target, + [&](IRGenFunction &IGF, llvm::Value *metadata, + MetadataDependencyCollector *collector) { + emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata, + collector); + }); } }; @@ -2621,18 +2561,120 @@ namespace { : super(IGM, theClass, builder, fieldLayout) {} }; - /// A builder for non-generic class metadata with resilient ancestry. - class ResilientClassMetadataBuilder : - public ClassMetadataBuilderBase { - using super = ClassMetadataBuilderBase; + /// A builder for metadata patterns for non-generic class with + /// resilient ancestry. + class ResilientClassMetadataBuilder { + IRGenModule &IGM; + ClassDecl *Target; + ConstantStructBuilder &B; + const ClassLayout &FieldLayout; public: ResilientClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass, ConstantStructBuilder &builder, const ClassLayout &fieldLayout) - : super(IGM, theClass, builder, fieldLayout) {} + : IGM(IGM), Target(theClass), B(builder), FieldLayout(fieldLayout) {} + + llvm::Constant *emitNominalTypeDescriptor() { + return ClassContextDescriptorBuilder(IGM, Target, RequireMetadata).emit(); + } + + void layout() { + emitNominalTypeDescriptor(); + + addRelocationFunction(); + addDestructorFunction(); + addIVarDestroyer(); + addClassFlags(); + addClassDataPointer(); + addMetaclass(); + } + + void addRelocationFunction() { + auto function = IGM.getAddrOfTypeMetadataInstantiationFunction( + Target, NotForDefinition); + B.addRelativeAddress(function); + } + + void addDestructorFunction() { + auto function = getAddrOfDestructorFunction(IGM, Target); + B.addRelativeAddressOrNull(function ? *function : nullptr); + } + + void addIVarDestroyer() { + auto function = IGM.getAddrOfIVarInitDestroy(Target, + /*isDestroyer=*/ true, + /*isForeign=*/ false, + NotForDefinition); + B.addRelativeAddressOrNull(function ? *function : nullptr); + } + + void addClassFlags() { + B.addInt32((uint32_t) getClassFlags(Target)); + } + + void addClassDataPointer() { + auto data = (IGM.ObjCInterop + ? emitClassPrivateData(IGM, Target) + : nullptr); + B.addRelativeAddressOrNull(data); + } + + void addMetaclass() { + auto metaclass = (IGM.ObjCInterop + ? IGM.getAddrOfMetaclassObject(Target, NotForDefinition) + : nullptr); + B.addRelativeAddressOrNull(metaclass); + } + + void createMetadataAccessFunction() { + assert(doesClassMetadataRequireRelocation(IGM, Target)); + + assert(!Target->isGenericContext()); + emitClassMetadataBaseOffset(IGM, Target); + createNonGenericMetadataAccessFunction(IGM, Target); + + emitMetadataCompletionFunction( + IGM, Target, + [&](IRGenFunction &IGF, llvm::Value *metadata, + MetadataDependencyCollector *collector) { + emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata, + collector); + }); + + emitRelocationFunction(); + } + + private: + /// Emit the create function for a class with resilient ancestry. + void emitRelocationFunction() { + // using MetadataRelocator = + // Metadata *(TypeContextDescriptor *type, void *pattern); + llvm::Function *f = + IGM.getAddrOfTypeMetadataInstantiationFunction(Target, ForDefinition); + f->setAttributes(IGM.constructInitialAttributes()); + + IRGenFunction IGF(IGM, f); + + // Skip instrumentation when building for TSan to avoid false positives. + // The synchronization for this happens in the Runtime and we do not see it. + if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread) + f->removeFnAttr(llvm::Attribute::SanitizeThread); + + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, f); + + Explosion params = IGF.collectParameters(); + llvm::Value *descriptor = params.claimNext(); + llvm::Value *pattern = params.claimNext(); + + // Allocate class metadata using the pattern we emitted. + llvm::Value *metadata = + IGF.Builder.CreateCall(IGF.IGM.getRelocateClassMetadataFn(), + {descriptor, pattern}); + + IGF.Builder.CreateRet(metadata); + } }; /// A builder for GenericClassMetadataPattern objects. @@ -2848,7 +2890,10 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, auto init = builder.beginStruct(); init.setPacked(true); - bool isGeneric = classDecl->isGenericContext(); + // If the class is generic or has resilient ancestry, we emit a pattern, + // not type metadata. + bool isPattern = doesClassMetadataRequireRelocation(IGM, classDecl); + bool canBeConstant; if (classDecl->isGenericContext()) { GenericClassMetadataBuilder builder(IGM, classDecl, init, @@ -2861,7 +2906,7 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, ResilientClassMetadataBuilder builder(IGM, classDecl, init, fieldLayout); builder.layout(); - canBeConstant = builder.canBeConstant(); + canBeConstant = true; builder.createMetadataAccessFunction(); } else if (doesClassMetadataRequireInitialization(IGM, classDecl)) { @@ -2887,14 +2932,14 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, IGM.TargetInfo.OutputObjectFormat == llvm::Triple::MachO) section = "__DATA,__objc_data, regular"; - auto var = IGM.defineTypeMetadata(declaredType, isGeneric, canBeConstant, + auto var = IGM.defineTypeMetadata(declaredType, isPattern, canBeConstant, init.finishAndCreateFuture(), section); // Add classes that don't require dynamic initialization to the // ObjC class list. // // FIXME: This is where we check the completely fragile layout. - if (IGM.ObjCInterop && !isGeneric && + if (IGM.ObjCInterop && !isPattern && !doesClassMetadataRequireInitialization(IGM, classDecl)) { // Emit the ObjC class symbol to make the class visible to ObjC. if (classDecl->isObjC()) { diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index b2f0d1affceee..e90b75a0ae41d 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -350,7 +350,7 @@ initializeClassMetadataFromPattern(ClassMetadata *metadata, // Initialize the header: // Heap destructor. - fullMetadata->destroy = pattern->Destroy; + fullMetadata->destroy = pattern->Destroy.get(); // Value witness table. #if SWIFT_OBJC_INTEROP @@ -2121,29 +2121,83 @@ static MetadataAllocator &getResilientMetadataAllocator() { ClassMetadata * swift::swift_relocateClassMetadata(ClassDescriptor *description, - ClassMetadata *pattern, - size_t patternSize) { + ResilientClassMetadataPattern *pattern) { auto bounds = description->getMetadataBounds(); - auto metadataSize = bounds.getTotalSizeInBytes(); - if (patternSize < metadataSize) { - auto bytes = (char*) malloc(metadataSize); + auto metadata = reinterpret_cast( + (char*) malloc(bounds.getTotalSizeInBytes()) + + bounds.getAddressPointInBytes()); + auto fullMetadata = asFullMetadata(metadata); + char *rawMetadata = reinterpret_cast(metadata); - auto fullPattern = (const char*) pattern; - fullPattern -= pattern->getClassAddressPoint(); - memcpy(bytes, fullPattern, patternSize); - memset(bytes + patternSize, 0, - metadataSize - patternSize); + // Zero out the entire immediate-members section. + void **immediateMembers = + reinterpret_cast(rawMetadata + bounds.ImmediateMembersOffset); + memset(immediateMembers, 0, description->getImmediateMembersSize()); - auto addressPoint = bytes + bounds.getAddressPointInBytes(); - auto metadata = reinterpret_cast(addressPoint); + // Initialize the header: - metadata->setClassSize(metadataSize); - assert(metadata->isTypeMetadata()); - return metadata; - } + // Heap destructor. + fullMetadata->destroy = pattern->Destroy.get(); - return pattern; + // Value witness table. +#if SWIFT_OBJC_INTEROP + fullMetadata->ValueWitnesses = + (pattern->Flags & ClassFlags::UsesSwiftRefcounting) + ? &VALUE_WITNESS_SYM(Bo) + : &VALUE_WITNESS_SYM(BO); +#else + fullMetadata->ValueWitnesses = &VALUE_WITNESS_SYM(Bo); +#endif + + // MetadataKind / isa. +#if SWIFT_OBJC_INTEROP + metadata->setClassISA(pattern->Metaclass.get()); +#else + metadata->setKind(MetadataKind::Class); +#endif + + // Superclass. + metadata->Superclass = nullptr; + +#if SWIFT_OBJC_INTEROP + // Cache data. Install the same initializer that the compiler is + // required to use. We don't need to do this in non-ObjC-interop modes. + metadata->CacheData[0] = &_objc_empty_cache; + metadata->CacheData[1] = nullptr; +#endif + + // RO-data pointer. +#if SWIFT_OBJC_INTEROP + auto classRO = pattern->Data.get(); + metadata->Data = + reinterpret_cast(classRO) | SWIFT_CLASS_IS_SWIFT_MASK; +#else + metadata->Data = SWIFT_CLASS_IS_SWIFT_MASK; +#endif + + // Class flags. + metadata->Flags = pattern->Flags; + + // Instance layout. + metadata->InstanceAddressPoint = 0; + metadata->InstanceSize = 0; + metadata->InstanceAlignMask = 0; + + // Reserved. + metadata->Reserved = 0; + + // Class metadata layout. + metadata->ClassSize = bounds.getTotalSizeInBytes(); + metadata->ClassAddressPoint = bounds.getAddressPointInBytes(); + + // Class descriptor. + metadata->setDescription(description); + + // I-var destroyer. + metadata->IVarDestroyer = pattern->IVarDestroyer; + + return metadata; } /// Initialize the field offset vector for a dependent-layout class, using the diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift index 9f72a42d8ee04..04d693ad4ca14 100644 --- a/test/IRGen/class_resilience.swift +++ b/test/IRGen/class_resilience.swift @@ -3,7 +3,7 @@ // RUN: %target-swift-frontend -emit-module -enable-resilience -enable-class-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift // RUN: %target-swift-frontend -emit-module -enable-resilience -enable-class-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift // RUN: %target-swift-frontend -emit-module -enable-resilience -enable-class-resilience -emit-module-path=%t/resilient_class.swiftmodule -module-name=resilient_class -I %t %S/../Inputs/resilient_class.swift -// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -enable-class-resilience %t/class_resilience.swift | %FileCheck %t/class_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -enable-class-resilience %t/class_resilience.swift | %FileCheck %t/class_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime -DINT=i%target-ptrsize // RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -enable-class-resilience -O %t/class_resilience.swift // CHECK: @"$S16class_resilience26ClassWithResilientPropertyC1s16resilient_struct4SizeVvpWvd" = hidden global [[INT]] 0 @@ -33,14 +33,50 @@ // CHECK: @"$S16class_resilience14ResilientChildCMn" = {{(protected )?}}{{(dllexport )?}}constant <{{.*}}> <{ // -- flags: class, unique, has vtable, in-place initialization, has resilient superclass // CHECK-SAME: +// -- parent: +// CHECK-SAME: @"$S16class_resilienceMXM" // -- name: // CHECK-SAME: [15 x i8]* [[RESILIENTCHILD_NAME]] -// -- num fields +// -- metadata accessor function: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMa" +// -- field descriptor: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMF" +// -- superclass: +// CHECK-SAME: @"got.$S15resilient_class22ResilientOutsideParentCMn" +// -- metadata bounds: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMo" +// -- metadata positive size in words (not used): +// CHECK-SAME: i32 0, +// -- num immediate members: +// CHECK-SAME: i32 4, +// -- num fields: // CHECK-SAME: i32 1, -// -- field offset vector offset +// -- field offset vector offset: // CHECK-SAME: i32 3, +// -- singleton metadata initialization cache: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMl" +// -- resilient pattern: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMP" +// -- completion function: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMr" // CHECK-SAME: }> +// CHECK: @"$S16class_resilience14ResilientChildCMP" = internal constant <{{.*}}> <{ +// -- instantiation function: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCMi" +// -- destructor: +// CHECK-SAME: @"$S16class_resilience14ResilientChildCfD" +// -- ivar destroyer: +// CHECK-SAME: i32 0, +// -- flags: +// CHECK-SAME: i32 3, +// -- RO data: +// CHECK-objc-SAME: @_DATA__TtC16class_resilience14ResilientChild +// CHECK-native-SAME: i32 0, +// -- metaclass: +// CHECK-objc-SAME: @"$S16class_resilience14ResilientChildCMm" +// CHECK-native-SAME: i32 0 + // CHECK: @"$S16class_resilience16FixedLayoutChildCMo" = {{(protected )?}}{{(dllexport )?}}global [[BOUNDS]] zeroinitializer // CHECK: @"$S16class_resilience17MyResilientParentCMo" = {{(protected )?}}{{(dllexport )?}}constant [[BOUNDS]] @@ -361,10 +397,10 @@ extension ResilientGenericOutsideParent { // CHECK: void @swift_initClassMetadata(%swift.type* %0, %swift.type* null, [[INT]] 256, [[INT]] 3, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) // CHECK-native: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* {{.*}} -// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience26ClassWithResilientPropertyC1s16resilient_struct4SizeVvWvd" +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience26ClassWithResilientPropertyC1s16resilient_struct4SizeVvpWvd" // CHECK-native: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* {{.*}} -// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience26ClassWithResilientPropertyC5colors5Int32VvWvd" +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience26ClassWithResilientPropertyC5colors5Int32VvpWvd" // CHECK: br label %metadata-dependencies.cont @@ -400,10 +436,10 @@ extension ResilientGenericOutsideParent { // CHECK: call void @swift_initClassMetadata(%swift.type* %0, %swift.type* null, [[INT]] 256, [[INT]] 2, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) // CHECK-native: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* {{.*}} -// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience33ClassWithResilientlySizedPropertyC1r16resilient_struct9RectangleVvWvd" +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience33ClassWithResilientlySizedPropertyC1r16resilient_struct9RectangleVvpWvd" // CHECK-native: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* {{.*}} -// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience33ClassWithResilientlySizedPropertyC5colors5Int32VvWvd" +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @"$S16class_resilience33ClassWithResilientlySizedPropertyC5colors5Int32VvpWvd" // CHECK: br label %metadata-dependencies.cont @@ -416,14 +452,6 @@ extension ResilientGenericOutsideParent { // CHECK-NEXT: ret %swift.metadata_response [[T1]] -// ResilientChild metadata relocation function - -// CHECK-LABEL: define internal %swift.type* @"$S16class_resilience14ResilientChildCMi"(%swift.type_descriptor*) -// CHECK-NEXT: entry: -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, %swift.type* bitcast ({{.*}} @"$S16class_resilience14ResilientChildCMf", {{.*}}), [[INT]] {{60|96}}) -// CHECK-NEXT: ret %swift.type* [[METADATA]] - - // ResilientChild metadata initialization function // CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$S16class_resilience14ResilientChildCMr"(%swift.type*, i8*, i8**) @@ -467,6 +495,14 @@ extension ResilientGenericOutsideParent { // CHECK-NEXT: ret %swift.metadata_response [[T1]] +// ResilientChild metadata relocation function + +// CHECK-LABEL: define internal %swift.type* @"$S16class_resilience14ResilientChildCMi"(%swift.type_descriptor*, i8*) +// CHECK-NEXT: entry: +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, i8* %1) +// CHECK-NEXT: ret %swift.type* [[METADATA]] + + // ResilientChild.field setter dispatch thunk // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$S16class_resilience14ResilientChildC5fields5Int32VvsTj"(i32, %T16class_resilience14ResilientChildC* swiftself) @@ -482,14 +518,6 @@ extension ResilientGenericOutsideParent { // CHECK-NEXT: ret void -// FixedLayoutChild metadata relocation function - -// CHECK-LABEL: define internal %swift.type* @"$S16class_resilience16FixedLayoutChildCMi"(%swift.type_descriptor*) -// CHECK-NEXT: entry: -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, %swift.type* bitcast ({{.*}} @"$S16class_resilience16FixedLayoutChildCMf", {{.*}}), [[INT]] {{60|96}}) -// CHECK-NEXT: ret %swift.type* [[METADATA]] - - // FixedLayoutChild metadata initialization function // CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$S16class_resilience16FixedLayoutChildCMr"(%swift.type*, i8*, i8**) @@ -516,6 +544,14 @@ extension ResilientGenericOutsideParent { // CHECK-NEXT: ret %swift.metadata_response [[T1]] +// FixedLayoutChild metadata relocation function + +// CHECK-LABEL: define internal %swift.type* @"$S16class_resilience16FixedLayoutChildCMi"(%swift.type_descriptor*, i8*) +// CHECK-NEXT: entry: +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, i8* %1) +// CHECK-NEXT: ret %swift.type* [[METADATA]] + + // ResilientGenericChild metadata initialization function // CHECK-LABEL: define internal %swift.type* @"$S16class_resilience21ResilientGenericChildCMi"(%swift.type_descriptor*, i8**, i8*)