Skip to content

Add a -reflection-metadata-for-debugger-only flag that emits reflection metadata but does not link them from runtime data structures #40853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -419,7 +426,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),
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down
7 changes: 6 additions & 1 deletion lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
11 changes: 7 additions & 4 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
15 changes: 10 additions & 5 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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))
Expand All @@ -1369,7 +1374,7 @@ emitAssociatedTypeMetadataRecord(const RootProtocolConformance *conformance) {
if (!normalConf)
return;

if (!IRGen.Opts.EnableReflectionMetadata)
if (IRGen.Opts.ReflectionMetadata != ReflectionMetadataMode::Runtime)
return;

SmallVector<std::pair<StringRef, CanType>, 2> AssociatedTypes;
Expand Down Expand Up @@ -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();
Expand Down
41 changes: 41 additions & 0 deletions test/IRGen/reflection-metadata-for-debugger-only.swift
Original file line number Diff line number Diff line change
@@ -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<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() }
}

// 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"