Files
swift-mirror/stdlib/public/runtime/GenericCacheEntry.h
Saleem Abdulrasool 0174528f81 stdlib: fix the problem swept under the rug in 58a97f1603
The `-Winvalid-offsetof` warning is valid in this case. `offsetof` is
being applied to types with a non-standard layout. The layout of this
type is undefined by the specification. There is no guarantee that the
type layout is uniform across all ABIs. It is not possible to portably
compute the offset statically, especially efficiently.

Sink this check into a unit test to avoid performing this test at
runtime. In order to do this in the standard library, we would need to
do this check through a global constructor.
2025-02-03 09:25:06 -08:00

140 lines
5.3 KiB
C++

//===--- GenericCacheEntry.h ------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_RUNTIME_GENERICCACHEENTRY_H
#define SWIFT_RUNTIME_GENERICCACHEENTRY_H
#include "MetadataCache.h"
#include "swift/ABI/Metadata.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/Basic/Unreachable.h"
#include "swift/RemoteInspection/GenericMetadataCacheEntry.h"
#include "swift/Runtime/LibPrespecialized.h"
namespace swift {
bool areAllTransitiveMetadataComplete_cheap(const Metadata *type);
PrivateMetadataState inferStateForMetadata(Metadata *metadata);
MetadataDependency checkTransitiveCompleteness(const Metadata *initialType);
struct GenericCacheEntry final
: VariadicMetadataCacheEntryBase<GenericCacheEntry> {
static const char *getName() { return "GenericCache"; }
// The constructor/allocate operations that take a `const Metadata *`
// are used for the insertion of canonical specializations.
// The metadata is always complete after construction.
GenericCacheEntry(MetadataCacheKey key, MetadataWaitQueue::Worker &worker,
MetadataRequest request, const Metadata *candidate)
: VariadicMetadataCacheEntryBase(key, worker,
PrivateMetadataState::Complete,
const_cast<Metadata *>(candidate)) {}
AllocationResult allocate(const Metadata *candidate) {
swift_unreachable("always short-circuited");
}
static bool allowMangledNameVerification(const Metadata *candidate) {
// Disallow mangled name verification for specialized candidates
// because it will trigger recursive entry into the swift_once
// in cacheCanonicalSpecializedMetadata.
// TODO: verify mangled names in a second pass in that function.
return false;
}
// The constructor/allocate operations that take a descriptor
// and arguments are used along the normal allocation path.
GenericCacheEntry(MetadataCacheKey key, MetadataWaitQueue::Worker &worker,
MetadataRequest request,
const TypeContextDescriptor *description,
const void *const *arguments)
: VariadicMetadataCacheEntryBase(key, worker,
PrivateMetadataState::Allocating,
/*candidate*/ nullptr) {}
AllocationResult allocate(const TypeContextDescriptor *description,
const void *const *arguments) {
if (auto *prespecialized =
getLibPrespecializedMetadata(description, arguments))
return {prespecialized, PrivateMetadataState::Complete};
// Find a pattern. Currently we always use the default pattern.
auto &generics = description->getFullGenericContextHeader();
auto pattern = generics.DefaultInstantiationPattern.get();
// Call the pattern's instantiation function.
auto metadata =
pattern->InstantiationFunction(description, arguments, pattern);
// If there's no completion function, do a quick-and-dirty check to
// see if all of the type arguments are already complete. If they
// are, we can broadcast completion immediately and potentially avoid
// some extra locking.
PrivateMetadataState state;
if (pattern->CompletionFunction.isNull()) {
if (areAllTransitiveMetadataComplete_cheap(metadata)) {
state = PrivateMetadataState::Complete;
} else {
state = PrivateMetadataState::NonTransitiveComplete;
}
} else {
state = inferStateForMetadata(metadata);
}
return {metadata, state};
}
static bool
allowMangledNameVerification(const TypeContextDescriptor *description,
const void *const *arguments) {
return true;
}
MetadataStateWithDependency
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 &generics =
metadata->getTypeContextDescriptor()->getFullGenericContextHeader();
auto pattern = generics.DefaultInstantiationPattern.get();
// Complete the metadata's instantiation.
auto dependency =
pattern->CompletionFunction(metadata, &context->Public, pattern);
// 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.
return {PrivateMetadataState::Complete, MetadataDependency()};
}
};
} // namespace swift
#endif