mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Add a flag to disable compile-time preallocated instantiation caches (for type metadata and protocol conformances) (#41148)
This commit is contained in:
committed by
GitHub
parent
f05f23147f
commit
17c5d6f0de
@@ -370,6 +370,10 @@ public:
|
||||
|
||||
unsigned InternalizeAtLink : 1;
|
||||
|
||||
/// Whether to avoid emitting zerofill globals as preallocated type metadata
|
||||
/// and prototol conformance caches.
|
||||
unsigned NoPreallocatedInstantiationCaches : 1;
|
||||
|
||||
/// The number of threads for multi-threaded code generation.
|
||||
unsigned NumThreads = 0;
|
||||
|
||||
@@ -433,6 +437,7 @@ public:
|
||||
EnableGlobalISel(false), VirtualFunctionElimination(false),
|
||||
WitnessMethodElimination(false), ConditionalRuntimeRecords(false),
|
||||
InternalizeAtLink(false),
|
||||
NoPreallocatedInstantiationCaches(false),
|
||||
CmdArgs(),
|
||||
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
|
||||
TypeInfoFilter(TypeInfoDumpFilter::All) {}
|
||||
|
||||
@@ -579,6 +579,10 @@ def conditional_runtime_records : Flag<["-"], "conditional-runtime-records">,
|
||||
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
|
||||
HelpText<"Allow removal of runtime metadata records (public types, protocol conformances) based on whether they're used or unused">;
|
||||
|
||||
def disable_preallocated_instantiation_caches : Flag<["-"], "disable-preallocated-instantiation-caches">,
|
||||
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
|
||||
HelpText<"Avoid preallocating metadata instantiation caches in globals">;
|
||||
|
||||
def disable_previous_implementation_calls_in_dynamic_replacements :
|
||||
Flag<["-"], "disable-previous-implementation-calls-in-dynamic-replacements">,
|
||||
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
|
||||
|
||||
@@ -2182,6 +2182,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
|
||||
Opts.InternalizeAtLink = true;
|
||||
}
|
||||
|
||||
if (Args.hasArg(OPT_disable_preallocated_instantiation_caches)) {
|
||||
Opts.NoPreallocatedInstantiationCaches = true;
|
||||
}
|
||||
|
||||
// Default to disabling swift async extended frame info on anything but
|
||||
// darwin. Other platforms are unlikely to have support for extended frame
|
||||
// pointer information.
|
||||
|
||||
@@ -1267,7 +1267,7 @@ namespace {
|
||||
}
|
||||
|
||||
void addMetadataInstantiationCache() {
|
||||
if (!HasMetadata) {
|
||||
if (!HasMetadata || IGM.getOptions().NoPreallocatedInstantiationCaches) {
|
||||
B.addInt32(0);
|
||||
return;
|
||||
}
|
||||
@@ -2569,6 +2569,8 @@ namespace {
|
||||
|
||||
/// Emit the instantiation cache variable for the template.
|
||||
void emitInstantiationCache() {
|
||||
if (IGM.IRGen.Opts.NoPreallocatedInstantiationCaches) return;
|
||||
|
||||
auto cache = cast<llvm::GlobalVariable>(
|
||||
IGM.getAddrOfTypeMetadataInstantiationCache(Target, ForDefinition));
|
||||
auto init =
|
||||
|
||||
@@ -1978,8 +1978,11 @@ namespace {
|
||||
Description.requiresSpecialization);
|
||||
// Instantiation function
|
||||
B.addRelativeAddressOrNull(Description.instantiationFn);
|
||||
|
||||
// Private data
|
||||
{
|
||||
if (IGM.IRGen.Opts.NoPreallocatedInstantiationCaches) {
|
||||
B.addInt32(0);
|
||||
} else {
|
||||
auto privateDataTy =
|
||||
llvm::ArrayType::get(IGM.Int8PtrTy,
|
||||
swift::NumGenericMetadataPrivateDataWords);
|
||||
|
||||
@@ -389,7 +389,35 @@ namespace {
|
||||
};
|
||||
|
||||
using LazyGenericMetadataCache = Lazy<GenericMetadataCache>;
|
||||
}
|
||||
|
||||
class GlobalMetadataCacheEntry {
|
||||
public:
|
||||
const TypeContextDescriptor *Description;
|
||||
GenericMetadataCache Cache;
|
||||
|
||||
GlobalMetadataCacheEntry(const TypeContextDescriptor *description)
|
||||
: Description(description), Cache(*description->getGenericContext()) {}
|
||||
|
||||
intptr_t getKeyIntValueForDump() {
|
||||
return reinterpret_cast<intptr_t>(Description);
|
||||
}
|
||||
bool matchesKey(const TypeContextDescriptor *description) const {
|
||||
return description == Description;
|
||||
}
|
||||
friend llvm::hash_code hash_value(const GlobalMetadataCacheEntry &value) {
|
||||
return llvm::hash_value(value.Description);
|
||||
}
|
||||
static size_t
|
||||
getExtraAllocationSize(const TypeContextDescriptor *description) {
|
||||
return 0;
|
||||
}
|
||||
size_t getExtraAllocationSize() const { return 0; }
|
||||
};
|
||||
|
||||
static SimpleGlobalCache<GlobalMetadataCacheEntry, GlobalMetadataCacheTag>
|
||||
GlobalMetadataCache;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
/// Fetch the metadata cache for a generic metadata structure.
|
||||
static GenericMetadataCache &getCache(
|
||||
@@ -401,6 +429,11 @@ static GenericMetadataCache &getCache(
|
||||
sizeof(GenericMetadataInstantiationCache::PrivateData),
|
||||
"metadata cache is larger than the allowed space");
|
||||
|
||||
auto *cacheStorage = generics.getInstantiationCache();
|
||||
if (cacheStorage == nullptr) {
|
||||
return GlobalMetadataCache.getOrInsert(&description).first->Cache;
|
||||
}
|
||||
|
||||
auto lazyCache =
|
||||
reinterpret_cast<LazyGenericMetadataCache*>(
|
||||
generics.getInstantiationCache()->PrivateData);
|
||||
@@ -4606,12 +4639,39 @@ public:
|
||||
const void * const *instantiationArgs);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
using GenericWitnessTableCache =
|
||||
MetadataCache<WitnessTableCacheEntry, GenericWitnessTableCacheTag>;
|
||||
using LazyGenericWitnessTableCache = Lazy<GenericWitnessTableCache>;
|
||||
|
||||
class GlobalWitnessTableCacheEntry {
|
||||
public:
|
||||
const GenericWitnessTable *Gen;
|
||||
GenericWitnessTableCache Cache;
|
||||
|
||||
GlobalWitnessTableCacheEntry(const GenericWitnessTable *gen)
|
||||
: Gen(gen), Cache() {}
|
||||
|
||||
intptr_t getKeyIntValueForDump() {
|
||||
return reinterpret_cast<intptr_t>(Gen);
|
||||
}
|
||||
bool matchesKey(const GenericWitnessTable *gen) const {
|
||||
return gen == Gen;
|
||||
}
|
||||
friend llvm::hash_code hash_value(const GlobalWitnessTableCacheEntry &value) {
|
||||
return llvm::hash_value(value.Gen);
|
||||
}
|
||||
static size_t
|
||||
getExtraAllocationSize(const GenericWitnessTable *gen) {
|
||||
return 0;
|
||||
}
|
||||
size_t getExtraAllocationSize() const { return 0; }
|
||||
};
|
||||
|
||||
static SimpleGlobalCache<GlobalWitnessTableCacheEntry, GlobalWitnessTableCacheTag>
|
||||
GlobalWitnessTableCache;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
/// Fetch the cache for a generic witness-table structure.
|
||||
static GenericWitnessTableCache &getCache(const GenericWitnessTable *gen) {
|
||||
// Keep this assert even if you change the representation above.
|
||||
@@ -4619,6 +4679,10 @@ static GenericWitnessTableCache &getCache(const GenericWitnessTable *gen) {
|
||||
sizeof(GenericWitnessTable::PrivateDataType),
|
||||
"metadata cache is larger than the allowed space");
|
||||
|
||||
if (gen->PrivateData == nullptr) {
|
||||
return GlobalWitnessTableCache.getOrInsert(gen).first->Cache;
|
||||
}
|
||||
|
||||
auto lazyCache =
|
||||
reinterpret_cast<LazyGenericWitnessTableCache*>(gen->PrivateData.get());
|
||||
return lazyCache->get();
|
||||
|
||||
@@ -42,5 +42,7 @@ TAG(GenericWitnessTableCache, 16)
|
||||
TAG(GenericClassMetadata, 17)
|
||||
TAG(GenericValueMetadata, 18)
|
||||
TAG(SingletonGenericWitnessTableCache, 19)
|
||||
TAG(GlobalMetadataCache, 20)
|
||||
TAG(GlobalWitnessTableCache, 21)
|
||||
|
||||
#undef TAG
|
||||
|
||||
23
test/IRGen/disable-instantiation-cache-exec.swift
Normal file
23
test/IRGen/disable-instantiation-cache-exec.swift
Normal file
@@ -0,0 +1,23 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-preallocated-instantiation-caches -o %t/a.out
|
||||
// RUN: %target-codesign %t/a.out
|
||||
// RUN: %target-run %t/a.out
|
||||
|
||||
// REQUIRES: executable_test
|
||||
|
||||
public class Generic<T> {
|
||||
public func m1(t: T) -> T { return t }
|
||||
public func m2(t: T) -> T { return t }
|
||||
}
|
||||
|
||||
protocol MyProtocol {
|
||||
associatedtype T
|
||||
func foo() -> T
|
||||
}
|
||||
|
||||
public struct MyStruct<T>: MyProtocol {
|
||||
func foo() -> T { fatalError() }
|
||||
}
|
||||
|
||||
print(Generic<Int>())
|
||||
print(MyStruct<Int>())
|
||||
32
test/IRGen/disable-instantiation-cache.swift
Normal file
32
test/IRGen/disable-instantiation-cache.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -module-name main %s -emit-ir | %FileCheck %s --check-prefix=CHECK-CACHE
|
||||
// RUN: %target-swift-frontend -module-name main %s -emit-ir -disable-preallocated-instantiation-caches | %FileCheck %s --check-prefix=CHECK-NOCACHE
|
||||
|
||||
public class Generic<T> {
|
||||
public func m1(t: T) -> T { return t }
|
||||
public func m2(t: T) -> T { return t }
|
||||
}
|
||||
|
||||
protocol MyProtocol {
|
||||
associatedtype T
|
||||
func foo() -> T
|
||||
}
|
||||
|
||||
public struct MyStruct<T>: MyProtocol {
|
||||
func foo() -> T { fatalError() }
|
||||
}
|
||||
|
||||
// "metadata instantiation cache for protocol conformance descriptor for main.MyStruct<A> : main.MyProtocol in main"
|
||||
// CHECK-CACHE: @"$s4main8MyStructVyxGAA0B8ProtocolAAMcMK" = internal global [{{.*}} x i8*] zeroinitializer
|
||||
// CHECK-CACHE: @"$s4main8MyStructVyxGAA0B8ProtocolAAMc" = {{.*}} @"$s4main8MyStructVyxGAA0B8ProtocolAAMcMK" {{.*}}
|
||||
// CHECK-NOCACHE-NOT: @"$s4main8MyStructVyxGAA0B8ProtocolAAMcMK"
|
||||
|
||||
// "type metadata instantiation cache for main.Generic"
|
||||
// CHECK-CACHE: @"$s4main7GenericCMI" = internal global [{{.*}} x i8*] zeroinitializer
|
||||
// CHECK-CACHE: @"$s4main7GenericCMn" = {{.*}} @"$s4main7GenericCMI" {{.*}}
|
||||
// CHECK-NOCACHE-NOT: @"$s4main7GenericCMI"
|
||||
|
||||
// "type metadata instantiation cache for main.MyStruct"
|
||||
// CHECK-CACHE: @"$s4main8MyStructVMI" = internal global [{{.*}} x i8*] zeroinitializer
|
||||
// CHECK-CACHE: @"$s4main8MyStructVMn" = {{.*}} @"$s4main8MyStructVMI" {{.*}}
|
||||
// CHECK-NOCACHE-NOT: @"$s4main8MyStructVMI"
|
||||
Reference in New Issue
Block a user