Skip to content

Commit 00c1279

Browse files
committed
Reflection: Compute if types are bitwise takable
Bitwise takability is now part of the layout of a type, because non-bitwise takable types are never stored inline in an existential or resilient global's buffer, even if they would fit. The basic rule is that weak references, unknown-refcounted unowned references, and aggregates that contain them, are not bitwise takable, whereas everything else is bitwise takable. Also, since the bitwise takable for an unowned reference depends on the reference counting style, we have to record the superclass of a protocol, if any, to correctly determine the reference counting style of the protocol existential.
1 parent 50e5a66 commit 00c1279

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1307
-987
lines changed

include/swift/Reflection/Records.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,23 @@ class BuiltinTypeDescriptor {
402402

403403
public:
404404
uint32_t Size;
405-
uint32_t Alignment;
405+
406+
// - Least significant 16 bits are the alignment.
407+
// - Bit 16 is 'bitwise takable'.
408+
// - Remaining bits are reserved.
409+
uint32_t AlignmentAndFlags;
410+
406411
uint32_t Stride;
407412
uint32_t NumExtraInhabitants;
408413

414+
bool isBitwiseTakable() const {
415+
return (AlignmentAndFlags >> 16) & 1;
416+
}
417+
418+
uint32_t getAlignment() const {
419+
return AlignmentAndFlags & 0xffff;
420+
}
421+
409422
bool hasMangledTypeName() const {
410423
return TypeName;
411424
}

include/swift/Reflection/ReflectionContext.h

+8-4
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,17 @@ class ReflectionContext
541541
return nullptr;
542542

543543
// Initialize the builder.
544-
Builder.addField(*OffsetToFirstCapture, sizeof(StoredPointer),
545-
/*numExtraInhabitants=*/0);
544+
Builder.addField(*OffsetToFirstCapture,
545+
/*alignment=*/sizeof(StoredPointer),
546+
/*numExtraInhabitants=*/0,
547+
/*bitwiseTakable=*/true);
546548

547549
// Skip the closure's necessary bindings struct, if it's present.
548550
auto SizeOfNecessaryBindings = Info.NumBindings * sizeof(StoredPointer);
549-
Builder.addField(SizeOfNecessaryBindings, sizeof(StoredPointer),
550-
/*numExtraInhabitants=*/0);
551+
Builder.addField(/*size=*/SizeOfNecessaryBindings,
552+
/*alignment=*/sizeof(StoredPointer),
553+
/*numExtraInhabitants=*/0,
554+
/*bitwiseTakable=*/true);
551555

552556
// FIXME: should be unordered_set but I'm too lazy to write a hash
553557
// functor

include/swift/Reflection/TypeLowering.h

+15-7
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,16 @@ enum class TypeInfoKind : unsigned {
110110
class TypeInfo {
111111
TypeInfoKind Kind;
112112
unsigned Size, Alignment, Stride, NumExtraInhabitants;
113+
bool BitwiseTakable;
113114

114115
public:
115116
TypeInfo(TypeInfoKind Kind,
116117
unsigned Size, unsigned Alignment,
117-
unsigned Stride, unsigned NumExtraInhabitants)
118+
unsigned Stride, unsigned NumExtraInhabitants,
119+
bool BitwiseTakable)
118120
: Kind(Kind), Size(Size), Alignment(Alignment), Stride(Stride),
119-
NumExtraInhabitants(NumExtraInhabitants) {
121+
NumExtraInhabitants(NumExtraInhabitants),
122+
BitwiseTakable(BitwiseTakable) {
120123
assert(Alignment > 0);
121124
}
122125

@@ -126,6 +129,7 @@ class TypeInfo {
126129
unsigned getAlignment() const { return Alignment; }
127130
unsigned getStride() const { return Stride; }
128131
unsigned getNumExtraInhabitants() const { return NumExtraInhabitants; }
132+
bool isBitwiseTakable() const { return BitwiseTakable; }
129133

130134
void dump() const;
131135
void dump(std::ostream &OS, unsigned Indent = 0) const;
@@ -162,9 +166,10 @@ class RecordTypeInfo : public TypeInfo {
162166
public:
163167
RecordTypeInfo(unsigned Size, unsigned Alignment,
164168
unsigned Stride, unsigned NumExtraInhabitants,
169+
bool BitwiseTakable,
165170
RecordKind SubKind, const std::vector<FieldInfo> &Fields)
166171
: TypeInfo(TypeInfoKind::Record, Size, Alignment, Stride,
167-
NumExtraInhabitants),
172+
NumExtraInhabitants, BitwiseTakable),
168173
SubKind(SubKind), Fields(Fields) {}
169174

170175
RecordKind getRecordKind() const { return SubKind; }
@@ -185,9 +190,10 @@ class ReferenceTypeInfo : public TypeInfo {
185190
public:
186191
ReferenceTypeInfo(unsigned Size, unsigned Alignment,
187192
unsigned Stride, unsigned NumExtraInhabitants,
188-
ReferenceKind SubKind, ReferenceCounting Refcounting)
193+
bool BitwiseTakable, ReferenceKind SubKind,
194+
ReferenceCounting Refcounting)
189195
: TypeInfo(TypeInfoKind::Reference, Size, Alignment, Stride,
190-
NumExtraInhabitants),
196+
NumExtraInhabitants, BitwiseTakable),
191197
SubKind(SubKind), Refcounting(Refcounting) {}
192198

193199
ReferenceKind getReferenceKind() const {
@@ -286,6 +292,7 @@ class TypeConverter {
286292
class RecordTypeInfoBuilder {
287293
TypeConverter &TC;
288294
unsigned Size, Alignment, NumExtraInhabitants;
295+
bool BitwiseTakable;
289296
RecordKind Kind;
290297
std::vector<FieldInfo> Fields;
291298
bool Empty;
@@ -294,14 +301,15 @@ class RecordTypeInfoBuilder {
294301
public:
295302
RecordTypeInfoBuilder(TypeConverter &TC, RecordKind Kind)
296303
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
297-
Kind(Kind), Empty(true), Invalid(false) {}
304+
BitwiseTakable(true), Kind(Kind), Empty(true), Invalid(false) {}
298305

299306
bool isInvalid() const {
300307
return Invalid;
301308
}
302309

303310
unsigned addField(unsigned fieldSize, unsigned fieldAlignment,
304-
unsigned numExtraInhabitants);
311+
unsigned numExtraInhabitants,
312+
bool bitwiseTakable);
305313

306314
// Add a field of a record type, such as a struct.
307315
void addField(const std::string &Name, const TypeRef *TR);

lib/IRGen/GenReflection.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,11 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
426426
}
427427

428428
void layoutProtocol() {
429-
auto protocolDecl = cast<ProtocolDecl>(NTD);
429+
auto PD = cast<ProtocolDecl>(NTD);
430430
FieldDescriptorKind Kind;
431-
if (protocolDecl->isObjC())
431+
if (PD->isObjC())
432432
Kind = FieldDescriptorKind::ObjCProtocol;
433-
else if (protocolDecl->requiresClass())
433+
else if (PD->requiresClass())
434434
Kind = FieldDescriptorKind::ClassProtocol;
435435
else
436436
Kind = FieldDescriptorKind::Protocol;
@@ -446,8 +446,11 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
446446
addNominalRef(NTD);
447447

448448
auto *CD = dyn_cast<ClassDecl>(NTD);
449+
auto *PD = dyn_cast<ProtocolDecl>(NTD);
449450
if (CD && CD->getSuperclass()) {
450451
addTypeRef(CD->getSuperclass()->getCanonicalType());
452+
} else if (PD && PD->getDeclaredType()->getSuperclass()) {
453+
addTypeRef(PD->getDeclaredType()->getSuperclass()->getCanonicalType());
451454
} else {
452455
B.addInt32(0);
453456
}
@@ -515,7 +518,13 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
515518
addTypeRef(type);
516519

517520
B.addInt32(ti->getFixedSize().getValue());
518-
B.addInt32(ti->getFixedAlignment().getValue());
521+
522+
auto alignment = ti->getFixedAlignment().getValue();
523+
unsigned bitwiseTakable =
524+
(ti->isBitwiseTakable(ResilienceExpansion::Minimal) == IsBitwiseTakable
525+
? 1 : 0);
526+
B.addInt32(alignment | (bitwiseTakable << 16));
527+
519528
B.addInt32(ti->getFixedStride().getValue());
520529
B.addInt32(ti->getFixedExtraInhabitantCount(IGM));
521530
}

stdlib/public/Reflection/TypeLowering.cpp

+80-13
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class PrintTypeInfo {
7777
printField("alignment", TI.getAlignment());
7878
printField("stride", TI.getStride());
7979
printField("num_extra_inhabitants", TI.getNumExtraInhabitants());
80+
printField("bitwise_takable", TI.isBitwiseTakable());
8081
}
8182

8283
void printFields(const RecordTypeInfo &TI) {
@@ -190,8 +191,12 @@ void TypeInfo::dump(std::ostream &OS, unsigned Indent) const {
190191
}
191192

192193
BuiltinTypeInfo::BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor)
193-
: TypeInfo(TypeInfoKind::Builtin, descriptor->Size, descriptor->Alignment,
194-
descriptor->Stride, descriptor->NumExtraInhabitants),
194+
: TypeInfo(TypeInfoKind::Builtin,
195+
descriptor->Size,
196+
descriptor->getAlignment(),
197+
descriptor->Stride,
198+
descriptor->NumExtraInhabitants,
199+
descriptor->isBitwiseTakable()),
195200
Name(descriptor->getMangledTypeName(0)) {}
196201

197202
/// Utility class for building values that contain witness tables.
@@ -263,6 +268,29 @@ class ExistentialTypeInfoBuilder {
263268
case FieldDescriptorKind::ClassProtocol:
264269
Representation = ExistentialTypeRepresentation::Class;
265270
WitnessTableCount++;
271+
272+
if (auto *Superclass = TC.getBuilder().lookupSuperclass(P)) {
273+
auto *SuperclassTI = TC.getTypeInfo(Superclass);
274+
if (SuperclassTI == nullptr) {
275+
DEBUG_LOG(std::cerr << "No TypeInfo for superclass: ";
276+
Superclass->dump());
277+
Invalid = true;
278+
continue;
279+
}
280+
281+
if (!isa<ReferenceTypeInfo>(SuperclassTI)) {
282+
DEBUG_LOG(std::cerr << "Superclass not a reference type: ";
283+
SuperclassTI->dump());
284+
Invalid = true;
285+
continue;
286+
}
287+
288+
if (cast<ReferenceTypeInfo>(SuperclassTI)->getReferenceCounting()
289+
== ReferenceCounting::Native) {
290+
Refcounting = ReferenceCounting::Native;
291+
}
292+
}
293+
266294
continue;
267295
case FieldDescriptorKind::Protocol:
268296
WitnessTableCount++;
@@ -397,9 +425,12 @@ class ExistentialTypeInfoBuilder {
397425

398426
// Non-class existentials consist of a three-word buffer,
399427
// value metadata, and finally zero or more witness tables.
428+
// The buffer is always bitwise takable, since non-bitwise
429+
// takable payloads are stored out of line.
400430
builder.addField(TI->getSize() * 3,
401431
TI->getAlignment(),
402-
/*numExtraInhabitants=*/0);
432+
/*numExtraInhabitants=*/0,
433+
/*bitwiseTakable=*/true);
403434
builder.addField("metadata", TC.getAnyMetatypeTypeRef());
404435
break;
405436
}
@@ -441,7 +472,8 @@ class ExistentialTypeInfoBuilder {
441472

442473
unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize,
443474
unsigned fieldAlignment,
444-
unsigned numExtraInhabitants) {
475+
unsigned numExtraInhabitants,
476+
bool bitwiseTakable) {
445477
assert(fieldAlignment > 0);
446478

447479
// Align the current size appropriately
@@ -456,6 +488,9 @@ unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize,
456488
// Update the aggregate alignment
457489
Alignment = std::max(Alignment, fieldAlignment);
458490

491+
// The aggregate is bitwise takable if all elements are.
492+
BitwiseTakable &= bitwiseTakable;
493+
459494
switch (Kind) {
460495
// The extra inhabitants of a struct or tuple are the same as the extra
461496
// inhabitants of the field that has the most.
@@ -500,7 +535,8 @@ void RecordTypeInfoBuilder::addField(const std::string &Name,
500535

501536
unsigned offset = addField(TI->getSize(),
502537
TI->getAlignment(),
503-
TI->getNumExtraInhabitants());
538+
TI->getNumExtraInhabitants(),
539+
TI->isBitwiseTakable());
504540
Fields.push_back({Name, offset, TR, *TI});
505541
}
506542

@@ -515,7 +551,8 @@ const RecordTypeInfo *RecordTypeInfoBuilder::build() {
515551

516552
return TC.makeTypeInfo<RecordTypeInfo>(
517553
Size, Alignment, Stride,
518-
NumExtraInhabitants, Kind, Fields);
554+
NumExtraInhabitants, BitwiseTakable,
555+
Kind, Fields);
519556
}
520557

521558
const ReferenceTypeInfo *
@@ -548,13 +585,28 @@ TypeConverter::getReferenceTypeInfo(ReferenceKind Kind,
548585
}
549586

550587
unsigned numExtraInhabitants = BuiltinTI->NumExtraInhabitants;
551-
if (Kind == ReferenceKind::Weak)
588+
bool bitwiseTakable = true;
589+
590+
switch (Kind) {
591+
case ReferenceKind::Strong:
592+
break;
593+
case ReferenceKind::Weak:
552594
numExtraInhabitants = 0;
595+
bitwiseTakable = false;
596+
break;
597+
case ReferenceKind::Unowned:
598+
if (Refcounting == ReferenceCounting::Unknown)
599+
bitwiseTakable = false;
600+
break;
601+
case ReferenceKind::Unmanaged:
602+
break;
603+
}
553604

554605
auto *TI = makeTypeInfo<ReferenceTypeInfo>(BuiltinTI->Size,
555-
BuiltinTI->Alignment,
606+
BuiltinTI->getAlignment(),
556607
BuiltinTI->Stride,
557608
numExtraInhabitants,
609+
bitwiseTakable,
558610
Kind, Refcounting);
559611
ReferenceCache[key] = TI;
560612
return TI;
@@ -619,7 +671,12 @@ const TypeInfo *TypeConverter::getEmptyTypeInfo() {
619671
if (EmptyTI != nullptr)
620672
return EmptyTI;
621673

622-
EmptyTI = makeTypeInfo<TypeInfo>(TypeInfoKind::Builtin, 0, 1, 1, 0);
674+
EmptyTI = makeTypeInfo<TypeInfo>(TypeInfoKind::Builtin,
675+
/*Size=*/0,
676+
/*Alignment=*/1,
677+
/*Stride=*/1,
678+
/*ExtraInhabitants=*/0,
679+
/*BitwiseTakable=*/true);
623680
return EmptyTI;
624681
}
625682

@@ -919,6 +976,7 @@ static unsigned getNumTagBytes(size_t size, unsigned emptyCases,
919976
class EnumTypeInfoBuilder {
920977
TypeConverter &TC;
921978
unsigned Size, Alignment, NumExtraInhabitants;
979+
bool BitwiseTakable;
922980
RecordKind Kind;
923981
std::vector<FieldInfo> Cases;
924982
bool Invalid;
@@ -942,14 +1000,15 @@ class EnumTypeInfoBuilder {
9421000

9431001
Size = std::max(Size, TI->getSize());
9441002
Alignment = std::max(Alignment, TI->getAlignment());
1003+
BitwiseTakable &= TI->isBitwiseTakable();
9451004

9461005
Cases.push_back({Name, /*offset=*/0, TR, *TI});
9471006
}
9481007

9491008
public:
9501009
EnumTypeInfoBuilder(TypeConverter &TC)
9511010
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
952-
Kind(RecordKind::Invalid), Invalid(false) {}
1011+
BitwiseTakable(true), Kind(RecordKind::Invalid), Invalid(false) {}
9531012

9541013
const TypeInfo *
9551014
build(const TypeRef *TR,
@@ -1028,8 +1087,9 @@ class EnumTypeInfoBuilder {
10281087
auto *FixedDescriptor = TC.getBuilder().getBuiltinTypeInfo(TR);
10291088
if (FixedDescriptor) {
10301089
Size = FixedDescriptor->Size;
1031-
Alignment = FixedDescriptor->Alignment;
1090+
Alignment = FixedDescriptor->getAlignment();
10321091
NumExtraInhabitants = FixedDescriptor->NumExtraInhabitants;
1092+
BitwiseTakable = FixedDescriptor->isBitwiseTakable();
10331093
} else {
10341094
// Dynamic multi-payload enums do not have extra inhabitants
10351095
NumExtraInhabitants = 0;
@@ -1052,7 +1112,8 @@ class EnumTypeInfoBuilder {
10521112

10531113
return TC.makeTypeInfo<RecordTypeInfo>(
10541114
Size, Alignment, Stride,
1055-
NumExtraInhabitants, Kind, Cases);
1115+
NumExtraInhabitants, BitwiseTakable,
1116+
Kind, Cases);
10561117
}
10571118
};
10581119

@@ -1263,10 +1324,12 @@ class LowerType
12631324
// Destructure the existential and replace the "object"
12641325
// field with the right reference kind.
12651326
} else if (SubKind == RecordKind::ClassExistential) {
1327+
bool BitwiseTakable = RecordTI->isBitwiseTakable();
12661328
std::vector<FieldInfo> Fields;
12671329
for (auto &Field : RecordTI->getFields()) {
12681330
if (Field.Name == "object") {
12691331
auto *FieldTI = rebuildStorageTypeInfo(&Field.TI, Kind);
1332+
BitwiseTakable &= FieldTI->isBitwiseTakable();
12701333
Fields.push_back({Field.Name, Field.Offset, Field.TR, *FieldTI});
12711334
continue;
12721335
}
@@ -1278,6 +1341,7 @@ class LowerType
12781341
RecordTI->getAlignment(),
12791342
RecordTI->getStride(),
12801343
RecordTI->getNumExtraInhabitants(),
1344+
BitwiseTakable,
12811345
SubKind, Fields);
12821346
}
12831347
}
@@ -1354,7 +1418,10 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR,
13541418

13551419
// Start layout from the given instance start offset. This should
13561420
// be the superclass instance size.
1357-
builder.addField(start, 1, /*numExtraInhabitants=*/0);
1421+
builder.addField(/*size=*/start,
1422+
/*alignment=*/1,
1423+
/*numExtraInhabitants=*/0,
1424+
/*bitwiseTakable=*/true);
13581425

13591426
for (auto Field : Fields)
13601427
builder.addField(Field.Name, Field.TR);

0 commit comments

Comments
 (0)