Skip to content

Commit ff80a2e

Browse files
committed
[AST] Tail-allocate protocol and superclass storage for ArchetypeType.
Superclass constraints are uncommon, so put them into trailing-object storage. Similarly, there's no reason to pay for the pointer + size of the array of protocols to which the archetype conforms when we can use trailing objects and existing padding bits. Note that the nested types are *not* tail-allocated because they will (eventually) be lazily allocated.
1 parent c09f092 commit ff80a2e

File tree

3 files changed

+118
-54
lines changed

3 files changed

+118
-54
lines changed

include/swift/AST/Types.h

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,15 @@ class alignas(1 << TypeAlignInBits) TypeBase {
284284
enum { NumAnyFunctionTypeBits = NumTypeBaseBits + 16 };
285285
static_assert(NumAnyFunctionTypeBits <= 32, "fits in an unsigned");
286286

287+
struct ArchetypeTypeBitfields {
288+
unsigned : NumTypeBaseBits;
289+
290+
unsigned HasSuperclass : 1;
291+
unsigned NumProtocols : 16;
292+
};
293+
enum { NumArchetypeTypeBitfields = NumTypeBaseBits + 17 };
294+
static_assert(NumArchetypeTypeBitfields <= 32, "fits in an unsigned");
295+
287296
struct TypeVariableTypeBitfields {
288297
unsigned : NumTypeBaseBits;
289298

@@ -319,6 +328,7 @@ class alignas(1 << TypeAlignInBits) TypeBase {
319328
ErrorTypeBitfields ErrorTypeBits;
320329
AnyFunctionTypeBitfields AnyFunctionTypeBits;
321330
TypeVariableTypeBitfields TypeVariableTypeBits;
331+
ArchetypeTypeBitfields ArchetypeTypeBits;
322332
SILFunctionTypeBitfields SILFunctionTypeBits;
323333
AnyMetatypeTypeBitfields AnyMetatypeTypeBits;
324334
};
@@ -3728,9 +3738,21 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(SubstitutableType, Type)
37283738
/// associated types, as well as the runtime type stored within an
37293739
/// existential container.
37303740
class ArchetypeType final : public SubstitutableType,
3731-
private llvm::TrailingObjects<ArchetypeType, UUID> {
3741+
private llvm::TrailingObjects<ArchetypeType, ProtocolDecl *, Type, UUID> {
37323742
friend TrailingObjects;
37333743

3744+
size_t numTrailingObjects(OverloadToken<ProtocolDecl *>) const {
3745+
return ArchetypeTypeBits.NumProtocols;
3746+
}
3747+
3748+
size_t numTrailingObjects(OverloadToken<Type>) const {
3749+
return ArchetypeTypeBits.HasSuperclass ? 1 : 0;
3750+
}
3751+
3752+
size_t numTrailingObjects(OverloadToken<UUID>) const {
3753+
return getOpenedExistentialType() ? 1 : 0;
3754+
}
3755+
37343756
public:
37353757
/// A nested type. Either a dependent associated archetype, or a concrete
37363758
/// type (which may be a bound archetype from an outer context).
@@ -3774,21 +3796,11 @@ class ArchetypeType final : public SubstitutableType,
37743796
};
37753797

37763798
private:
3777-
ArrayRef<ProtocolDecl *> ConformsTo;
3778-
Type Superclass;
3779-
37803799
llvm::PointerUnion3<ArchetypeType *, TypeBase *,
37813800
GenericEnvironment *> ParentOrOpenedOrEnvironment;
37823801
llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName;
37833802
MutableArrayRef<std::pair<Identifier, NestedType>> NestedTypes;
37843803

3785-
/// Set the ID number of this opened existential.
3786-
void setOpenedExistentialID(UUID value) {
3787-
assert(getOpenedExistentialType() && "Not an opened existential archetype");
3788-
// The UUID is tail-allocated at the end of opened existential archetypes.
3789-
*getTrailingObjects<UUID>() = value;
3790-
}
3791-
37923804
void resolveNestedType(std::pair<Identifier, NestedType> &nested) const;
37933805

37943806
public:
@@ -3864,15 +3876,22 @@ class ArchetypeType final : public SubstitutableType,
38643876

38653877
/// getConformsTo - Retrieve the set of protocols to which this substitutable
38663878
/// type shall conform.
3867-
ArrayRef<ProtocolDecl *> getConformsTo() const { return ConformsTo; }
3879+
ArrayRef<ProtocolDecl *> getConformsTo() const {
3880+
return { getTrailingObjects<ProtocolDecl *>(),
3881+
ArchetypeTypeBits.NumProtocols };
3882+
}
38683883

38693884
/// requiresClass - True if the type can only be substituted with class types.
38703885
/// This is true if the type conforms to one or more class protocols or has
38713886
/// a superclass constraint.
38723887
bool requiresClass() const;
38733888

38743889
/// \brief Retrieve the superclass of this type, if such a requirement exists.
3875-
Type getSuperclass() const { return Superclass; }
3890+
Type getSuperclass() const {
3891+
if (!ArchetypeTypeBits.HasSuperclass) return Type();
3892+
3893+
return *getTrailingObjects<Type>();
3894+
}
38763895

38773896
/// \brief Return true if the archetype has any requirements at all.
38783897
bool hasRequirements() const {
@@ -3960,29 +3979,11 @@ class ArchetypeType final : public SubstitutableType,
39603979
ParentOrGenericEnv,
39613980
llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName,
39623981
ArrayRef<ProtocolDecl *> ConformsTo,
3963-
Type Superclass)
3964-
: SubstitutableType(TypeKind::Archetype, &Ctx,
3965-
RecursiveTypeProperties::HasArchetype),
3966-
ConformsTo(ConformsTo), Superclass(Superclass),
3967-
AssocTypeOrName(AssocTypeOrName) {
3968-
if (auto parent = ParentOrGenericEnv.dyn_cast<ArchetypeType *>()) {
3969-
ParentOrOpenedOrEnvironment = parent;
3970-
} else {
3971-
ParentOrOpenedOrEnvironment =
3972-
ParentOrGenericEnv.get<GenericEnvironment *>();
3973-
}
3974-
}
3982+
Type Superclass);
39753983

3976-
ArchetypeType(const ASTContext &Ctx,
3977-
Type Existential,
3978-
ArrayRef<ProtocolDecl *> ConformsTo,
3979-
Type Superclass)
3980-
: SubstitutableType(TypeKind::Archetype, &Ctx,
3981-
RecursiveTypeProperties(
3982-
RecursiveTypeProperties::HasArchetype |
3983-
RecursiveTypeProperties::HasOpenedExistential)),
3984-
ConformsTo(ConformsTo), Superclass(Superclass),
3985-
ParentOrOpenedOrEnvironment(Existential.getPointer()) { }
3984+
ArchetypeType(const ASTContext &Ctx, Type Existential,
3985+
ArrayRef<ProtocolDecl *> ConformsTo, Type Superclass,
3986+
UUID uuid);
39863987
};
39873988
BEGIN_CAN_TYPE_WRAPPER(ArchetypeType, SubstitutableType)
39883989
CanArchetypeType getParent() const {

lib/AST/ASTContext.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3418,7 +3418,7 @@ DependentMemberType *DependentMemberType::get(Type base,
34183418
}
34193419

34203420
CanArchetypeType ArchetypeType::getOpened(Type existential,
3421-
Optional<UUID> knownID) {
3421+
Optional<UUID> knownID) {
34223422
auto &ctx = existential->getASTContext();
34233423
auto &openedExistentialArchetypes = ctx.Impl.OpenedExistentialArchetypes;
34243424
// If we know the ID already...
@@ -3437,19 +3437,20 @@ CanArchetypeType ArchetypeType::getOpened(Type existential,
34373437
knownID = UUID::fromTime();
34383438
}
34393439

3440-
auto arena = AllocationArena::Permanent;
34413440
llvm::SmallVector<ProtocolDecl *, 4> conformsTo;
34423441
assert(existential->isExistentialType());
34433442
existential->getAnyExistentialTypeProtocols(conformsTo);
3443+
Type superclass = existential->getSuperclass(nullptr);
34443444

3445-
// Tail-allocate space for the UUID.
3446-
void *archetypeBuf = ctx.Allocate(totalSizeToAlloc<UUID>(1),
3447-
alignof(ArchetypeType), arena);
3448-
3449-
auto result = ::new (archetypeBuf) ArchetypeType(ctx, existential,
3450-
ctx.AllocateCopy(conformsTo),
3451-
existential->getSuperclass(nullptr));
3452-
result->setOpenedExistentialID(*knownID);
3445+
auto arena = AllocationArena::Permanent;
3446+
void *mem = ctx.Allocate(
3447+
totalSizeToAlloc<ProtocolDecl *, Type, UUID>(conformsTo.size(),
3448+
superclass ? 1 : 0,
3449+
1),
3450+
alignof(ArchetypeType), arena);
3451+
3452+
auto result = ::new (mem) ArchetypeType(ctx, existential, conformsTo,
3453+
superclass, *knownID);
34533454
openedExistentialArchetypes[*knownID] = result;
34543455

34553456
return CanArchetypeType(result);

lib/AST/Type.cpp

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,60 @@ Type TupleType::getVarArgsBaseType() const {
24762476
}
24772477

24782478

2479+
ArchetypeType::ArchetypeType(
2480+
const ASTContext &Ctx,
2481+
llvm::PointerUnion<ArchetypeType *, GenericEnvironment *> ParentOrGenericEnv,
2482+
llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName,
2483+
ArrayRef<ProtocolDecl *> ConformsTo,
2484+
Type Superclass)
2485+
: SubstitutableType(TypeKind::Archetype, &Ctx,
2486+
RecursiveTypeProperties::HasArchetype),
2487+
AssocTypeOrName(AssocTypeOrName) {
2488+
// Record the parent/generic environment.
2489+
if (auto parent = ParentOrGenericEnv.dyn_cast<ArchetypeType *>()) {
2490+
ParentOrOpenedOrEnvironment = parent;
2491+
} else {
2492+
ParentOrOpenedOrEnvironment =
2493+
ParentOrGenericEnv.get<GenericEnvironment *>();
2494+
}
2495+
2496+
// Set up the bits we need for trailing objects to work.
2497+
ArchetypeTypeBits.HasSuperclass = static_cast<bool>(Superclass);
2498+
ArchetypeTypeBits.NumProtocols = ConformsTo.size();
2499+
2500+
// Record the superclass.
2501+
if (Superclass)
2502+
*getTrailingObjects<Type>() = Superclass;
2503+
2504+
// Copy the protocols.
2505+
std::uninitialized_copy(ConformsTo.begin(), ConformsTo.end(),
2506+
getTrailingObjects<ProtocolDecl *>());
2507+
}
2508+
2509+
ArchetypeType::ArchetypeType(const ASTContext &Ctx, Type Existential,
2510+
ArrayRef<ProtocolDecl *> ConformsTo,
2511+
Type Superclass, UUID uuid)
2512+
: SubstitutableType(TypeKind::Archetype, &Ctx,
2513+
RecursiveTypeProperties(
2514+
RecursiveTypeProperties::HasArchetype |
2515+
RecursiveTypeProperties::HasOpenedExistential)),
2516+
ParentOrOpenedOrEnvironment(Existential.getPointer()) {
2517+
// Set up the bits we need for trailing objects to work.
2518+
ArchetypeTypeBits.HasSuperclass = static_cast<bool>(Superclass);
2519+
ArchetypeTypeBits.NumProtocols = ConformsTo.size();
2520+
2521+
// Record the superclass.
2522+
if (Superclass)
2523+
*getTrailingObjects<Type>() = Superclass;
2524+
2525+
// Copy the protocols.
2526+
std::uninitialized_copy(ConformsTo.begin(), ConformsTo.end(),
2527+
getTrailingObjects<ProtocolDecl *>());
2528+
2529+
// Record the UUID.
2530+
*getTrailingObjects<UUID>() = uuid;
2531+
}
2532+
24792533
CanArchetypeType ArchetypeType::getNew(
24802534
const ASTContext &Ctx,
24812535
ArchetypeType *Parent,
@@ -2486,10 +2540,14 @@ CanArchetypeType ArchetypeType::getNew(
24862540
ProtocolType::canonicalizeProtocols(ConformsTo);
24872541

24882542
auto arena = AllocationArena::Permanent;
2489-
return CanArchetypeType(
2490-
new (Ctx, arena) ArchetypeType(Ctx, Parent, AssocType,
2491-
Ctx.AllocateCopy(ConformsTo),
2492-
Superclass));
2543+
void *mem = Ctx.Allocate(
2544+
totalSizeToAlloc<ProtocolDecl *, Type, UUID>(ConformsTo.size(),
2545+
Superclass ? 1 : 0,
2546+
0),
2547+
alignof(ArchetypeType), arena);
2548+
2549+
return CanArchetypeType(new (mem) ArchetypeType(Ctx, Parent, AssocType,
2550+
ConformsTo, Superclass));
24932551
}
24942552

24952553
CanArchetypeType
@@ -2502,14 +2560,18 @@ ArchetypeType::getNew(const ASTContext &Ctx,
25022560
ProtocolType::canonicalizeProtocols(ConformsTo);
25032561

25042562
auto arena = AllocationArena::Permanent;
2505-
return CanArchetypeType(
2506-
new (Ctx, arena) ArchetypeType(Ctx, genericEnvironment, Name,
2507-
Ctx.AllocateCopy(ConformsTo),
2508-
Superclass));
2563+
void *mem = Ctx.Allocate(
2564+
totalSizeToAlloc<ProtocolDecl *, Type, UUID>(ConformsTo.size(),
2565+
Superclass ? 1 : 0,
2566+
0),
2567+
alignof(ArchetypeType), arena);
2568+
2569+
return CanArchetypeType(new (mem) ArchetypeType(Ctx, genericEnvironment, Name,
2570+
ConformsTo, Superclass));
25092571
}
25102572

25112573
bool ArchetypeType::requiresClass() const {
2512-
if (Superclass)
2574+
if (ArchetypeTypeBits.HasSuperclass)
25132575
return true;
25142576
for (ProtocolDecl *conformed : getConformsTo())
25152577
if (conformed->requiresClass())

0 commit comments

Comments
 (0)