Skip to content

Commit f6bed48

Browse files
committed
IRGen: Fix emission of builtin reflection descriptors in multi-threaded mode
Ensure they get emitted at the end of the job by the dispatcher, and also use a proper mangling and shared linkage for these symbols so that if multiple threads emit the same descriptor it gets merged. The new tests attempt to exercise these scenarios. Fixes <rdar://problem/27906876>.
1 parent a851201 commit f6bed48

15 files changed

+255
-74
lines changed

docs/ABI.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ Globals
739739
global ::= 'Mm' type // class metaclass
740740
global ::= 'Mn' nominal-type // nominal type descriptor
741741
global ::= 'Mp' protocol // protocol descriptor
742+
global ::= 'MR' remote-reflection-record // metadata for remote mirrors
742743
global ::= 'PA' .* // partial application forwarder
743744
global ::= 'PAo' .* // ObjC partial application forwarder
744745
global ::= 'w' value-witness-kind type // value witness
@@ -820,6 +821,10 @@ Globals
820821
addressor-kind ::= 'o' // owning addressor (native owner)
821822
addressor-kind ::= 'p' // pinning addressor (native owner)
822823

824+
remote-reflection-record ::= 'f' type // field descriptor
825+
remote-reflection-record ::= 'a' protocol-conformance // associated type descriptor
826+
remote-reflection-record ::= 'b' type // builtin type descriptor
827+
823828
An ``entity`` starts with a ``nominal-type-kind`` (``[COPV]``), a
824829
substitution (``[Ss]``) of a nominal type, or an ``entity-kind``
825830
(``[FIiv]``).

lib/IRGen/GenDecl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,19 @@ SILLinkage LinkEntity::getLinkage(IRGenModule &IGM,
11351135

11361136
case Kind::SILGlobalVariable:
11371137
return getSILGlobalVariable()->getLinkage();
1138+
1139+
case Kind::ReflectionBuiltinDescriptor:
1140+
case Kind::ReflectionFieldDescriptor:
1141+
// Reflection descriptors for imported types have shared linkage,
1142+
// since we may emit them in other TUs in the same module.
1143+
if (getTypeLinkage(getType()) == FormalLinkage::PublicNonUnique)
1144+
return SILLinkage::Shared;
1145+
return SILLinkage::Private;
1146+
case Kind::ReflectionAssociatedTypeDescriptor:
1147+
if (getConformanceLinkage(IGM, getProtocolConformance())
1148+
== SILLinkage::Shared)
1149+
return SILLinkage::Shared;
1150+
return SILLinkage::Private;
11381151
}
11391152
llvm_unreachable("bad link entity kind");
11401153
}
@@ -1198,6 +1211,9 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
11981211
case Kind::GenericProtocolWitnessTableInstantiationFunction:
11991212
case Kind::SILFunction:
12001213
case Kind::SILGlobalVariable:
1214+
case Kind::ReflectionBuiltinDescriptor:
1215+
case Kind::ReflectionFieldDescriptor:
1216+
case Kind::ReflectionAssociatedTypeDescriptor:
12011217
llvm_unreachable("Relative reference to unsupported link entity");
12021218
}
12031219
llvm_unreachable("bad link entity kind");

lib/IRGen/GenReflection.cpp

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "GenHeap.h"
3030
#include "GenProto.h"
3131
#include "IRGenModule.h"
32+
#include "Linking.h"
3233
#include "LoadableTypeInfo.h"
3334

3435
using namespace swift;
@@ -276,13 +277,13 @@ class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {
276277
if (!init)
277278
return nullptr;
278279

279-
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
280-
/*isConstant*/ true,
281-
llvm::GlobalValue::PrivateLinkage,
282-
init,
283-
"\x01l__swift3_assocty_metadata");
280+
auto entity = LinkEntity::forReflectionAssociatedTypeDescriptor(Conformance);
281+
auto info = LinkInfo::get(IGM, entity, ForDefinition);
282+
283+
auto var = info.createVariable(IGM, init->getType(), Alignment(4));
284+
var->setConstant(true);
285+
var->setInitializer(init);
284286
var->setSection(IGM.getAssociatedTypeMetadataSectionName());
285-
var->setAlignment(4);
286287

287288
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
288289
tempBase->replaceAllUsesWith(replacer);
@@ -444,13 +445,14 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
444445
if (!init)
445446
return nullptr;
446447

447-
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
448-
/*isConstant*/ true,
449-
llvm::GlobalValue::PrivateLinkage,
450-
init,
451-
"\x01l__swift3_reflection_metadata");
448+
auto entity = LinkEntity::forReflectionFieldDescriptor(
449+
NTD->getDeclaredType()->getCanonicalType());
450+
auto info = LinkInfo::get(IGM, entity, ForDefinition);
451+
452+
auto var = info.createVariable(IGM, init->getType(), Alignment(4));
453+
var->setConstant(true);
454+
var->setInitializer(init);
452455
var->setSection(IGM.getFieldTypeMetadataSectionName());
453-
var->setAlignment(4);
454456

455457
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
456458
tempBase->replaceAllUsesWith(replacer);
@@ -460,61 +462,57 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
460462
};
461463

462464
class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
463-
void addFixedType(Module *module, CanType type,
464-
const FixedTypeInfo &ti) {
465-
addTypeRef(module, type);
465+
ModuleDecl *module;
466+
CanType type;
467+
const FixedTypeInfo *ti;
466468

467-
addConstantInt32(ti.getFixedSize().getValue());
468-
addConstantInt32(ti.getFixedAlignment().getValue());
469-
addConstantInt32(ti.getFixedStride().getValue());
470-
addConstantInt32(ti.getFixedExtraInhabitantCount(IGM));
471-
}
472-
473-
void addBuiltinType(CanType builtinType) {
474-
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(builtinType));
475-
addFixedType(builtinType->getASTContext().TheBuiltinModule, builtinType, ti);
476-
}
477-
478-
void addOpaqueType(const NominalTypeDecl *nominalDecl) {
479-
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(
469+
public:
470+
FixedTypeMetadataBuilder(IRGenModule &IGM,
471+
CanType builtinType)
472+
: ReflectionMetadataBuilder(IGM) {
473+
module = builtinType->getASTContext().TheBuiltinModule;
474+
type = builtinType;
475+
ti = &cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(builtinType));
476+
}
477+
478+
FixedTypeMetadataBuilder(IRGenModule &IGM,
479+
const NominalTypeDecl *nominalDecl)
480+
: ReflectionMetadataBuilder(IGM) {
481+
module = nominalDecl->getParentModule();
482+
type = nominalDecl->getDeclaredType()->getCanonicalType();
483+
ti = &cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(
480484
nominalDecl->getDeclaredTypeInContext()->getCanonicalType()));
481-
482-
addFixedType(nominalDecl->getParentModule(),
483-
nominalDecl->getDeclaredType()->getCanonicalType(), ti);
484485
}
485486

486487
void layout() {
487-
for (auto builtinType : IGM.BuiltinTypes)
488-
addBuiltinType(builtinType);
488+
addTypeRef(module, type);
489489

490-
for (auto nominalDecl : IGM.OpaqueTypes)
491-
addOpaqueType(nominalDecl);
490+
addConstantInt32(ti->getFixedSize().getValue());
491+
addConstantInt32(ti->getFixedAlignment().getValue());
492+
addConstantInt32(ti->getFixedStride().getValue());
493+
addConstantInt32(ti->getFixedExtraInhabitantCount(IGM));
492494
}
493495

494-
public:
495-
FixedTypeMetadataBuilder(IRGenModule &IGM)
496-
: ReflectionMetadataBuilder(IGM) {}
497-
498496
llvm::GlobalVariable *emit() {
499-
500497
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
501498
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
502499
llvm::GlobalValue::PrivateLinkage));
503500
setRelativeAddressBase(tempBase.get());
504501

505502
layout();
503+
506504
auto init = getInit();
507505

508506
if (!init)
509507
return nullptr;
510508

511-
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
512-
/*isConstant*/ true,
513-
llvm::GlobalValue::PrivateLinkage,
514-
init,
515-
"\x01l__swift3_builtin_metadata");
509+
auto entity = LinkEntity::forReflectionBuiltinDescriptor(type);
510+
auto info = LinkInfo::get(IGM, entity, ForDefinition);
511+
512+
auto var = info.createVariable(IGM, init->getType(), Alignment(4));
513+
var->setConstant(true);
514+
var->setInitializer(init);
516515
var->setSection(IGM.getBuiltinTypeMetadataSectionName());
517-
var->setAlignment(4);
518516

519517
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
520518
tempBase->replaceAllUsesWith(replacer);
@@ -523,6 +521,20 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
523521
}
524522
};
525523

524+
void IRGenModule::emitBuiltinTypeMetadataRecord(CanType builtinType) {
525+
FixedTypeMetadataBuilder builder(*this, builtinType);
526+
auto var = builder.emit();
527+
if (var)
528+
addUsedGlobal(var);
529+
}
530+
531+
void IRGenModule::emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl) {
532+
FixedTypeMetadataBuilder builder(*this, nominalDecl);
533+
auto var = builder.emit();
534+
if (var)
535+
addUsedGlobal(var);
536+
}
537+
526538
/// Builds a constant LLVM struct describing the layout of a fixed-size
527539
/// SIL @box. These look like closure contexts, but without any necessary
528540
/// bindings or metadata sources, and only a single captured value.
@@ -915,10 +927,17 @@ void IRGenModule::emitBuiltinReflectionMetadata() {
915927
for (auto PD : ImportedProtocols)
916928
emitFieldMetadataRecord(PD);
917929

918-
FixedTypeMetadataBuilder builder(*this);
919-
auto var = builder.emit();
920-
if (var)
921-
addUsedGlobal(var);
930+
for (auto builtinType : BuiltinTypes)
931+
emitBuiltinTypeMetadataRecord(builtinType);
932+
933+
for (auto nominalDecl : OpaqueTypes)
934+
emitOpaqueTypeMetadataRecord(nominalDecl);
935+
}
936+
937+
void IRGenerator::emitBuiltinReflectionMetadata() {
938+
for (auto &m : *this) {
939+
m.second->emitBuiltinReflectionMetadata();
940+
}
922941
}
923942

924943
void IRGenModule::emitFieldMetadataRecord(const NominalTypeDecl *Decl) {
@@ -941,3 +960,9 @@ void IRGenModule::emitReflectionMetadataVersion() {
941960
Version->setVisibility(llvm::GlobalValue::HiddenVisibility);
942961
addUsedGlobal(Version);
943962
}
963+
964+
void IRGenerator::emitReflectionMetadataVersion() {
965+
for (auto &m : *this) {
966+
m.second->emitReflectionMetadataVersion();
967+
}
968+
}

lib/IRGen/IRGen.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,11 @@ static void performParallelIRGeneration(IRGenOptions &Opts,
778778

779779
irgen.emitProtocolConformances();
780780

781+
irgen.emitReflectionMetadataVersion();
782+
783+
// Emit reflection metadata for builtin and imported types.
784+
irgen.emitBuiltinReflectionMetadata();
785+
781786
// Okay, emit any definitions that we suddenly need.
782787
irgen.emitLazyDefinitions();
783788

lib/IRGen/IRGenModule.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ class IRGenerator {
275275
/// Emit type metadata records for types without explicit protocol conformance.
276276
void emitTypeMetadataRecords();
277277

278+
/// Emit reflection metadata records for builtin and imported types referenced
279+
/// from this module.
280+
void emitBuiltinReflectionMetadata();
281+
282+
/// Emit a symbol identifying the reflection metadata version.
283+
void emitReflectionMetadataVersion();
284+
278285
/// Emit everything which is reachable from already emitted IR.
279286
void emitLazyDefinitions();
280287

@@ -747,8 +754,22 @@ class IRGenModule {
747754

748755
void emitAssociatedTypeMetadataRecord(const ProtocolConformance *Conformance);
749756
void emitFieldMetadataRecord(const NominalTypeDecl *Decl);
757+
758+
/// Emit a reflection metadata record for a builtin type referenced
759+
/// from this module.
760+
void emitBuiltinTypeMetadataRecord(CanType builtinType);
761+
762+
/// Emit a reflection metadata record for an imported type referenced
763+
/// from this module.
764+
void emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl);
765+
766+
/// Emit reflection metadata records for builtin and imported types referenced
767+
/// from this module.
750768
void emitBuiltinReflectionMetadata();
769+
770+
/// Emit a symbol identifying the reflection metadata version.
751771
void emitReflectionMetadataVersion();
772+
752773
std::string getBuiltinTypeMetadataSectionName();
753774
std::string getFieldTypeMetadataSectionName();
754775
std::string getAssociatedTypeMetadataSectionName();

lib/IRGen/Linking.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,19 @@ void LinkEntity::mangle(raw_ostream &buffer) const {
315315
case Kind::SILGlobalVariable:
316316
mangler.appendSymbol(getSILGlobalVariable()->getName());
317317
return mangler.finalize(buffer);
318+
319+
case Kind::ReflectionBuiltinDescriptor:
320+
mangler.append("_TMRb");
321+
mangler.mangleType(getType(), getUncurryLevel());
322+
return mangler.finalize(buffer);
323+
case Kind::ReflectionFieldDescriptor:
324+
mangler.append("_TMRf");
325+
mangler.mangleType(getType(), getUncurryLevel());
326+
return mangler.finalize(buffer);
327+
case Kind::ReflectionAssociatedTypeDescriptor:
328+
mangler.append("_TMRa");
329+
mangler.mangleProtocolConformance(getProtocolConformance());
330+
return mangler.finalize(buffer);
318331
}
319332
llvm_unreachable("bad entity kind!");
320333
}

lib/IRGen/Linking.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ class LinkEntity {
160160
/// The index of the associated type declaration is stored in the data.
161161
AssociatedTypeWitnessTableAccessFunction,
162162

163+
/// A reflection metadata descriptor for the associated type witnesses of a
164+
/// nominal type in a protocol conformance.
165+
ReflectionAssociatedTypeDescriptor,
166+
163167
// These are both type kinds and protocol-conformance kinds.
164168

165169
/// A lazy protocol witness accessor function. The pointer is a
@@ -171,7 +175,7 @@ class LinkEntity {
171175
/// canonical TypeBase*, and the secondary pointer is a
172176
/// ProtocolConformance*.
173177
ProtocolWitnessTableLazyCacheVariable,
174-
178+
175179
// Everything following this is a type kind.
176180

177181
/// A value witness for a type.
@@ -201,6 +205,12 @@ class LinkEntity {
201205
/// A type which is being mangled just for its string.
202206
/// The pointer is a canonical TypeBase*.
203207
TypeMangling,
208+
209+
/// A reflection metadata descriptor for a builtin or imported type.
210+
ReflectionBuiltinDescriptor,
211+
212+
/// A reflection metadata descriptor for an struct, enum, class or protocol.
213+
ReflectionFieldDescriptor,
204214
};
205215
friend struct llvm::DenseMapInfo<LinkEntity>;
206216

@@ -225,8 +235,8 @@ class LinkEntity {
225235
}
226236

227237
static bool isProtocolConformanceKind(Kind k) {
228-
return k >= Kind::DirectProtocolWitnessTable
229-
&& k <= Kind::ProtocolWitnessTableLazyCacheVariable;
238+
return (k >= Kind::DirectProtocolWitnessTable &&
239+
k <= Kind::ProtocolWitnessTableLazyCacheVariable);
230240
}
231241

232242
void setForDecl(Kind kind, ValueDecl *decl, unsigned uncurryLevel) {
@@ -495,6 +505,26 @@ class LinkEntity {
495505
return entity;
496506
}
497507

508+
static LinkEntity forReflectionBuiltinDescriptor(CanType type) {
509+
LinkEntity entity;
510+
entity.setForType(Kind::ReflectionBuiltinDescriptor, type);
511+
return entity;
512+
}
513+
514+
static LinkEntity forReflectionFieldDescriptor(CanType type) {
515+
LinkEntity entity;
516+
entity.setForType(Kind::ReflectionFieldDescriptor, type);
517+
return entity;
518+
}
519+
520+
static LinkEntity
521+
forReflectionAssociatedTypeDescriptor(const ProtocolConformance *C) {
522+
LinkEntity entity;
523+
entity.setForProtocolConformance(
524+
Kind::ReflectionAssociatedTypeDescriptor, C);
525+
return entity;
526+
}
527+
498528

499529
void mangle(llvm::raw_ostream &out) const;
500530
void mangle(SmallVectorImpl<char> &buffer) const;

test/IRGen/Inputs/abi/c_layout.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct A {
2727
};
2828
struct A createA(void);
2929

30+
enum CrappyColor {
31+
Red, Green, Blue
32+
};
3033

3134
struct BitfieldSeparatorReference {
3235
unsigned char a;

0 commit comments

Comments
 (0)