Skip to content

Commit d5868e5

Browse files
committed
IRGen: ElementLayout now stores two TypeInfos
This allows us to perform fragile layout of resilient fields without completely disabling value type resilience.
1 parent c7853fe commit d5868e5

File tree

8 files changed

+52
-40
lines changed

8 files changed

+52
-40
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ namespace {
199199
Elements.push_back(Elt);
200200
if (!addField(Elements.back(), LayoutStrategy::Universal)) {
201201
// For empty tail allocated elements we still add 1 padding byte.
202-
assert(cast<FixedTypeInfo>(Elt.getType()).getFixedStride() == Size(1) &&
202+
assert(cast<FixedTypeInfo>(Elt.getTypeForLayout()).getFixedStride() == Size(1) &&
203203
"empty elements should have stride 1");
204204
StructFields.push_back(llvm::ArrayType::get(IGM.Int8Ty, 1));
205205
CurSize += Size(1);
@@ -335,7 +335,7 @@ namespace {
335335
assert(!abstractLayout ||
336336
abstractLayout->getFieldIndex(var) == fieldIndex);
337337

338-
Elements.push_back(ElementLayout::getIncomplete(eltType));
338+
Elements.push_back(ElementLayout::getIncomplete(eltType, eltType));
339339
AllStoredProperties.push_back(var);
340340
AllFieldAccesses.push_back(getFieldAccess(abstractLayout, fieldIndex));
341341
}
@@ -414,7 +414,7 @@ ClassTypeInfo::createLayoutWithTailElems(IRGenModule &IGM,
414414
// Add the tail elements.
415415
for (SILType TailTy : tailTypes) {
416416
const TypeInfo &tailTI = IGM.getTypeInfo(TailTy);
417-
builder.addTailElement(ElementLayout::getIncomplete(tailTI));
417+
builder.addTailElement(ElementLayout::getIncomplete(tailTI, tailTI));
418418
}
419419

420420
// Create a name for the new llvm type.

lib/IRGen/GenFunc.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
10931093
auto &fieldTy = layout->getElementTypes()[nextCapturedField];
10941094
auto fieldConvention = conventions[nextCapturedField];
10951095
Address fieldAddr = fieldLayout.project(subIGF, data, offsets);
1096-
auto &fieldTI = fieldLayout.getType();
1096+
auto &fieldTI = fieldLayout.getTypeForAccess();
10971097
auto fieldSchema = fieldTI.getSchema();
10981098

10991099
Explosion param;
@@ -1575,9 +1575,9 @@ void irgen::emitFunctionPartialApplication(
15751575
case ParameterConvention::Indirect_In:
15761576
case ParameterConvention::Indirect_In_Constant:
15771577
case ParameterConvention::Indirect_In_Guaranteed: {
1578-
auto addr = fieldLayout.getType().getAddressForPointer(args.claimNext());
1579-
fieldLayout.getType().initializeWithTake(IGF, fieldAddr, addr, fieldTy,
1580-
isOutlined);
1578+
auto addr = fieldLayout.getTypeForAccess().getAddressForPointer(args.claimNext());
1579+
fieldLayout.getTypeForAccess().initializeWithTake(IGF, fieldAddr, addr, fieldTy,
1580+
isOutlined);
15811581
break;
15821582
}
15831583
// Take direct value arguments and inout pointers by value.
@@ -1586,7 +1586,7 @@ void irgen::emitFunctionPartialApplication(
15861586
case ParameterConvention::Direct_Guaranteed:
15871587
case ParameterConvention::Indirect_Inout:
15881588
case ParameterConvention::Indirect_InoutAliasable:
1589-
cast<LoadableTypeInfo>(fieldLayout.getType())
1589+
cast<LoadableTypeInfo>(fieldLayout.getTypeForAccess())
15901590
.initialize(IGF, args, fieldAddr, isOutlined);
15911591
break;
15921592
}

lib/IRGen/GenHeap.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
9696
case ElementLayout::Kind::InitialNonFixedSize:
9797
// Factor the non-fixed-size field's alignment into the total alignment.
9898
totalAlign = IGF.Builder.CreateOr(totalAlign,
99-
elt.getType().getAlignmentMask(IGF, eltTy));
99+
elt.getTypeForLayout().getAlignmentMask(IGF, eltTy));
100100
LLVM_FALLTHROUGH;
101101
case ElementLayout::Kind::Empty:
102102
case ElementLayout::Kind::Fixed:
@@ -108,7 +108,7 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
108108
// Start calculating non-fixed offsets from the end of the first fixed
109109
// field.
110110
if (i == 0) {
111-
totalAlign = elt.getType().getAlignmentMask(IGF, eltTy);
111+
totalAlign = elt.getTypeForLayout().getAlignmentMask(IGF, eltTy);
112112
offset = totalAlign;
113113
Offsets.push_back(totalAlign);
114114
break;
@@ -120,7 +120,7 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
120120
// Start calculating offsets from the last fixed-offset field.
121121
if (!offset) {
122122
Size lastFixedOffset = layout.getElement(i-1).getByteOffset();
123-
if (auto *fixedType = dyn_cast<FixedTypeInfo>(&prevElt.getType())) {
123+
if (auto *fixedType = dyn_cast<FixedTypeInfo>(&prevElt.getTypeForLayout())) {
124124
// If the last fixed-offset field is also fixed-size, we can
125125
// statically compute the end of the fixed-offset fields.
126126
auto fixedEnd = lastFixedOffset + fixedType->getFixedSize();
@@ -133,12 +133,12 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
133133
= llvm::ConstantInt::get(IGF.IGM.SizeTy,
134134
lastFixedOffset.getValue());
135135
offset = IGF.Builder.CreateAdd(offset,
136-
prevElt.getType().getSize(IGF, prevType));
136+
prevElt.getTypeForLayout().getSize(IGF, prevType));
137137
}
138138
}
139139

140140
// Round up to alignment to get the offset.
141-
auto alignMask = elt.getType().getAlignmentMask(IGF, eltTy);
141+
auto alignMask = elt.getTypeForLayout().getAlignmentMask(IGF, eltTy);
142142
auto notAlignMask = IGF.Builder.CreateNot(alignMask);
143143
offset = IGF.Builder.CreateAdd(offset, alignMask);
144144
offset = IGF.Builder.CreateAnd(offset, notAlignMask);
@@ -147,7 +147,7 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
147147

148148
// Advance by the field's size to start the next field.
149149
offset = IGF.Builder.CreateAdd(offset,
150-
elt.getType().getSize(IGF, eltTy));
150+
elt.getTypeForLayout().getSize(IGF, eltTy));
151151
totalAlign = IGF.Builder.CreateOr(totalAlign, alignMask);
152152

153153
break;
@@ -237,7 +237,7 @@ static llvm::Function *createDtorFn(IRGenModule &IGM,
237237
if (field.isPOD())
238238
continue;
239239

240-
field.getType().destroy(
240+
field.getTypeForAccess().destroy(
241241
IGF, field.project(IGF, structAddr, offsets), fieldTy,
242242
true /*Called from metadata constructors: must be outlined*/);
243243
}

lib/IRGen/GenObjC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -934,8 +934,8 @@ void irgen::emitObjCPartialApplication(IRGenFunction &IGF,
934934
Address fieldAddr = fieldLayout.project(IGF, dataAddr, offsets);
935935
Explosion selfParams;
936936
selfParams.add(self);
937-
fieldLayout.getType().initializeFromParams(IGF, selfParams, fieldAddr,
938-
fieldType, false);
937+
fieldLayout.getTypeForAccess().initializeFromParams(IGF, selfParams, fieldAddr,
938+
fieldType, false);
939939

940940
// Create the forwarding stub.
941941
llvm::Function *forwarder = emitObjCPartialApplicationForwarder(IGF.IGM,

lib/IRGen/GenRecord.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ template <class FieldImpl> class RecordField {
4545

4646
protected:
4747
explicit RecordField(const TypeInfo &elementTI)
48-
: Layout(ElementLayout::getIncomplete(elementTI)) {}
48+
: Layout(ElementLayout::getIncomplete(elementTI, elementTI)) {}
4949

5050
explicit RecordField(const ElementLayout &layout,
5151
unsigned begin, unsigned end)
@@ -55,7 +55,7 @@ template <class FieldImpl> class RecordField {
5555
return static_cast<const FieldImpl*>(this);
5656
}
5757
public:
58-
const TypeInfo &getTypeInfo() const { return Layout.getType(); }
58+
const TypeInfo &getTypeInfo() const { return Layout.getTypeForLayout(); }
5959

6060
void completeFrom(const ElementLayout &layout) {
6161
Layout.completeFrom(layout);

lib/IRGen/GenStruct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ class ClangRecordLowering {
766766
NextExplosionIndex += explosionSize;
767767
unsigned explosionEnd = NextExplosionIndex;
768768

769-
ElementLayout layout = ElementLayout::getIncomplete(fieldType);
769+
ElementLayout layout = ElementLayout::getIncomplete(fieldType, fieldType);
770770
auto isEmpty = fieldType.isKnownEmpty(ResilienceExpansion::Maximal);
771771
if (isEmpty)
772772
layout.completeEmpty(fieldType.isPOD(ResilienceExpansion::Maximal),

lib/IRGen/StructLayout.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ StructLayout::StructLayout(IRGenModule &IGM, CanType astTy,
4949

5050
// Fill in the Elements array.
5151
for (auto type : types)
52-
Elements.push_back(ElementLayout::getIncomplete(*type));
52+
Elements.push_back(ElementLayout::getIncomplete(*type, *type));
5353

5454
assert(typeToFill == nullptr || typeToFill->isOpaque());
5555

@@ -153,7 +153,7 @@ Address ElementLayout::project(IRGenFunction &IGF, Address baseAddr,
153153
const llvm::Twine &suffix) const {
154154
switch (getKind()) {
155155
case Kind::Empty:
156-
return getType().getUndefAddress();
156+
return getTypeForAccess().getUndefAddress();
157157

158158
case Kind::Fixed:
159159
return IGF.Builder.CreateStructGEP(baseAddr,
@@ -165,13 +165,13 @@ Address ElementLayout::project(IRGenFunction &IGF, Address baseAddr,
165165
assert(offsets.hasValue());
166166
llvm::Value *offset =
167167
offsets.getValue()->getOffsetForIndex(IGF, getNonFixedElementIndex());
168-
return IGF.emitByteOffsetGEP(baseAddr.getAddress(), offset, getType(),
168+
return IGF.emitByteOffsetGEP(baseAddr.getAddress(), offset, getTypeForAccess(),
169169
baseAddr.getAddress()->getName() + suffix);
170170
}
171171

172172
case Kind::InitialNonFixedSize:
173173
return IGF.Builder.CreateBitCast(baseAddr,
174-
getType().getStorageType()->getPointerTo(),
174+
getTypeForAccess().getStorageType()->getPointerTo(),
175175
baseAddr.getAddress()->getName() + suffix);
176176
}
177177
llvm_unreachable("bad element layout kind");
@@ -207,7 +207,7 @@ bool StructLayoutBuilder::addFields(llvm::MutableArrayRef<ElementLayout> elts,
207207

208208
bool StructLayoutBuilder::addField(ElementLayout &elt,
209209
LayoutStrategy strategy) {
210-
auto &eltTI = elt.getType();
210+
auto &eltTI = elt.getTypeForLayout();
211211
IsKnownPOD &= eltTI.isPOD(ResilienceExpansion::Maximal);
212212
IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceExpansion::Maximal);
213213
IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal);
@@ -235,7 +235,7 @@ bool StructLayoutBuilder::addField(ElementLayout &elt,
235235
}
236236

237237
void StructLayoutBuilder::addFixedSizeElement(ElementLayout &elt) {
238-
auto &eltTI = cast<FixedTypeInfo>(elt.getType());
238+
auto &eltTI = cast<FixedTypeInfo>(elt.getTypeForLayout());
239239

240240
// Note that, even in the presence of elements with non-fixed
241241
// size, we continue to compute the minimum size and alignment
@@ -302,19 +302,19 @@ void StructLayoutBuilder::addNonFixedSizeElement(ElementLayout &elt) {
302302

303303
/// Add an empty element to the aggregate.
304304
void StructLayoutBuilder::addEmptyElement(ElementLayout &elt) {
305-
elt.completeEmpty(elt.getType().isPOD(ResilienceExpansion::Maximal),
305+
elt.completeEmpty(elt.getTypeForLayout().isPOD(ResilienceExpansion::Maximal),
306306
CurSize);
307307
}
308308

309309
/// Add an element at the fixed offset of the current end of the
310310
/// aggregate.
311311
void StructLayoutBuilder::addElementAtFixedOffset(ElementLayout &elt) {
312312
assert(isFixedLayout());
313-
auto &eltTI = cast<FixedTypeInfo>(elt.getType());
313+
auto &eltTI = cast<FixedTypeInfo>(elt.getTypeForLayout());
314314

315-
elt.completeFixed(elt.getType().isPOD(ResilienceExpansion::Maximal),
315+
elt.completeFixed(elt.getTypeForLayout().isPOD(ResilienceExpansion::Maximal),
316316
CurSize, StructFields.size());
317-
StructFields.push_back(elt.getType().getStorageType());
317+
StructFields.push_back(elt.getTypeForLayout().getStorageType());
318318

319319
// Carry over the spare bits from the element.
320320
CurSpareBits.append(eltTI.getSpareBits());
@@ -323,17 +323,17 @@ void StructLayoutBuilder::addElementAtFixedOffset(ElementLayout &elt) {
323323
/// Add an element at a non-fixed offset to the aggregate.
324324
void StructLayoutBuilder::addElementAtNonFixedOffset(ElementLayout &elt) {
325325
assert(!isFixedLayout());
326-
elt.completeNonFixed(elt.getType().isPOD(ResilienceExpansion::Maximal),
326+
elt.completeNonFixed(elt.getTypeForLayout().isPOD(ResilienceExpansion::Maximal),
327327
NextNonFixedOffsetIndex);
328328
CurSpareBits.clear();
329329
}
330330

331331
/// Add a non-fixed-size element to the aggregate at offset zero.
332332
void StructLayoutBuilder::addNonFixedSizeElementAtOffsetZero(ElementLayout &elt) {
333333
assert(isFixedLayout());
334-
assert(!isa<FixedTypeInfo>(elt.getType()));
334+
assert(!isa<FixedTypeInfo>(elt.getTypeForLayout()));
335335
assert(CurSize.isZero());
336-
elt.completeInitialNonFixedSize(elt.getType().isPOD(ResilienceExpansion::Maximal));
336+
elt.completeInitialNonFixedSize(elt.getTypeForLayout().isPOD(ResilienceExpansion::Maximal));
337337
CurSpareBits.clear();
338338
}
339339

lib/IRGen/StructLayout.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,16 @@ class ElementLayout {
100100
private:
101101
enum : unsigned { IncompleteKind = 4 };
102102

103-
/// The swift type information for this element.
104-
const TypeInfo *Type;
103+
/// The swift type information for this element's layout.
104+
const TypeInfo *TypeLayout;
105+
106+
/// The swift type information for this element's access.
107+
///
108+
/// Almost always the same as the layout type info, except for classes
109+
/// we have a workaround where we must perform layout as if the type
110+
/// was completely fragile, since the Objective-C runtime does not
111+
/// support classes with an unknown instance size.
112+
const TypeInfo *TypeAccess;
105113

106114
/// The offset in bytes from the start of the struct.
107115
unsigned ByteOffset;
@@ -117,16 +125,18 @@ class ElementLayout {
117125
/// The kind of layout performed for this element.
118126
unsigned TheKind : 3;
119127

120-
explicit ElementLayout(const TypeInfo &type)
121-
: Type(&type), TheKind(IncompleteKind) {}
128+
explicit ElementLayout(const TypeInfo &typeLayout,
129+
const TypeInfo &typeAccess)
130+
: TypeLayout(&typeLayout), TypeAccess(&typeAccess), TheKind(IncompleteKind) {}
122131

123132
bool isCompleted() const {
124133
return (TheKind != IncompleteKind);
125134
}
126135

127136
public:
128-
static ElementLayout getIncomplete(const TypeInfo &type) {
129-
return ElementLayout(type);
137+
static ElementLayout getIncomplete(const TypeInfo &typeLayout,
138+
const TypeInfo &typeAccess) {
139+
return ElementLayout(typeLayout, typeAccess);
130140
}
131141

132142
void completeFrom(const ElementLayout &other) {
@@ -171,7 +181,9 @@ class ElementLayout {
171181
Index = nonFixedElementIndex;
172182
}
173183

174-
const TypeInfo &getType() const { return *Type; }
184+
const TypeInfo &getTypeForLayout() const { return *TypeLayout; }
185+
186+
const TypeInfo &getTypeForAccess() const { return *TypeAccess; }
175187

176188
Kind getKind() const {
177189
assert(isCompleted());

0 commit comments

Comments
 (0)