diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 46aa62cf2c4a6..ac13b2e983978 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -87,6 +87,13 @@ enum class SwiftAsyncFramePointerKind : unsigned { Never, // Don't emit Swift async extended frame info. }; +enum class ReflectionMetadataMode : unsigned { + None, ///< Don't emit reflection metadata at all. + DebuggerOnly, ///< Emit reflection metadata for the debugger, don't link them + /// into runtime metadata and don't force them to stay alive. + Runtime, ///< Make reflection metadata fully available. +}; + using clang::PointerAuthSchema; struct PointerAuthOptions : clang::PointerAuthOptions { @@ -295,7 +302,7 @@ class IRGenOptions { unsigned ValueNames : 1; /// Emit nominal type field metadata. - unsigned EnableReflectionMetadata : 1; + ReflectionMetadataMode ReflectionMetadata : 2; /// Emit names of struct stored properties and enum cases. unsigned EnableReflectionNames : 1; @@ -423,7 +430,7 @@ class IRGenOptions { LLVMLTOKind(IRGenLLVMLTOKind::None), SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Auto), HasValueNamesSetting(false), - ValueNames(false), EnableReflectionMetadata(true), + ValueNames(false), ReflectionMetadata(ReflectionMetadataMode::Runtime), EnableReflectionNames(true), EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false), LazyInitializeClassMetadata(false), LazyInitializeProtocolConformances(false), diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 1bb7bd9a6bf2a..bf0c1414ee6ee 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -455,6 +455,9 @@ def enable_anonymous_context_mangled_names : def disable_reflection_metadata : Flag<["-"], "disable-reflection-metadata">, HelpText<"Disable emission of reflection metadata for nominal types">; +def reflection_metadata_for_debugger_only : Flag<["-"], "reflection-metadata-for-debugger-only">, + HelpText<"Emit reflection metadata for debugger only, don't make them available at runtime">; + def disable_reflection_names : Flag<["-"], "disable-reflection-names">, HelpText<"Disable emission of names of stored properties and enum cases in" "reflection metadata">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 6c580fdfc5ac9..5afae9b3588b1 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2043,10 +2043,15 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, } if (Args.hasArg(OPT_disable_reflection_metadata)) { - Opts.EnableReflectionMetadata = false; + Opts.ReflectionMetadata = ReflectionMetadataMode::None; Opts.EnableReflectionNames = false; } + if (Args.hasArg(OPT_reflection_metadata_for_debugger_only)) { + Opts.ReflectionMetadata = ReflectionMetadataMode::DebuggerOnly; + Opts.EnableReflectionNames = true; + } + if (Args.hasArg(OPT_enable_anonymous_context_mangled_names)) Opts.EnableAnonymousContextMangledNames = true; diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 58acb6e948c85..bea6fe9941c3a 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1488,11 +1488,12 @@ namespace { void maybeAddResilientSuperclass() { } void addReflectionFieldDescriptor() { - if (!IGM.IRGen.Opts.EnableReflectionMetadata) { + if (IGM.IRGen.Opts.ReflectionMetadata != + ReflectionMetadataMode::Runtime) { B.addInt32(0); return; } - + IGM.IRGen.noteUseOfFieldDescriptor(getType()); B.addRelativeAddress(IGM.getAddrOfReflectionFieldDescriptor( @@ -1566,7 +1567,8 @@ namespace { void maybeAddResilientSuperclass() { } void addReflectionFieldDescriptor() { - if (!IGM.IRGen.Opts.EnableReflectionMetadata) { + if (IGM.IRGen.Opts.ReflectionMetadata != + ReflectionMetadataMode::Runtime) { B.addInt32(0); return; } @@ -1723,7 +1725,8 @@ namespace { void addReflectionFieldDescriptor() { // Classes are always reflectable, unless reflection is disabled or this // is a foreign class. - if (!IGM.IRGen.Opts.EnableReflectionMetadata || + if ((IGM.IRGen.Opts.ReflectionMetadata != + ReflectionMetadataMode::Runtime) || getType()->isForeign()) { B.addInt32(0); return; diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 3dfd08a1a6544..cec71696080bf 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -623,7 +623,12 @@ class ReflectionMetadataBuilder { var->setSection(section); - IGM.addUsedGlobal(var); + // Only mark the reflection record as used when emitting for the runtime. + // In ReflectionMetadataMode::DebuggerOnly mode we want to allow the linker + // to remove/dead-strip these. + if (IGM.IRGen.Opts.ReflectionMetadata == ReflectionMetadataMode::Runtime) { + IGM.addUsedGlobal(var); + } disableAddressSanitizer(IGM, var); @@ -1335,7 +1340,7 @@ llvm::Constant *IRGenModule::getAddrOfFieldName(StringRef Name) { llvm::Constant * IRGenModule::getAddrOfBoxDescriptor(SILType BoxedType, CanGenericSignature genericSig) { - if (!IRGen.Opts.EnableReflectionMetadata) + if (IRGen.Opts.ReflectionMetadata != ReflectionMetadataMode::Runtime) return llvm::Constant::getNullValue(CaptureDescriptorPtrTy); BoxDescriptorBuilder builder(*this, BoxedType, genericSig); @@ -1350,7 +1355,7 @@ IRGenModule::getAddrOfCaptureDescriptor(SILFunction &Caller, CanSILFunctionType SubstCalleeType, SubstitutionMap Subs, const HeapLayout &Layout) { - if (!IRGen.Opts.EnableReflectionMetadata) + if (IRGen.Opts.ReflectionMetadata != ReflectionMetadataMode::Runtime) return llvm::Constant::getNullValue(CaptureDescriptorPtrTy); if (CaptureDescriptorBuilder::hasOpenedExistential(OrigCalleeType, Layout)) @@ -1369,7 +1374,7 @@ emitAssociatedTypeMetadataRecord(const RootProtocolConformance *conformance) { if (!normalConf) return; - if (!IRGen.Opts.EnableReflectionMetadata) + if (IRGen.Opts.ReflectionMetadata != ReflectionMetadataMode::Runtime) return; SmallVector, 2> AssociatedTypes; @@ -1428,7 +1433,7 @@ void IRGenerator::emitBuiltinReflectionMetadata() { } void IRGenModule::emitFieldDescriptor(const NominalTypeDecl *D) { - if (!IRGen.Opts.EnableReflectionMetadata) + if (IRGen.Opts.ReflectionMetadata == ReflectionMetadataMode::None) return; auto T = D->getDeclaredTypeInContext()->getCanonicalType(); diff --git a/test/IRGen/reflection-metadata-for-debugger-only.swift b/test/IRGen/reflection-metadata-for-debugger-only.swift new file mode 100644 index 0000000000000..78774f9ec7bcc --- /dev/null +++ b/test/IRGen/reflection-metadata-for-debugger-only.swift @@ -0,0 +1,41 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -module-name main %s -emit-ir | %FileCheck %s --check-prefix=CHECK-REFL +// RUN: %target-swift-frontend -module-name main %s -emit-ir -reflection-metadata-for-debugger-only | %FileCheck %s --check-prefix=CHECK-REFLDEBUG +// RUN: %target-swift-frontend -module-name main %s -emit-ir -disable-reflection-metadata | %FileCheck %s --check-prefix=CHECK-NOREFL + +public class Generic { + 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: MyProtocol { + func foo() -> T { fatalError() } +} + +// CHECK-REFL: @"$s4main8MyStructVyxGAA0B8ProtocolAAMA" +// CHECK-REFL: @"$s4main7GenericCMn" = {{.*}} @"$s4main7GenericCMF" {{.*}} +// CHECK-REFL: @"$s4main7GenericCMF" = +// CHECK-REFL: @"$s4main10MyProtocol_pMF" = +// CHECK-REFL: @"$s4main8MyStructVMn" = {{.*}} @"$s4main8MyStructVMF" {{.*}} +// CHECK-REFL: @"$s4main8MyStructVMF" = + +// CHECK-REFLDEBUG-NOT: @"$s4main8MyStructVyxGAA0B8ProtocolAAMA" +// CHECK-REFLDEBUG: @"$s4main7GenericCMn" = +// CHECK-REFLDEBUG-NOT: @"$s4main7GenericCMF" +// CHECK-REFLDEBUG-SAME: , align 4 +// CHECK-REFLDEBUG: @"$s4main7GenericCMF" = +// CHECK-REFLDEBUG: @"$s4main10MyProtocol_pMF" = +// CHECK-REFLDEBUG: @"$s4main8MyStructVMn" = +// CHECK-REFLDEBUG-NOT: @"$s4main8MyStructVMF" +// CHECK-REFLDEBUG-SAME: , align 4 +// CHECK-REFLDEBUG: @"$s4main8MyStructVMF" = + +// CHECK-NOREFL-NOT: @"$s4main8MyStructVyxGAA0B8ProtocolAAMA" +// CHECK-NOREFL-NOT: @"$s4main10MyProtocol_pMF" +// CHECK-NOREFL-NOT: @"$s4main7GenericCMF" +// CHECK-NOREFL-NOT: @"$s4main8MyStructVMF"