Skip to content

Commit 9c8bdf2

Browse files
committed
Fill in the field-offset vector and payload size for fixed-layout value metadata.
This regression wasn't caught by normal testing because the emission pattern substantially changed anyway, breaking tests that were looking for the field-offset vector, and because normal execution testing doesn't actually use the field-offset vector and enum payload size fields. Reflection, which does use these fields, was skating by for common types because metadata is typically allocated out of freshly zeroed pages and most such types have only one field. Also, don't emit a completion function for value metadata with fixed layout. We really shouldn't have to emit field-offset vectors for fixed-layout types; the layout should just go in the type descriptor. But for now, this is what we have to do.
1 parent d62e516 commit 9c8bdf2

File tree

4 files changed

+128
-27
lines changed

4 files changed

+128
-27
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,6 +5037,10 @@ namespace {
50375037
public:
50385038
void noteStartOfTypeSpecificMembers() {}
50395039

5040+
SILType getLoweredType() {
5041+
return IGM.getLoweredType(Target->getDeclaredTypeInContext());
5042+
}
5043+
50405044
MetadataKind getMetadataKind() {
50415045
return MetadataKind::Struct;
50425046
}
@@ -5067,8 +5071,7 @@ namespace {
50675071
void addFieldOffset(VarDecl *var) {
50685072
assert(var->hasStorage() &&
50695073
"storing field offset for computed property?!");
5070-
SILType structType =
5071-
IGM.getLoweredType(Target->getDeclaredTypeInContext());
5074+
SILType structType = getLoweredType();
50725075

50735076
llvm::Constant *offset =
50745077
emitPhysicalStructMemberFixedOffset(IGM, structType, var);
@@ -5162,19 +5165,64 @@ namespace {
51625165
HasDependentVWT);
51635166
}
51645167

5165-
bool hasCompletionFunction() {
5166-
// TODO: recognize cases where this is not required
5168+
bool hasExtraDataPattern() {
5169+
auto &ti = IGM.getTypeInfo(getLoweredType());
5170+
if (!isa<FixedTypeInfo>(ti))
5171+
return false;
5172+
5173+
if (Target->getStoredProperties().empty())
5174+
return false;
5175+
51675176
return true;
51685177
}
5169-
5178+
5179+
/// Fill in a constant field offset vector if possible.
5180+
PartialPattern buildExtraDataPattern() {
5181+
ConstantInitBuilder builder(IGM);
5182+
auto init = builder.beginArray(IGM.SizeTy);
5183+
5184+
struct Scanner : StructMetadataScanner<Scanner> {
5185+
SILType Type;
5186+
ConstantArrayBuilder &B;
5187+
Scanner(IRGenModule &IGM, StructDecl *target, SILType type,
5188+
ConstantArrayBuilder &B)
5189+
: StructMetadataScanner(IGM, target), Type(type), B(B) {}
5190+
5191+
void addFieldOffset(VarDecl *field) {
5192+
auto offset = emitPhysicalStructMemberFixedOffset(IGM, Type, field);
5193+
if (offset) {
5194+
B.add(offset);
5195+
return;
5196+
}
5197+
assert(IGM.isKnownEmpty(Type.getFieldType(field, IGM.getSILModule()),
5198+
ResilienceExpansion::Maximal));
5199+
B.addInt(IGM.SizeTy, 0);
5200+
}
5201+
};
5202+
Scanner(IGM, Target, getLoweredType(), init).layout();
5203+
Size vectorSize = init.getNextOffsetFromGlobal();
5204+
5205+
auto global = init.finishAndCreateGlobal("", IGM.getPointerAlignment(),
5206+
/*constant*/ true);
5207+
5208+
auto &layout = IGM.getMetadataLayout(Target);
5209+
return { global,
5210+
layout.getFieldOffsetVectorOffset().getStatic()
5211+
- IGM.getOffsetOfStructTypeSpecificMetadataMembers(),
5212+
vectorSize };
5213+
}
5214+
5215+
bool hasCompletionFunction() {
5216+
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
5217+
}
5218+
51705219
void emitInitializeMetadata(IRGenFunction &IGF,
51715220
llvm::Value *metadata,
51725221
bool isVWTMutable) {
51735222
// Nominal types are always preserved through SIL lowering.
5174-
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5175-
IGM.getTypeInfoForUnlowered(structTy)
5176-
.initializeMetadata(IGF, metadata, isVWTMutable,
5177-
IGF.IGM.getLoweredType(structTy));
5223+
auto loweredTy = getLoweredType();
5224+
IGM.getTypeInfo(loweredTy)
5225+
.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy);
51785226
}
51795227
};
51805228
} // end anonymous namespace
@@ -5231,6 +5279,10 @@ namespace {
52315279
: super(IGM, theEnum), B(B) {
52325280
}
52335281

5282+
SILType getLoweredType() {
5283+
return IGM.getLoweredType(Target->getDeclaredTypeInContext());
5284+
}
5285+
52345286
public:
52355287
void noteStartOfTypeSpecificMembers() {}
52365288

@@ -5270,6 +5322,19 @@ namespace {
52705322
void addGenericWitnessTable(CanType type, ProtocolConformanceRef conf) {
52715323
B.addNullPointer(IGM.WitnessTablePtrTy);
52725324
}
5325+
5326+
Optional<Size> getConstantPayloadSize() {
5327+
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5328+
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
5329+
if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
5330+
return None;
5331+
}
5332+
5333+
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
5334+
"non-generic, non-resilient enums don't need payload size in metadata");
5335+
auto &strategy = getEnumImplStrategy(IGM, enumTy);
5336+
return Size(strategy.getPayloadSizeForMetadata());
5337+
}
52735338
};
52745339

52755340
class EnumMetadataBuilder
@@ -5281,19 +5346,17 @@ namespace {
52815346
ConstantStructBuilder &B)
52825347
: EnumMetadataBuilderBase(IGM, theEnum, B) {}
52835348

5349+
5350+
52845351
void addPayloadSize() {
5285-
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5286-
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
5287-
if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
5352+
auto payloadSize = getConstantPayloadSize();
5353+
if (!payloadSize) {
52885354
B.addInt(IGM.IntPtrTy, 0);
52895355
HasUnfilledPayloadSize = true;
52905356
return;
52915357
}
52925358

5293-
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
5294-
"non-generic, non-resilient enums don't need payload size in metadata");
5295-
auto &strategy = getEnumImplStrategy(IGM, enumTy);
5296-
B.addInt(IGM.IntPtrTy, strategy.getPayloadSizeForMetadata());
5359+
B.addInt(IGM.IntPtrTy, payloadSize->getValue());
52975360
}
52985361

52995362
bool canBeConstant() {
@@ -5325,9 +5388,24 @@ namespace {
53255388
- IGM.getOffsetOfEnumTypeSpecificMetadataMembers();
53265389
auto extraSizeV = IGM.getSize(extraSize);
53275390

5328-
return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
5329-
{descriptor, arguments, templatePointer,
5330-
extraSizeV});
5391+
auto metadata =
5392+
IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
5393+
{descriptor, arguments, templatePointer,
5394+
extraSizeV});
5395+
5396+
// Initialize the payload-size field if we have a constant value for it.
5397+
// This is so small that we just do it inline instead of bothering
5398+
// with a pattern.
5399+
if (layout.hasPayloadSizeOffset()) {
5400+
if (auto size = getConstantPayloadSize()) {
5401+
auto offset = layout.getPayloadSizeOffset();
5402+
auto slot = IGF.emitAddressAtOffset(metadata, offset, IGM.SizeTy,
5403+
IGM.getPointerAlignment());
5404+
IGF.Builder.CreateStore(IGM.getSize(*size), slot);
5405+
}
5406+
}
5407+
5408+
return metadata;
53315409
}
53325410

53335411
llvm::Constant *emitValueWitnessTable() {
@@ -5336,18 +5414,16 @@ namespace {
53365414
}
53375415

53385416
bool hasCompletionFunction() {
5339-
// TODO: recognize cases where this is not required
5340-
return true;
5417+
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
53415418
}
53425419

53435420
void emitInitializeMetadata(IRGenFunction &IGF,
53445421
llvm::Value *metadata,
53455422
bool isVWTMutable) {
53465423
// Nominal types are always preserved through SIL lowering.
5347-
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5348-
IGM.getTypeInfoForUnlowered(enumTy)
5349-
.initializeMetadata(IGF, metadata, isVWTMutable,
5350-
IGF.IGM.getLoweredType(enumTy));
5424+
auto enumTy = getLoweredType();
5425+
IGM.getTypeInfo(enumTy)
5426+
.initializeMetadata(IGF, metadata, isVWTMutable, enumTy);
53515427
}
53525428
};
53535429

stdlib/public/runtime/Metadata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ initializeValueMetadataFromPattern(ValueMetadata *metadata,
397397

398398
if (pattern->hasExtraDataPattern()) {
399399
void **metadataExtraData =
400-
reinterpret_cast<void**>(rawMetadata) + sizeof(ValueMetadata);
400+
reinterpret_cast<void**>(rawMetadata + sizeof(ValueMetadata));
401401
auto extraDataPattern = pattern->getExtraDataPattern();
402402

403403
// Zero memory up to the offset.

test/IRGen/enum_value_semantics.sil

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,10 @@ enum GenericFixedLayout<T> {
159159
// CHECK-SAME: @"$S20enum_value_semantics18GenericFixedLayoutOMP"
160160

161161
// CHECK-LABEL: @"$S20enum_value_semantics18GenericFixedLayoutOMP" = internal constant <{ {{.*}} }> <{
162+
// Instantiation function.
162163
// 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),
163-
// CHECK-SAME: @"$S20enum_value_semantics18GenericFixedLayoutOMr"
164+
// Completion function.
165+
// CHECK-SAME: i32 0,
164166
// Pattern flags. 0x400000 == (MetadataKind::Enum << 21).
165167
// CHECK-SAME: i32 4194304,
166168
// Value witness table.

test/IRGen/generic_structs.sil

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@
66

77
import Builtin
88

9+
// -- Generic structs with fixed layout should have no completion function
10+
// and emit the field offset vector as part of the pattern.
11+
// CHECK: [[PATTERN:@.*]] = internal constant [3 x i64] [i64 0, i64 1, i64 8]
12+
// CHECK-LABEL: @"$S15generic_structs18FixedLayoutGenericVMP" = internal constant <{ {{.*}} }> <{
13+
// -- instantiation function
14+
// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S15generic_structs18FixedLayoutGenericVMi"
15+
// -- completion function
16+
// CHECK-SAME: i32 0,
17+
// -- pattern flags
18+
// CHECK-SAME: i32 2097153,
19+
// -- vwtable pointer
20+
// CHECK-SAME: @"$S15generic_structs18FixedLayoutGenericVWV"
21+
// -- extra data pattern
22+
// CHECK-SAME: [3 x i64]* [[PATTERN]]
23+
// CHECK-SAME: i16 1,
24+
// CHECK-SAME: i16 3 }>
25+
926
// -- Generic structs with dynamic layout contain the vwtable pattern as part
1027
// of the metadata pattern, and no independent vwtable symbol
1128
// CHECK: @"$S15generic_structs13SingleDynamicVWV" = internal constant
@@ -88,6 +105,12 @@ import Builtin
88105
// CHECK-SAME: i64 0, i64 8, i64 16
89106
// CHECK-SAME: }>
90107

108+
struct FixedLayoutGeneric<T> {
109+
var x: Byteful
110+
var y: Byteful
111+
var z: Intish
112+
}
113+
91114
struct SingleDynamic<T> {
92115
var x : T
93116
}

0 commit comments

Comments
 (0)