mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
140 lines
5.3 KiB
C++
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
|