Skip to content

Commit cdff742

Browse files
committed
[AST] Unique and ASTContext-allocate SubstitutionMaps.
Prepare for SubstitutionMaps to be stored in other AST nodes by making them ASTContext-allocated and uniqued (via a FoldingSet). They are now cheap to copy and have trivial destructors.
1 parent 03a47b8 commit cdff742

File tree

3 files changed

+83
-43
lines changed

3 files changed

+83
-43
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
#include "swift/AST/SubstitutionList.h"
2323
#include "swift/AST/Type.h"
2424
#include "llvm/ADT/ArrayRef.h"
25+
#include "llvm/ADT/FoldingSet.h"
2526
#include "llvm/ADT/Optional.h"
2627
#include "llvm/Support/TrailingObjects.h"
27-
#include <memory>
2828

2929
namespace llvm {
3030
class FoldingSetNodeID;
@@ -56,10 +56,12 @@ enum class CombineSubstitutionMaps {
5656
/// on a GenericSignature or (equivalently) by calling one of the static
5757
/// \c SubstitutionMap::get() methods.
5858
class SubstitutionMap {
59+
public:
5960
/// Stored data for a substitution map, which uses tail allocation for the
6061
/// replacement types and conformances.
6162
class Storage final
62-
: llvm::TrailingObjects<Storage, Type, ProtocolConformanceRef>
63+
: public llvm::FoldingSetNode,
64+
llvm::TrailingObjects<Storage, Type, ProtocolConformanceRef>
6365
{
6466
friend TrailingObjects;
6567

@@ -126,13 +128,26 @@ class SubstitutionMap {
126128
getTrailingObjects<ProtocolConformanceRef>(),
127129
numConformanceRequirements);
128130
}
131+
132+
/// Profile the substitution map storage, for use with LLVM's FoldingSet.
133+
void Profile(llvm::FoldingSetNodeID &id) const {
134+
Profile(id, getGenericSignature(), getReplacementTypes(),
135+
getConformances());
136+
}
137+
138+
/// Profile the substitution map storage, for use with LLVM's FoldingSet.
139+
static void Profile(llvm::FoldingSetNodeID &id,
140+
GenericSignature *genericSig,
141+
ArrayRef<Type> replacementTypes,
142+
ArrayRef<ProtocolConformanceRef> conformances);
129143
};
130144

145+
private:
131146
/// The storage needed to describe the set of substitutions.
132147
///
133148
/// When null, this substitution map is empty, having neither a generic
134149
/// signature nor any replacement types/conformances.
135-
std::shared_ptr<Storage> storage;
150+
Storage *storage = nullptr;
136151

137152
/// Retrieve the array of replacement types, which line up with the
138153
/// generic parameters.

lib/AST/ASTContext.cpp

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
309309
/// The set of inherited protocol conformances.
310310
llvm::FoldingSet<InheritedProtocolConformance> InheritedConformances;
311311

312+
/// The set of substitution maps (uniqued by their storage).
313+
llvm::FoldingSet<SubstitutionMap::Storage> SubstitutionMaps;
314+
312315
~Arena() {
313316
for (auto &conformance : SpecializedConformances)
314317
conformance.~SpecializedProtocolConformance();
@@ -2907,11 +2910,9 @@ NameAliasType::NameAliasType(TypeAliasDecl *typealias, Type parent,
29072910
}
29082911
}
29092912

2910-
NameAliasType *NameAliasType::get(
2911-
TypeAliasDecl *typealias,
2912-
Type parent,
2913-
const SubstitutionMap &substitutions,
2914-
Type underlying) {
2913+
NameAliasType *NameAliasType::get(TypeAliasDecl *typealias, Type parent,
2914+
const SubstitutionMap &substitutions,
2915+
Type underlying) {
29152916
// Compute the recursive properties.
29162917
//
29172918
auto properties = underlying->getRecursiveProperties();
@@ -4293,6 +4294,64 @@ CapturingTypeCheckerDebugConsumer::~CapturingTypeCheckerDebugConsumer() {
42934294
delete Log;
42944295
}
42954296

4297+
void SubstitutionMap::Storage::Profile(
4298+
llvm::FoldingSetNodeID &id,
4299+
GenericSignature *genericSig,
4300+
ArrayRef<Type> replacementTypes,
4301+
ArrayRef<ProtocolConformanceRef> conformances) {
4302+
id.AddPointer(genericSig);
4303+
id.AddInteger(replacementTypes.size());
4304+
for (auto type : replacementTypes)
4305+
id.AddPointer(type.getPointer());
4306+
id.AddInteger(conformances.size());
4307+
for (auto conformance : conformances)
4308+
id.AddPointer(conformance.getOpaqueValue());
4309+
}
4310+
4311+
SubstitutionMap::Storage *SubstitutionMap::Storage::get(
4312+
GenericSignature *genericSig,
4313+
ArrayRef<Type> replacementTypes,
4314+
ArrayRef<ProtocolConformanceRef> conformances) {
4315+
// If there is no generic signature, we need no storage.
4316+
if (!genericSig) {
4317+
assert(replacementTypes.empty());
4318+
assert(conformances.empty());
4319+
return nullptr;
4320+
}
4321+
4322+
// Figure out which arena this should go in.
4323+
RecursiveTypeProperties properties;
4324+
for (auto type : replacementTypes) {
4325+
if (type)
4326+
properties |= type->getRecursiveProperties();
4327+
}
4328+
4329+
// Profile the substitution map.
4330+
llvm::FoldingSetNodeID id;
4331+
SubstitutionMap::Storage::Profile(id, genericSig, replacementTypes,
4332+
conformances);
4333+
4334+
auto arena = getArena(properties);
4335+
4336+
// Did we already record this substitution map?
4337+
auto &ctx = genericSig->getASTContext();
4338+
void *insertPos;
4339+
auto &substitutionMaps = ctx.Impl.getArena(arena).SubstitutionMaps;
4340+
if (auto result = substitutionMaps.FindNodeOrInsertPos(id, insertPos))
4341+
return result;
4342+
4343+
// Allocate the appropriate amount of storage for the signature and its
4344+
// replacement types and conformances.
4345+
auto size = Storage::totalSizeToAlloc<Type, ProtocolConformanceRef>(
4346+
replacementTypes.size(),
4347+
conformances.size());
4348+
auto mem = ctx.Allocate(size, alignof(Storage), arena);
4349+
4350+
auto result = new (mem) Storage(genericSig, replacementTypes, conformances);
4351+
substitutionMaps.InsertNode(result, insertPos);
4352+
return result;
4353+
}
4354+
42964355
void GenericSignature::Profile(llvm::FoldingSetNodeID &ID,
42974356
TypeArrayView<GenericTypeParamType> genericParams,
42984357
ArrayRef<Requirement> requirements) {

lib/AST/SubstitutionMap.cpp

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,6 @@ SubstitutionMap::Storage::Storage(
5050
getConformances().data());
5151
}
5252

53-
SubstitutionMap::Storage *SubstitutionMap::Storage::get(
54-
GenericSignature *genericSig,
55-
ArrayRef<Type> replacementTypes,
56-
ArrayRef<ProtocolConformanceRef> conformances) {
57-
// If there is no generic signature, we need no storage.
58-
if (!genericSig) {
59-
assert(replacementTypes.empty());
60-
assert(conformances.empty());
61-
return nullptr;
62-
}
63-
64-
// Allocate the appropriate amount of storage for the signature and its
65-
// replacement types and conformances.
66-
auto size = Storage::totalSizeToAlloc<Type, ProtocolConformanceRef>(
67-
replacementTypes.size(),
68-
conformances.size());
69-
auto mem = malloc(size);
70-
return new (mem) Storage(genericSig, replacementTypes, conformances);
71-
}
72-
7353
bool SubstitutionMap::hasArchetypes() const {
7454
for (Type replacementTy : getReplacementTypes()) {
7555
if (replacementTy && replacementTy->hasArchetype())
@@ -587,20 +567,6 @@ void SubstitutionMap::dump() const {
587567
}
588568

589569
void SubstitutionMap::profile(llvm::FoldingSetNodeID &id) const {
590-
// Generic signature.
591-
auto genericSig = getGenericSignature();
592-
id.AddPointer(genericSig);
593-
594-
if (empty() || !genericSig) return;
595-
596-
// Replacement types.
597-
for (Type gp : genericSig->getGenericParams()) {
598-
id.AddPointer(gp.subst(*this).getPointer());
599-
}
600-
601-
// Conformance requirements.
602-
for (const auto conformance : getConformances()) {
603-
id.AddPointer(conformance.getOpaqueValue());
604-
}
570+
id.AddPointer(storage);
605571
}
606572

0 commit comments

Comments
 (0)