mirror of
https://github.com/apple/swift.git
synced 2026-03-04 18:24:35 +01:00
Previously, the trailing flags field of runtime instantiated generic metadata for types which had prespecialization enabled were not zeroed. Consequently, the field always contained garbage. Often, metadata was instantiated on new (and so, zeroed) pages, so the garbage happened to be zero as is appropriate. However, when the metadata was instantiated on pages which had previously been dirtied, the garbage value would sometimes indicate that the metadata was canonical statically specialized. When that occurred, swift_checkMetadataState would incorrectly return a metadata state of complete, despite the fact that the metadata might not in fact be complete. As a result, the runtime was trafficking in incomplete metadata as if it were complete, resulting in various crashes that would arise from for example missing a witness table or a value witness table. Here the problem is corrected. The trailing flags field of structs and enums that have the field is set to 0. For structs, this is accomplished by modifying the extra data pattern to exist not only when there is fixed type info for the type but also when the type is being prespecialized. Specifically, the extra data for a struct is, rather than an i32 array of field offsets, a struct consisting of none, one, or both of the following: (1) the array of field offsets, (2) the trailing flags. Similarly, enums now have an extra data pattern which consists of none, one, or both of the following: (1) the payload size, (2) the trailing flags. Enum metadata extra data setting was previously achieved by customizing the metadata allocation function; that customization is now eliminated, being replaced with the shared runtime code for copying extra data into place, a modest code size savings. rdar://problem/61465515
262 lines
12 KiB
Plaintext
262 lines
12 KiB
Plaintext
// RUN: %empty-directory(%t)
|
|
// RUN: %{python} %utils/chex.py < %s > %t/generic_structs.sil
|
|
// RUN: %target-swift-frontend -disable-type-layout -disable-generic-metadata-prespecialization %t/generic_structs.sil -emit-ir | %FileCheck %t/generic_structs.sil
|
|
|
|
// REQUIRES: CPU=x86_64
|
|
|
|
import Builtin
|
|
|
|
// -- Generic structs with fixed layout should have no completion function
|
|
// and emit the field offset vector as part of the pattern.
|
|
// CHECK: [[PATTERN:@.*]] = internal constant { i32, i32, i32, [4 x i8] } { i32 0, i32 1, i32 8, [4 x i8] zeroinitializer }, align 8
|
|
// CHECK-LABEL: @"$s15generic_structs18FixedLayoutGenericVMP" = internal constant <{ {{.*}} }> <{
|
|
// -- instantiation function
|
|
// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$s15generic_structs18FixedLayoutGenericVMi"
|
|
// -- completion function
|
|
// CHECK-SAME: i32 0,
|
|
// -- pattern flags
|
|
// CHECK-SAME: <i32 0x4000_0001>,
|
|
// -- vwtable pointer
|
|
// CHECK-SAME: @"$s15generic_structs18FixedLayoutGenericVWV"
|
|
// -- extra data pattern
|
|
// CHECK-SAME: { i32, i32, i32, [4 x i8] }* [[PATTERN]]
|
|
// CHECK-SAME: i16 1,
|
|
// CHECK-SAME: i16 2 }>
|
|
|
|
// -- Generic structs with dynamic layout contain the vwtable pattern as part
|
|
// of the metadata pattern, and no independent vwtable symbol
|
|
// CHECK: @"$s15generic_structs13SingleDynamicVWV" = internal constant
|
|
// CHECK-SAME: i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @"$s15generic_structs13SingleDynamicVwCP" to i8*),
|
|
// -- ...
|
|
// -- placeholder for size, stride, flags
|
|
// CHECK-SAME: i64 0,
|
|
// CHECK-SAME: i64 0,
|
|
// CHECK-SAME: i32 4194304,
|
|
// CHECK-SAME: i32 0 }
|
|
|
|
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
|
|
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
|
|
// CHECK: @"$s15generic_structs13SingleDynamicVMn" = hidden constant
|
|
// -- flags: struct, unique, generic
|
|
// CHECK-SAME: <i32 0x0000_00D1>
|
|
// -- name
|
|
// CHECK-SAME: [14 x i8]* [[SINGLEDYNAMIC_NAME]]
|
|
// -- field count
|
|
// CHECK-SAME: i32 1,
|
|
// -- field offset vector offset
|
|
// CHECK-SAME: i32 3,
|
|
// -- generic instantiation info
|
|
// CHECK-SAME: [{{[0-9]+}} x i8*]* @"$s15generic_structs13SingleDynamicVMI"
|
|
// CHECK-SAME: @"$s15generic_structs13SingleDynamicVMP"
|
|
// -- generic params, requirements, key args, extra args
|
|
// CHECK-SAME: i16 1, i16 0, i16 1, i16 0
|
|
// -- generic parameters
|
|
// CHECK-SAME: <i8 0x80>
|
|
// CHECK-SAME: }>
|
|
// CHECK: @"$s15generic_structs13SingleDynamicVMP" = internal constant <{ {{.*}} }> <{
|
|
// -- instantiation function
|
|
// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$s15generic_structs13SingleDynamicVMi"
|
|
// -- vwtable pointer
|
|
// CHECK-SAME: @"$s15generic_structs13SingleDynamicVWV"
|
|
|
|
// -- Nominal type descriptor for generic struct with protocol requirements
|
|
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
|
|
// CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
|
|
// CHECK: @"$s15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
|
|
// -- flags: struct, unique, generic
|
|
// CHECK-SAME: <i32 0x0000_00D1>
|
|
// -- name
|
|
// CHECK-SAME: [24 x i8]* [[DYNAMICWITHREQUIREMENTS_NAME]]
|
|
// -- field count
|
|
// CHECK-SAME: i32 2,
|
|
// -- field offset vector offset
|
|
// CHECK-SAME: i32 6,
|
|
// -- generic params, requirements, key args, extra args
|
|
// CHECK-SAME: i16 2, i16 2, i16 4, i16 0,
|
|
// -- generic parameters
|
|
// CHECK-SAME: <i8 0x80>, <i8 0x80>,
|
|
// -- generic requirement
|
|
// -- protocol requirement with key arg
|
|
// CHECK-SAME: i32 128
|
|
// -- param 0
|
|
// CHECK-SAME: i32 0
|
|
// -- protocol Req1
|
|
// CHECK-SAME: @"$s15generic_structs4Req1Mp"
|
|
|
|
// -- protocol requirement with key arg
|
|
// CHECK-SAME: i32 128
|
|
// -- param 1
|
|
// CHECK-SAME: i32 2
|
|
// -- protocol Req2
|
|
// CHECK-SAME: @"$s15generic_structs4Req2Mp"
|
|
// CHECK-SAME: }>
|
|
|
|
// CHECK: @"$s15generic_structs23DynamicWithRequirementsVMP" = internal constant <{ {{.*}} }> <{
|
|
|
|
// -- Fixed-layout struct metadata contains fixed field offsets
|
|
// CHECK: @"$s15generic_structs6IntishVMf" = internal constant <{ {{.*}} i32, [4 x i8] }> <{
|
|
// CHECK-SAME: i32 0
|
|
// CHECK-SAME: }>
|
|
// CHECK: @"$s15generic_structs7CharethVMf" = internal constant <{ {{.*}} i32, [4 x i8] }> <{
|
|
// CHECK-SAME: i32 0
|
|
// CHECK-SAME: }>
|
|
// CHECK: @"$s15generic_structs8StringlyVMf" = internal constant <{ {{.*}} i32, i32, i32, [4 x i8] }> <{
|
|
// CHECK-SAME: i32 0, i32 8, i32 16, [4 x i8] zeroinitializer
|
|
// CHECK-SAME: }>
|
|
|
|
struct FixedLayoutGeneric<T> {
|
|
var x: Byteful
|
|
var y: Byteful
|
|
var z: Intish
|
|
}
|
|
|
|
struct SingleDynamic<T> {
|
|
var x : T
|
|
}
|
|
|
|
protocol Req1 { associatedtype Assoc1 }
|
|
protocol Req2 {}
|
|
|
|
struct DynamicWithRequirements<T: Req1, U: Req2> {
|
|
var x : T
|
|
var y : U
|
|
}
|
|
|
|
struct Intish { var value : Builtin.Int64 }
|
|
struct Chareth { var value : Builtin.Int21 }
|
|
struct Byteful { var value : Builtin.Int8 }
|
|
struct Stringly {
|
|
var owner : Builtin.NativeObject
|
|
var base : Builtin.RawPointer
|
|
var size : Builtin.Int64
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i32 } @concrete_instances(i64 %0, i32 %1) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: %2 = trunc i32 %1 to i21
|
|
// CHECK: %3 = zext i21 %2 to i32
|
|
// CHECK: %4 = insertvalue { i64, i32 } undef, i64 %0, 0
|
|
// CHECK: %5 = insertvalue { i64, i32 } %4, i32 %3, 1
|
|
// CHECK: ret { i64, i32 } %5
|
|
// CHECK: }
|
|
sil @concrete_instances : $(SingleDynamic<Intish>, SingleDynamic<Chareth>) -> (Intish, Chareth) {
|
|
entry(%0 : $SingleDynamic<Intish>, %1 : $SingleDynamic<Chareth>):
|
|
%a = struct_extract %0 : $SingleDynamic<Intish>, #SingleDynamic.x
|
|
%b = struct_extract %1 : $SingleDynamic<Chareth>, #SingleDynamic.x
|
|
%c = tuple (%a : $Intish, %b : $Chareth)
|
|
return %c : $(Intish, Chareth)
|
|
}
|
|
|
|
struct ComplexDynamic<U, V> {
|
|
var a, a2 : Byteful
|
|
var b : U
|
|
var c : SingleDynamic<V>
|
|
var d : Chareth
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @explode_complex_dynamic
|
|
sil @explode_complex_dynamic : $<A, B> (@in ComplexDynamic<A, B>, @inout Byteful, @inout A, @inout B, @inout Chareth) -> () {
|
|
entry(%0 : $*ComplexDynamic<A, B>, %1 : $*Byteful, %2 : $*A, %3 : $*B, %4 : $*Chareth):
|
|
%a = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.a2
|
|
|
|
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i32*
|
|
// CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i32, i32* [[METADATA]], i64 10
|
|
// CHECK: [[FIELD_OFFSET:%.*]] = load i32, i32* [[FIELD_OFFSET_ADDR]], align 8
|
|
// CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
|
|
// CHECK: [[BYTE_OFFSET:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i32 [[FIELD_OFFSET]]
|
|
// CHECK: bitcast i8* [[BYTE_OFFSET]] to %swift.opaque*
|
|
%b = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.b
|
|
|
|
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i32*
|
|
// CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i32, i32* [[METADATA]], i64 11
|
|
// CHECK: [[FIELD_OFFSET:%.*]] = load i32, i32* [[FIELD_OFFSET_ADDR]], align 8
|
|
// CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
|
|
// CHECK: [[BYTE_OFFSET:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i32 [[FIELD_OFFSET]]
|
|
// CHECK: bitcast i8* [[BYTE_OFFSET]] to %T15generic_structs13SingleDynamicV
|
|
%5 = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.c
|
|
%c = struct_element_addr %5 : $*SingleDynamic<B>, #SingleDynamic.x
|
|
|
|
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i32*
|
|
// CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i32, i32* [[METADATA]], i64 12
|
|
// CHECK: [[FIELD_OFFSET:%.*]] = load i32, i32* [[FIELD_OFFSET_ADDR]], align 8
|
|
// CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
|
|
// CHECK: [[BYTE_OFFSET:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i32 [[FIELD_OFFSET]]
|
|
// CHECK: bitcast i8* [[BYTE_OFFSET]] to %T15generic_structs7CharethV
|
|
%d = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.d
|
|
copy_addr %a to %1 : $*Byteful
|
|
copy_addr %b to %2 : $*A
|
|
copy_addr %c to %3 : $*B
|
|
copy_addr %d to %4 : $*Chareth
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} internal %swift.type* @"$s15generic_structs13SingleDynamicVMi"(%swift.type_descriptor* %0, i8** %1, i8* %2)
|
|
// 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-NEXT: ret %swift.type* [[METADATA]]
|
|
// CHECK: }
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$s15generic_structs13SingleDynamicVMr"
|
|
// CHECK-SAME: (%swift.type* [[METADATA:%.*]], i8* %0, i8** %1) {{.*}} {
|
|
// Lay out fields.
|
|
// CHECK: [[T0:%.*]] = bitcast %swift.type* [[METADATA]] to i32*
|
|
// CHECK: [[T1:%.*]] = getelementptr inbounds i32, i32* [[T0]], i64 6
|
|
// CHECK: [[T2:%.*]] = getelementptr inbounds i8**, i8*** [[TYPES:%.*]], i32 0
|
|
// CHECK: call void @swift_initStructMetadata(%swift.type* [[METADATA]], i64 0, i64 1, i8*** [[TYPES]], i32* [[T1]])
|
|
// CHECK: ret %swift.metadata_response
|
|
// CHECK: }
|
|
|
|
// Check that we directly delegate buffer witnesses to a single dynamic field:
|
|
|
|
// initializeBufferWithCopyOfBuffer
|
|
// CHECK-LABEL: define internal %swift.opaque* @"$s15generic_structs13SingleDynamicVwCP"([24 x i8]* noalias %dest, [24 x i8]* noalias %src, %swift.type* %"SingleDynamic<T>") {{.*}} {
|
|
// CHECK: %T = load %swift.type*,
|
|
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8***
|
|
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 -1
|
|
// CHECK-NEXT: %T.valueWitnesses = load i8**, i8*** [[T1]]
|
|
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** %T.valueWitnesses,
|
|
// CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)*
|
|
// CHECK-NEXT: [[T0:%.*]] = call %swift.opaque* [[FN]]([24 x i8]* noalias %dest, [24 x i8]* noalias %src, %swift.type* %T)
|
|
// CHECK-NEXT: [[T1:%.*]] = bitcast %swift.opaque* [[T0]] to {{.*}}
|
|
// CHECK-NEXT: [[T2:%.*]] = bitcast {{.*}} [[T1]] to %swift.opaque*
|
|
// CHECK-NEXT: ret %swift.opaque* [[T2]]
|
|
|
|
|
|
protocol HasAssociatedType {
|
|
associatedtype Assoc
|
|
}
|
|
protocol ParentHasAssociatedType : HasAssociatedType {
|
|
associatedtype Assoc : HasAssociatedType
|
|
}
|
|
|
|
struct GenericLayoutWithAssocType<T: ParentHasAssociatedType> {
|
|
var x: T.Assoc
|
|
var y: T.Assoc.Assoc
|
|
}
|
|
// CHECK-LABEL: define internal %swift.type* @"$s15generic_structs26GenericLayoutWithAssocTypeVMi"(
|
|
// CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type**
|
|
// CHECK: %T = load %swift.type*, %swift.type** [[T0]], align 8
|
|
// CHECK: [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i32 1
|
|
// CHECK: [[T2:%.*]] = bitcast %swift.type** [[T1]] to i8***
|
|
// CHECK: %T.ParentHasAssociatedType = load i8**, i8*** [[T2]],
|
|
|
|
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata
|
|
|
|
// CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$s15generic_structs26GenericLayoutWithAssocTypeVMr"(
|
|
|
|
// CHECK: [[T0:%.*]] = call{{( tail)?}} swiftcc %swift.metadata_response @swift_checkMetadataState(i64 0, %swift.type* %T)
|
|
// CHECK: [[T_CHECKED:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
|
|
|
|
// CHECK: [[T0_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.ParentHasAssociatedType, i32 1
|
|
// CHECK: [[T0:%.*]] = load i8*, i8** [[T0_GEP]]
|
|
// CHECK: [[T1:%.*]] = bitcast i8* [[T0]] to i8**
|
|
// CHECK: [[T4:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
|
|
|
|
// CHECK: %T.Assoc = extractvalue %swift.metadata_response [[T4]], 0
|
|
// CHECK: %T.Assoc.HasAssociatedType = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %T.ParentHasAssociatedType, %swift.type* %T, %swift.type* %T.Assoc,
|
|
|
|
// CHECK: [[T2:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.Assoc.HasAssociatedType, %swift.type* %T.Assoc, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
|
|
// CHECK: %T.Assoc.Assoc = extractvalue %swift.metadata_response [[T2]], 0
|