Support in-place value metadata initialization in the runtime.

This commit is contained in:
John McCall
2018-07-24 18:27:42 -04:00
parent e6fc5cb54e
commit dadb51e708
6 changed files with 340 additions and 15 deletions

View File

@@ -3364,6 +3364,14 @@ public:
return TypeContextDescriptorFlags(this->Flags.getKindSpecificFlags()); return TypeContextDescriptorFlags(this->Flags.getKindSpecificFlags());
} }
/// Does this type have non-trivial "in place" metadata initialization?
///
/// The type of the initialization-control structure differs by subclass,
/// so it doesn't appear here.
bool hasInPlaceMetadataInitialization() const {
return getTypeContextDescriptorFlags().hasInPlaceMetadataInitialization();
}
const TargetTypeGenericContextDescriptorHeader<Runtime> & const TargetTypeGenericContextDescriptorHeader<Runtime> &
getFullGenericContextHeader() const; getFullGenericContextHeader() const;
@@ -3709,10 +3717,49 @@ public:
using ClassDescriptor = TargetClassDescriptor<InProcess>; using ClassDescriptor = TargetClassDescriptor<InProcess>;
/// The cache structure for non-trivial initialization of singleton value
/// metadata.
template <typename Runtime>
struct TargetInPlaceValueMetadataCache {
/// The metadata pointer. Clients can do dependency-ordered loads
/// from this, and if they see a non-zero value, it's a Complete
/// metadata.
std::atomic<TargetMetadataPointer<Runtime, TargetMetadata>> Metadata;
/// The private cache data.
std::atomic<TargetPointer<Runtime, void>> Private;
};
using InPlaceValueMetadataCache =
TargetInPlaceValueMetadataCache<InProcess>;
/// The control structure for performing non-trivial initialization of
/// singleton value metadata, which is required when e.g. a non-generic
/// value type has a resilient component type.
template <typename Runtime>
struct TargetInPlaceValueMetadataInitialization {
/// The initialization cache. Out-of-line because mutable.
TargetRelativeDirectPointer<Runtime,
TargetInPlaceValueMetadataCache<Runtime>>
InitializationCache;
/// The incomplete metadata.
TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>>
IncompleteMetadata;
/// The completion function. The pattern will always be null.
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
CompletionFunction;
};
template <typename Runtime> template <typename Runtime>
class TargetValueTypeDescriptor class TargetValueTypeDescriptor
: public TargetTypeContextDescriptor<Runtime> { : public TargetTypeContextDescriptor<Runtime> {
public: public:
using InPlaceMetadataInitialization =
TargetInPlaceValueMetadataInitialization<Runtime>;
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const;
static bool classof(const TargetContextDescriptor<Runtime> *cd) { static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::Struct || return cd->getKind() == ContextDescriptorKind::Struct ||
cd->getKind() == ContextDescriptorKind::Enum; cd->getKind() == ContextDescriptorKind::Enum;
@@ -3724,16 +3771,30 @@ template <typename Runtime>
class TargetStructDescriptor final class TargetStructDescriptor final
: public TargetValueTypeDescriptor<Runtime>, : public TargetValueTypeDescriptor<Runtime>,
public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>, public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader> { TargetTypeGenericContextDescriptorHeader,
TargetInPlaceValueMetadataInitialization<Runtime>> {
public:
using InPlaceMetadataInitialization =
TargetInPlaceValueMetadataInitialization<Runtime>;
private: private:
using TrailingGenericContextObjects = using TrailingGenericContextObjects =
TrailingGenericContextObjects<TargetStructDescriptor<Runtime>, TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader>; TargetTypeGenericContextDescriptorHeader,
InPlaceMetadataInitialization>;
using TrailingObjects = using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects; typename TrailingGenericContextObjects::TrailingObjects;
friend TrailingObjects; friend TrailingObjects;
template<typename T>
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
using TrailingGenericContextObjects::numTrailingObjects;
size_t numTrailingObjects(OverloadToken<InPlaceMetadataInitialization>) const{
return this->hasInPlaceMetadataInitialization() ? 1 : 0;
}
public: public:
using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader; using TrailingGenericContextObjects::getGenericContextHeader;
@@ -3752,6 +3813,11 @@ public:
/// its stored properties. /// its stored properties.
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; } bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const{
assert(this->hasInPlaceMetadataInitialization());
return *this->template getTrailingObjects<InPlaceMetadataInitialization>();
}
static constexpr int32_t getGenericArgumentOffset() { static constexpr int32_t getGenericArgumentOffset() {
return TargetStructMetadata<Runtime>::getGenericArgumentOffset(); return TargetStructMetadata<Runtime>::getGenericArgumentOffset();
} }
@@ -3767,16 +3833,30 @@ template <typename Runtime>
class TargetEnumDescriptor final class TargetEnumDescriptor final
: public TargetValueTypeDescriptor<Runtime>, : public TargetValueTypeDescriptor<Runtime>,
public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>, public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader> { TargetTypeGenericContextDescriptorHeader,
TargetInPlaceValueMetadataInitialization<Runtime>> {
public:
using InPlaceMetadataInitialization =
TargetInPlaceValueMetadataInitialization<Runtime>;
private: private:
using TrailingGenericContextObjects = using TrailingGenericContextObjects =
TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>, TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader>; TargetTypeGenericContextDescriptorHeader,
InPlaceMetadataInitialization>;
using TrailingObjects = using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects; typename TrailingGenericContextObjects::TrailingObjects;
friend TrailingObjects; friend TrailingObjects;
template<typename T>
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
using TrailingGenericContextObjects::numTrailingObjects;
size_t numTrailingObjects(OverloadToken<InPlaceMetadataInitialization>) const{
return this->hasInPlaceMetadataInitialization() ? 1 : 0;
}
public: public:
using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader; using TrailingGenericContextObjects::getGenericContextHeader;
@@ -3813,6 +3893,11 @@ public:
return TargetEnumMetadata<Runtime>::getGenericArgumentOffset(); return TargetEnumMetadata<Runtime>::getGenericArgumentOffset();
} }
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const{
assert(this->hasInPlaceMetadataInitialization());
return *this->template getTrailingObjects<InPlaceMetadataInitialization>();
}
static bool classof(const TargetContextDescriptor<Runtime> *cd) { static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::Enum; return cd->getKind() == ContextDescriptorKind::Enum;
} }
@@ -3901,6 +3986,21 @@ TargetTypeContextDescriptor<Runtime>::getGenericParams() const {
} }
} }
template<typename Runtime>
inline const TargetInPlaceValueMetadataInitialization<Runtime> &
TargetValueTypeDescriptor<Runtime>::getInPlaceMetadataInitialization() const {
switch (this->getKind()) {
case ContextDescriptorKind::Enum:
return llvm::cast<TargetEnumDescriptor<Runtime>>(this)
->getInPlaceMetadataInitialization();
case ContextDescriptorKind::Struct:
return llvm::cast<TargetStructDescriptor<Runtime>>(this)
->getInPlaceMetadataInitialization();
default:
swift_runtime_unreachable("Not a value type descriptor.");
}
}
} // end namespace swift } // end namespace swift
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@@ -1202,6 +1202,14 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
/// declarations associated with the same declaration. /// declarations associated with the same declaration.
IsSynthesizedRelatedEntity = 3, IsSynthesizedRelatedEntity = 3,
/// Set if the type requires non-trivial but non-generic metadata
/// initialization. It may or may not be truly "in place" depending
/// on the kind of metadata.
///
/// Currently only meaningful for value descriptors, but will be
/// extended to class descriptors.
HasInPlaceMetadataInitialization = 4,
/// Set if the context descriptor is includes metadata for dynamically /// Set if the context descriptor is includes metadata for dynamically
/// constructing a class's vtables at metadata instantiation time. /// constructing a class's vtables at metadata instantiation time.
/// ///
@@ -1237,6 +1245,10 @@ public:
isSynthesizedRelatedEntity, isSynthesizedRelatedEntity,
setIsSynthesizedRelatedEntity) setIsSynthesizedRelatedEntity)
FLAGSET_DEFINE_FLAG_ACCESSORS(HasInPlaceMetadataInitialization,
hasInPlaceMetadataInitialization,
setHasInPlaceMetadataInitialization)
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable, FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
class_hasVTable, class_hasVTable,
class_setHasVTable) class_setHasVTable)

View File

@@ -1050,8 +1050,10 @@ private:
sizeof(flags))) sizeof(flags)))
return nullptr; return nullptr;
TypeContextDescriptorFlags typeFlags(flags.getKindSpecificFlags());
unsigned baseSize = 0; unsigned baseSize = 0;
unsigned genericHeaderSize = sizeof(GenericContextDescriptorHeader); unsigned genericHeaderSize = sizeof(GenericContextDescriptorHeader);
unsigned inPlaceInitSize = 0;
bool hasVTable = false; bool hasVTable = false;
switch (auto kind = flags.getKind()) { switch (auto kind = flags.getKind()) {
case ContextDescriptorKind::Module: case ContextDescriptorKind::Module:
@@ -1067,16 +1069,23 @@ private:
case ContextDescriptorKind::Class: case ContextDescriptorKind::Class:
baseSize = sizeof(TargetClassDescriptor<Runtime>); baseSize = sizeof(TargetClassDescriptor<Runtime>);
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
hasVTable = TypeContextDescriptorFlags(flags.getKindSpecificFlags()) hasVTable = typeFlags.class_hasVTable();
.class_hasVTable();
break; break;
case ContextDescriptorKind::Enum: case ContextDescriptorKind::Enum:
baseSize = sizeof(TargetEnumDescriptor<Runtime>); baseSize = sizeof(TargetEnumDescriptor<Runtime>);
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
if (typeFlags.hasInPlaceMetadataInitialization()) {
inPlaceInitSize =
sizeof(TargetInPlaceValueMetadataInitialization<Runtime>);
}
break; break;
case ContextDescriptorKind::Struct: case ContextDescriptorKind::Struct:
baseSize = sizeof(TargetStructDescriptor<Runtime>); baseSize = sizeof(TargetStructDescriptor<Runtime>);
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
if (typeFlags.hasInPlaceMetadataInitialization()) {
inPlaceInitSize =
sizeof(TargetInPlaceValueMetadataInitialization<Runtime>);
}
break; break;
case ContextDescriptorKind::Protocol: case ContextDescriptorKind::Protocol:
baseSize = sizeof(TargetProtocolDescriptorRef<Runtime>); baseSize = sizeof(TargetProtocolDescriptorRef<Runtime>);
@@ -1122,7 +1131,7 @@ private:
+ header.VTableSize * sizeof(TargetMethodDescriptor<Runtime>); + header.VTableSize * sizeof(TargetMethodDescriptor<Runtime>);
} }
unsigned size = baseSize + genericsSize + vtableSize; unsigned size = baseSize + genericsSize + vtableSize + inPlaceInitSize;
auto buffer = (uint8_t *)malloc(size); auto buffer = (uint8_t *)malloc(size);
if (!Reader->readBytes(RemoteAddress(address), buffer, size)) { if (!Reader->readBytes(RemoteAddress(address), buffer, size)) {
free(buffer); free(buffer);

View File

@@ -335,6 +335,13 @@ ClassMetadataBounds getResilientMetadataBounds(
const ClassDescriptor *descriptor); const ClassDescriptor *descriptor);
int32_t getResilientImmediateMembersOffset(const ClassDescriptor *descriptor); int32_t getResilientImmediateMembersOffset(const ClassDescriptor *descriptor);
/// \brief Fetch a uniqued metadata object for a nominal type which requires
/// in-place metadata initialization.
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
MetadataResponse
swift_getInPlaceMetadata(MetadataRequest request,
const TypeContextDescriptor *description);
/// \brief Fetch a uniqued metadata object for a generic nominal type. /// \brief Fetch a uniqued metadata object for a generic nominal type.
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
MetadataResponse MetadataResponse

View File

@@ -653,6 +653,13 @@ FUNCTION(GetForeignWitnessTable, swift_getForeignWitnessTable, C_CC,
ProtocolDescriptorPtrTy), ProtocolDescriptorPtrTy),
ATTRS(NoUnwind, ReadNone)) ATTRS(NoUnwind, ReadNone))
// MetadataResponse swift_getInPlaceMetadata(MetadataRequest request,
// TypeContextDescriptor *type);
FUNCTION(GetInPlaceMetadata, swift_getInPlaceMetadata, SwiftCC,
RETURNS(TypeMetadataResponseTy),
ARGS(SizeTy, TypeContextDescriptorPtrTy),
ATTRS(NoUnwind, ReadNone))
// MetadataResponse swift_getGenericMetadata(MetadataRequest request, // MetadataResponse swift_getGenericMetadata(MetadataRequest request,
// const void * const *arguments, // const void * const *arguments,
// TypeContextDescriptor *type); // TypeContextDescriptor *type);

View File

@@ -175,6 +175,14 @@ areAllTransitiveMetadataComplete_cheap(const Metadata *metadata);
static MetadataDependency static MetadataDependency
checkTransitiveCompleteness(const Metadata *metadata); checkTransitiveCompleteness(const Metadata *metadata);
static PrivateMetadataState inferStateForMetadata(Metadata *metadata) {
if (metadata->getValueWitnesses()->isIncomplete())
return PrivateMetadataState::Abstract;
// TODO: internal vs. external layout-complete?
return PrivateMetadataState::LayoutComplete;
}
namespace { namespace {
struct GenericCacheEntry final : struct GenericCacheEntry final :
VariadicMetadataCacheEntryBase<GenericCacheEntry> { VariadicMetadataCacheEntryBase<GenericCacheEntry> {
@@ -212,14 +220,6 @@ namespace {
return { metadata, state }; return { metadata, state };
} }
PrivateMetadataState inferStateForMetadata(Metadata *metadata) {
if (metadata->getValueWitnesses()->isIncomplete())
return PrivateMetadataState::Abstract;
// TODO: internal vs. external layout-complete?
return PrivateMetadataState::LayoutComplete;
}
static const TypeContextDescriptor *getDescription(Metadata *type) { static const TypeContextDescriptor *getDescription(Metadata *type) {
if (auto classType = dyn_cast<ClassMetadata>(type)) if (auto classType = dyn_cast<ClassMetadata>(type))
return classType->getDescription(); return classType->getDescription();
@@ -533,6 +533,169 @@ swift::swift_getGenericMetadata(MetadataRequest request,
return result.second; return result.second;
} }
/***************************************************************************/
/*** In-place metadata initialization **************************************/
/***************************************************************************/
namespace {
/// A cache entry for "in-place" metadata initializations.
class InPlaceMetadataCacheEntry final
: public MetadataCacheEntryBase<InPlaceMetadataCacheEntry, int> {
ValueType Value = nullptr;
friend MetadataCacheEntryBase;
ValueType getValue() {
return Value;
}
void setValue(ValueType value) {
Value = value;
}
public:
// We have to give MetadataCacheEntryBase a non-empty list of trailing
// objects or else it gets annoyed.
static size_t numTrailingObjects(OverloadToken<int>) { return 0; }
static const char *getName() { return "InPlaceMetadataCache"; }
InPlaceMetadataCacheEntry() {}
AllocationResult allocate(const TypeContextDescriptor *description) {
auto valueTypeDescriptor = cast<ValueTypeDescriptor>(description);
auto &initialization =
valueTypeDescriptor->getInPlaceMetadataInitialization();
auto metadata = initialization.IncompleteMetadata.get();
auto state = inferStateForMetadata(metadata);
return { metadata, state };
}
static const TypeContextDescriptor *getDescription(Metadata *type) {
return cast<ValueMetadata>(type)->getDescription();
}
TryInitializeResult tryInitialize(Metadata *metadata,
PrivateMetadataState state,
PrivateMetadataCompletionContext *context) {
assert(state != PrivateMetadataState::Complete);
// Finish the completion function.
if (state < PrivateMetadataState::NonTransitiveComplete) {
// Find a pattern. Currently we always use the default pattern.
auto &initialization =
cast<ValueMetadata>(metadata)->getDescription()
->getInPlaceMetadataInitialization();
// Complete the metadata's instantiation.
auto dependency =
initialization.CompletionFunction(metadata, &context->Public,
/*pattern*/ nullptr);
// If this failed with a dependency, infer the current metadata state
// and return.
if (dependency) {
return { inferStateForMetadata(metadata), dependency };
}
}
// Check for transitive completeness.
if (auto dependency = checkTransitiveCompleteness(metadata)) {
return { PrivateMetadataState::NonTransitiveComplete, dependency };
}
// We're done.
publishCompleteMetadata(metadata);
return { PrivateMetadataState::Complete, MetadataDependency() };
}
void publishCompleteMetadata(Metadata *metadata) {
auto &init = cast<ValueMetadata>(metadata)->getDescription()
->getInPlaceMetadataInitialization();
auto &cache = *init.InitializationCache.get();
cache.Metadata.store(metadata, std::memory_order_release);
}
};
/// An implementation of LockingConcurrentMapStorage that's more
/// appropriate for the in-place metadata cache.
///
/// TODO: delete the cache entry when initialization is complete.
class InPlaceMetadataCacheStorage {
ConcurrencyControl Concurrency;
public:
using KeyType = const TypeContextDescriptor *;
using EntryType = InPlaceMetadataCacheEntry;
ConcurrencyControl &getConcurrency() { return Concurrency; }
template <class... ArgTys>
std::pair<EntryType*, bool>
getOrInsert(KeyType key, ArgTys &&...args) {
auto &init =
cast<ValueTypeDescriptor>(key)->getInPlaceMetadataInitialization();
auto &cache = *init.InitializationCache.get();
// Check for an existing entry.
auto existingEntry = cache.Private.load(std::memory_order_acquire);
// If there isn't one there, optimistically create an entry and
// try to swap it in.
if (!existingEntry) {
auto allocatedEntry = new InPlaceMetadataCacheEntry();
if (cache.Private.compare_exchange_strong(existingEntry,
allocatedEntry,
std::memory_order_acq_rel,
std::memory_order_acquire)) {
// If that succeeded, return the entry we allocated and tell the
// caller we allocated it.
return { allocatedEntry, true };
}
// Otherwise, use the new entry and destroy the one we allocated.
assert(existingEntry && "spurious failure of strong compare-exchange?");
delete allocatedEntry;
}
return { static_cast<InPlaceMetadataCacheEntry*>(existingEntry), false };
}
EntryType *find(KeyType key) {
auto &init =
cast<ValueTypeDescriptor>(key)->getInPlaceMetadataInitialization();
return static_cast<InPlaceMetadataCacheEntry*>(
init.InitializationCache->Private.load(std::memory_order_acquire));
}
/// A default implementation for resolveEntry that assumes that the
/// key type is a lookup key for the map.
EntryType *resolveExistingEntry(KeyType key) {
auto entry = find(key);
assert(entry && "entry doesn't already exist!");
return entry;
}
};
class InPlaceMetadataCache
: public LockingConcurrentMap<InPlaceMetadataCacheEntry,
InPlaceMetadataCacheStorage> {
};
} // end anonymous namespace
/// The cache of all in-place metadata initializations.
static Lazy<InPlaceMetadataCache> InPlaceMetadata;
MetadataResponse
swift::swift_getInPlaceMetadata(MetadataRequest request,
const TypeContextDescriptor *description) {
auto result = InPlaceMetadata.get().getOrInsert(description, request,
description);
return result.second;
}
/***************************************************************************/ /***************************************************************************/
/*** Objective-C class wrappers ********************************************/ /*** Objective-C class wrappers ********************************************/
/***************************************************************************/ /***************************************************************************/
@@ -3470,6 +3633,10 @@ static Result performOnMetadataCache(const Metadata *metadata,
} }
if (!description->isGeneric()) { if (!description->isGeneric()) {
if (description->hasInPlaceMetadataInitialization()) {
return std::move(callbacks).forInPlaceMetadata(description);
}
return std::move(callbacks).forOtherMetadata(metadata); return std::move(callbacks).forOtherMetadata(metadata);
} }
@@ -3498,6 +3665,10 @@ bool swift::addToMetadataQueue(MetadataCompletionQueueEntry *queueEntry,
return cache.enqueue(key, QueueEntry, Dependency); return cache.enqueue(key, QueueEntry, Dependency);
} }
bool forInPlaceMetadata(const TypeContextDescriptor *description) && {
return InPlaceMetadata.get().enqueue(description, QueueEntry, Dependency);
}
bool forTupleMetadata(const TupleTypeMetadata *metadata) { bool forTupleMetadata(const TupleTypeMetadata *metadata) {
return TupleTypes.get().enqueue(metadata, QueueEntry, Dependency); return TupleTypes.get().enqueue(metadata, QueueEntry, Dependency);
} }
@@ -3521,6 +3692,10 @@ void swift::resumeMetadataCompletion(MetadataCompletionQueueEntry *queueEntry) {
cache.resumeInitialization(key, QueueEntry); cache.resumeInitialization(key, QueueEntry);
} }
void forInPlaceMetadata(const TypeContextDescriptor *description) && {
InPlaceMetadata.get().resumeInitialization(description, QueueEntry);
}
void forTupleMetadata(const TupleTypeMetadata *metadata) { void forTupleMetadata(const TupleTypeMetadata *metadata) {
TupleTypes.get().resumeInitialization(metadata, QueueEntry); TupleTypes.get().resumeInitialization(metadata, QueueEntry);
} }
@@ -3547,6 +3722,11 @@ MetadataResponse swift::swift_checkMetadataState(MetadataRequest request,
return cache.await(key, Request); return cache.await(key, Request);
} }
MetadataResponse forInPlaceMetadata(
const TypeContextDescriptor *description) && {
return InPlaceMetadata.get().await(description, Request);
}
MetadataResponse forTupleMetadata(const TupleTypeMetadata *metadata) { MetadataResponse forTupleMetadata(const TupleTypeMetadata *metadata) {
return TupleTypes.get().await(metadata, Request); return TupleTypes.get().await(metadata, Request);
} }
@@ -3630,6 +3810,11 @@ areAllTransitiveMetadataComplete_cheap(const Metadata *type) {
return true; return true;
} }
bool forInPlaceMetadata(const TypeContextDescriptor *description) && {
// TODO: this could be cheap enough.
return true;
}
bool forTupleMetadata(const TupleTypeMetadata *metadata) { bool forTupleMetadata(const TupleTypeMetadata *metadata) {
// TODO: this could be cheap enough. // TODO: this could be cheap enough.
return true; return true;
@@ -3787,6 +3972,11 @@ checkMetadataDependency(MetadataDependency dependency) {
return cache.checkDependency(key, Requirement); return cache.checkDependency(key, Requirement);
} }
MetadataDependency forInPlaceMetadata(
const TypeContextDescriptor *description) && {
return InPlaceMetadata.get().checkDependency(description, Requirement);
}
MetadataDependency forTupleMetadata(const TupleTypeMetadata *metadata) { MetadataDependency forTupleMetadata(const TupleTypeMetadata *metadata) {
return TupleTypes.get().checkDependency(metadata, Requirement); return TupleTypes.get().checkDependency(metadata, Requirement);
} }