Skip to content

Serialization: Preserve identity of opened generic environments [5.7] #60525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 6 additions & 18 deletions include/swift/AST/GenericEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class QueryInterfaceTypeSubstitutions {
/// Extra data in a generic environment for an opened existentiak.
struct OpenedGenericEnvironmentData {
Type existential;
GenericSignature parentSig;
UUID uuid;
};

Expand Down Expand Up @@ -110,7 +111,8 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final

explicit GenericEnvironment(GenericSignature signature);
explicit GenericEnvironment(
GenericSignature signature, Type existential, UUID uuid);
GenericSignature signature,
Type existential, GenericSignature parentSig, UUID uuid);
explicit GenericEnvironment(
GenericSignature signature, OpaqueTypeDecl *opaque, SubstitutionMap subs);

Expand Down Expand Up @@ -143,6 +145,9 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
/// Retrieve the UUID for an opened existential environment.
UUID getOpenedExistentialUUID() const;

/// Retrieve the parent signature for an opened existential environment.
GenericSignature getOpenedExistentialParentSignature() const;

/// Retrieve the opaque type declaration for a generic environment describing
/// opaque types.
OpaqueTypeDecl *getOpaqueTypeDecl() const;
Expand All @@ -158,29 +163,12 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final

/// Create a new generic environment for an opened existential.
///
/// This function uses the provided parent signature to construct a new
/// signature suitable for use with an opened archetype. If you have an
/// existing generic signature from e.g. deserialization use
/// \c GenericEnvironment::forOpenedArchetypeSignature instead.
///
/// \param existential The subject existential type
/// \param parentSig The signature of the context where this existential type is being opened
/// \param uuid The unique identifier for this opened existential
static GenericEnvironment *
forOpenedExistential(Type existential, GenericSignature parentSig, UUID uuid);

/// Create a new generic environment for an opened existential.
///
/// It is unlikely you want to use this function.
/// Call \c GenericEnvironment::forOpenedExistential instead.
///
/// \param existential The subject existential type
/// \param signature The signature of the opened archetype
/// \param uuid The unique identifier for this opened existential
static GenericEnvironment *
forOpenedArchetypeSignature(Type existential,
GenericSignature signature, UUID uuid);

/// Create a new generic environment for an opaque type with the given set of
/// outer substitutions.
static GenericEnvironment *forOpaqueType(
Expand Down
7 changes: 1 addition & 6 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4679,19 +4679,14 @@ GenericEnvironment::forOpenedExistential(
Type existential, GenericSignature parentSig, UUID uuid) {
auto &ctx = existential->getASTContext();
auto signature = ctx.getOpenedArchetypeSignature(existential, parentSig);
return GenericEnvironment::forOpenedArchetypeSignature(existential, signature, uuid);
}

GenericEnvironment *GenericEnvironment::forOpenedArchetypeSignature(
Type existential, GenericSignature signature, UUID uuid) {
// Allocate and construct the new environment.
auto &ctx = existential->getASTContext();
unsigned numGenericParams = signature.getGenericParams().size();
size_t bytes = totalSizeToAlloc<OpaqueTypeDecl *, SubstitutionMap,
OpenedGenericEnvironmentData, Type>(
0, 0, 1, numGenericParams);
void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment));
return new (mem) GenericEnvironment(signature, existential, uuid);
return new (mem) GenericEnvironment(signature, existential, parentSig, uuid);
}

/// Create a new generic environment for an opaque type with the given set of
Expand Down
11 changes: 9 additions & 2 deletions lib/AST/GenericEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ UUID GenericEnvironment::getOpenedExistentialUUID() const {
return getTrailingObjects<OpenedGenericEnvironmentData>()->uuid;
}

GenericSignature
GenericEnvironment::getOpenedExistentialParentSignature() const {
assert(getKind() == Kind::OpenedExistential);
return getTrailingObjects<OpenedGenericEnvironmentData>()->parentSig;
}

GenericEnvironment::GenericEnvironment(GenericSignature signature)
: SignatureAndKind(signature, Kind::Normal)
{
Expand All @@ -113,11 +119,12 @@ GenericEnvironment::GenericEnvironment(GenericSignature signature)
}

GenericEnvironment::GenericEnvironment(
GenericSignature signature, Type existential, UUID uuid)
GenericSignature signature,
Type existential, GenericSignature parentSig, UUID uuid)
: SignatureAndKind(signature, Kind::OpenedExistential)
{
new (getTrailingObjects<OpenedGenericEnvironmentData>())
OpenedGenericEnvironmentData{ existential, uuid };
OpenedGenericEnvironmentData{ existential, parentSig, uuid };

// Clear out the memory that holds the context types.
std::uninitialized_fill(getContextTypes().begin(), getContextTypes().end(),
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/DeclTypeRecordNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ OTHER(TOP_LEVEL_CODE_DECL_CONTEXT, 112)
OTHER(GENERIC_PARAM_LIST, 120)
OTHER(GENERIC_SIGNATURE, 121)
OTHER(REQUIREMENT_SIGNATURE, 122)
// 123 is unused; was LAYOUT_REQUIREMENT
OTHER(GENERIC_ENVIRONMENT, 123)
OTHER(BUILTIN_PROTOCOL_CONFORMANCE, 124)
OTHER(SIL_GENERIC_SIGNATURE, 125)
OTHER(SUBSTITUTION_MAP, 126)
Expand Down
68 changes: 54 additions & 14 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,53 @@ ModuleFile::getGenericSignatureChecked(serialization::GenericSignatureID ID) {
return signature;
}

Expected<GenericEnvironment *>
ModuleFile::getGenericEnvironmentChecked(serialization::GenericEnvironmentID ID) {
using namespace decls_block;

assert(ID <= GenericEnvironments.size() &&
"invalid GenericEnvironment ID");
auto &envOffset = GenericEnvironments[ID-1];

// If we've already deserialized this generic environment, return it.
if (envOffset.isComplete())
return envOffset.get();

// Read the generic environment.
BCOffsetRAII restoreOffset(DeclTypeCursor);
fatalIfNotSuccess(DeclTypeCursor.JumpToBit(envOffset));

llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();

StringRef blobData;
SmallVector<uint64_t, 8> scratch;
unsigned recordID = fatalIfUnexpected(
DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
if (recordID != GENERIC_ENVIRONMENT)
fatal();

GenericSignatureID parentSigID;
TypeID existentialID;
GenericEnvironmentLayout::readRecord(scratch, existentialID, parentSigID);

auto existentialTypeOrError = getTypeChecked(existentialID);
if (!existentialTypeOrError)
return existentialTypeOrError.takeError();

auto parentSigOrError = getGenericSignatureChecked(parentSigID);
if (!parentSigOrError)
return parentSigOrError.takeError();

auto *genericEnv = GenericEnvironment::forOpenedExistential(
existentialTypeOrError.get(), parentSigOrError.get(), UUID::fromTime());
envOffset = genericEnv;

return genericEnv;
}

SubstitutionMap ModuleFile::getSubstitutionMap(
serialization::SubstitutionMapID id) {
auto map = getSubstitutionMapChecked(id);
Expand Down Expand Up @@ -5709,28 +5756,21 @@ class TypeDeserializer {

Expected<Type> deserializeOpenedArchetypeType(ArrayRef<uint64_t> scratch,
StringRef blobData) {
TypeID existentialID;
TypeID interfaceID;
GenericSignatureID sigID;

decls_block::OpenedArchetypeTypeLayout::readRecord(scratch, existentialID,
interfaceID, sigID);
GenericEnvironmentID genericEnvID;

auto sigOrError = MF.getGenericSignatureChecked(sigID);
if (!sigOrError)
return sigOrError.takeError();
decls_block::OpenedArchetypeTypeLayout::readRecord(scratch,
interfaceID, genericEnvID);

auto interfaceTypeOrError = MF.getTypeChecked(interfaceID);
if (!interfaceTypeOrError)
return interfaceTypeOrError.takeError();

auto existentialTypeOrError = MF.getTypeChecked(existentialID);
if (!existentialTypeOrError)
return existentialTypeOrError.takeError();
auto envOrError = MF.getGenericEnvironmentChecked(genericEnvID);
if (!envOrError)
return envOrError.takeError();

auto env = GenericEnvironment::forOpenedArchetypeSignature(
existentialTypeOrError.get(), sigOrError.get(), UUID::fromTime());
return env->mapTypeIntoContext(interfaceTypeOrError.get())
return envOrError.get()->mapTypeIntoContext(interfaceTypeOrError.get())
->castTo<OpenedArchetypeType>();
}

Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/ModuleFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ ModuleFile::ModuleFile(std::shared_ptr<const ModuleFileSharedCore> core)
allocateBuffer(Types, core->Types);
allocateBuffer(ClangTypes, core->ClangTypes);
allocateBuffer(GenericSignatures, core->GenericSignatures);
allocateBuffer(GenericEnvironments, core->GenericEnvironments);
allocateBuffer(SubstitutionMaps, core->SubstitutionMaps);
allocateBuffer(Identifiers, core->Identifiers);
}
Expand Down
7 changes: 7 additions & 0 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ class ModuleFile
/// Generic signatures referenced by this module.
MutableArrayRef<Serialized<GenericSignature>> GenericSignatures;

/// Generic environments referenced by this module.
MutableArrayRef<Serialized<GenericEnvironment *>> GenericEnvironments;

/// Substitution maps referenced by this module.
MutableArrayRef<Serialized<SubstitutionMap>> SubstitutionMaps;

Expand Down Expand Up @@ -859,6 +862,10 @@ class ModuleFile
llvm::Expected<GenericSignature>
getGenericSignatureChecked(serialization::GenericSignatureID ID);

/// Returns the generic environment for the given ID or the first error.
llvm::Expected<GenericEnvironment *>
getGenericEnvironmentChecked(serialization::GenericEnvironmentID ID);

/// Returns the substitution map for the given ID, deserializing it if
/// needed.
SubstitutionMap getSubstitutionMap(serialization::SubstitutionMapID id);
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,10 @@ bool ModuleFileSharedCore::readIndexBlock(llvm::BitstreamCursor &cursor) {
assert(blobData.empty());
allocateBuffer(GenericSignatures, scratch);
break;
case index_block::GENERIC_ENVIRONMENT_OFFSETS:
assert(blobData.empty());
allocateBuffer(GenericEnvironments, scratch);
break;
case index_block::SUBSTITUTION_MAP_OFFSETS:
assert(blobData.empty());
allocateBuffer(SubstitutionMaps, scratch);
Expand Down
3 changes: 3 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ class ModuleFileSharedCore {
/// Generic signatures referenced by this module.
ArrayRef<RawBitOffset> GenericSignatures;

/// Generic environments referenced by this module.
ArrayRef<RawBitOffset> GenericEnvironments;

/// Substitution maps referenced by this module.
ArrayRef<RawBitOffset> SubstitutionMaps;

Expand Down
17 changes: 13 additions & 4 deletions lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 698; // revert selector table changes
const uint16_t SWIFTMODULE_VERSION_MINOR = 699; // opened archetype serialization

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -143,6 +143,9 @@ using ProtocolConformanceIDField = DeclIDField;
using GenericSignatureID = DeclID;
using GenericSignatureIDField = DeclIDField;

using GenericEnvironmentID = unsigned;
using GenericEnvironmentIDField = BCFixed<32>;

// SubstitutionMapID must be the same as DeclID because it is stored in the
// same way.
using SubstitutionMapID = DeclID;
Expand Down Expand Up @@ -1077,9 +1080,8 @@ namespace decls_block {

using OpenedArchetypeTypeLayout = BCRecordLayout<
OPENED_ARCHETYPE_TYPE,
TypeIDField, // the existential type
TypeIDField, // the interface type
GenericSignatureIDField // generic signature
TypeIDField, // the interface type
GenericEnvironmentIDField // generic environment ID
>;

using OpaqueArchetypeTypeLayout = BCRecordLayout<
Expand Down Expand Up @@ -1636,6 +1638,12 @@ namespace decls_block {
BCArray<TypeIDField> // generic parameter types
>;

using GenericEnvironmentLayout = BCRecordLayout<
GENERIC_ENVIRONMENT,
TypeIDField, // existential type
GenericSignatureIDField // parent signature
>;

using SubstitutionMapLayout = BCRecordLayout<
SUBSTITUTION_MAP,
GenericSignatureIDField, // generic signature
Expand Down Expand Up @@ -2119,6 +2127,7 @@ namespace index_block {
LOCAL_TYPE_DECLS,
OPAQUE_RETURN_TYPE_DECLS,
GENERIC_SIGNATURE_OFFSETS,
GENERIC_ENVIRONMENT_OFFSETS,
PROTOCOL_CONFORMANCE_OFFSETS,
SIL_LAYOUT_OFFSETS,

Expand Down
34 changes: 29 additions & 5 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,13 @@ Serializer::addGenericSignatureRef(GenericSignature sig) {
return GenericSignaturesToSerialize.addRef(sig);
}

GenericEnvironmentID
Serializer::addGenericEnvironmentRef(GenericEnvironment *env) {
if (!env)
return 0;
return GenericEnvironmentsToSerialize.addRef(env);
}

SubstitutionMapID
Serializer::addSubstitutionMapRef(SubstitutionMap substitutions) {
return SubstitutionMapsToSerialize.addRef(substitutions);
Expand Down Expand Up @@ -878,6 +885,7 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(index_block, ENTRY_POINT);
BLOCK_RECORD(index_block, LOCAL_DECL_CONTEXT_OFFSETS);
BLOCK_RECORD(index_block, GENERIC_SIGNATURE_OFFSETS);
BLOCK_RECORD(index_block, GENERIC_ENVIRONMENT_OFFSETS);
BLOCK_RECORD(index_block, SUBSTITUTION_MAP_OFFSETS);
BLOCK_RECORD(index_block, CLANG_TYPE_OFFSETS);
BLOCK_RECORD(index_block, LOCAL_TYPE_DECLS);
Expand Down Expand Up @@ -1490,6 +1498,20 @@ void Serializer::writeASTBlockEntity(GenericSignature sig) {
}
}

void Serializer::writeASTBlockEntity(const GenericEnvironment *genericEnv) {
using namespace decls_block;

assert(GenericEnvironmentsToSerialize.hasRef(genericEnv));

auto existentialTypeID = addTypeRef(genericEnv->getOpenedExistentialType());
auto parentSig = genericEnv->getOpenedExistentialParentSignature();
auto parentSigID = addGenericSignatureRef(parentSig);

auto genericEnvAbbrCode = DeclTypeAbbrCodes[GenericEnvironmentLayout::Code];
GenericEnvironmentLayout::emitRecord(Out, ScratchRecord, genericEnvAbbrCode,
existentialTypeID, parentSigID);
}

void Serializer::writeASTBlockEntity(const SubstitutionMap substitutions) {
using namespace decls_block;
assert(substitutions);
Expand Down Expand Up @@ -4592,14 +4614,12 @@ class Serializer::TypeSerializer : public TypeVisitor<TypeSerializer> {

void visitOpenedArchetypeType(const OpenedArchetypeType *archetypeTy) {
using namespace decls_block;
auto sig = archetypeTy->getGenericEnvironment()->getGenericSignature();
auto existentialTypeID = S.addTypeRef(archetypeTy->getExistentialType());
auto interfaceTypeID = S.addTypeRef(archetypeTy->getInterfaceType());
auto sigID = S.addGenericSignatureRef(sig);
auto genericEnvID = S.addGenericEnvironmentRef(
archetypeTy->getGenericEnvironment());
unsigned abbrCode = S.DeclTypeAbbrCodes[OpenedArchetypeTypeLayout::Code];
OpenedArchetypeTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
existentialTypeID, interfaceTypeID,
sigID);
interfaceTypeID, genericEnvID);
}

void
Expand Down Expand Up @@ -5090,6 +5110,7 @@ void Serializer::writeAllDeclsAndTypes() {
registerDeclTypeAbbr<InlinableBodyTextLayout>();
registerDeclTypeAbbr<GenericParamListLayout>();
registerDeclTypeAbbr<GenericSignatureLayout>();
registerDeclTypeAbbr<GenericEnvironmentLayout>();
registerDeclTypeAbbr<RequirementSignatureLayout>();
registerDeclTypeAbbr<SILGenericSignatureLayout>();
registerDeclTypeAbbr<SubstitutionMapLayout>();
Expand Down Expand Up @@ -5143,6 +5164,8 @@ void Serializer::writeAllDeclsAndTypes() {
writeASTBlockEntitiesIfNeeded(LocalDeclContextsToSerialize);
wroteSomething |=
writeASTBlockEntitiesIfNeeded(GenericSignaturesToSerialize);
wroteSomething |=
writeASTBlockEntitiesIfNeeded(GenericEnvironmentsToSerialize);
wroteSomething |=
writeASTBlockEntitiesIfNeeded(SubstitutionMapsToSerialize);
wroteSomething |=
Expand Down Expand Up @@ -5746,6 +5769,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
writeOffsets(Offsets, ClangTypesToSerialize);
writeOffsets(Offsets, LocalDeclContextsToSerialize);
writeOffsets(Offsets, GenericSignaturesToSerialize);
writeOffsets(Offsets, GenericEnvironmentsToSerialize);
writeOffsets(Offsets, SubstitutionMapsToSerialize);
writeOffsets(Offsets, ConformancesToSerialize);
writeOffsets(Offsets, SILLayoutsToSerialize);
Expand Down
Loading