Skip to content

Commit 55633e8

Browse files
committed
IRGen: New way of bypassing resilience for LLDB
When running Swift from within LLDB, we need to bypass resilience since LLDB does not support resilience yet. However, the bypass was done too early as part of the module loader, which had the effect of disabling resilience altogether. We still want resilience at the SIL level so that function types lower the same with debugger support turned on and off. Only IRGen needs to bypass resilience, so that LLDB can calculate fragile layouts of types. Also, the DebuggerSupport flag is not always set in the ASTContexts created by LLDB. So replace it with a new flag that only controls this behavior and nothing else, and make it part of IRGenOptions to make it totally clear that it only impacts IRGen. Together with the paired LLDB change, fixes <rdar://problem/38719739> and <rdar://problem/38483762>.
1 parent f1076fd commit 55633e8

File tree

8 files changed

+57
-26
lines changed

8 files changed

+57
-26
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class IRGenOptions {
152152
/// Enables resilient class layout.
153153
unsigned EnableClassResilience : 1;
154154

155+
/// Bypass resilience when accessing resilient frameworks.
156+
unsigned EnableResilienceBypass : 1;
157+
155158
/// Should we try to build incrementally by not emitting an object file if it
156159
/// has the same IR hash as the module that we are preparing to emit?
157160
///
@@ -185,8 +188,8 @@ class IRGenOptions {
185188
EmbedMode(IRGenEmbedMode::None), HasValueNamesSetting(false),
186189
ValueNames(false), EnableReflectionMetadata(true),
187190
EnableReflectionNames(true), EnableClassResilience(false),
188-
UseIncrementalLLVMCodeGen(true), UseSwiftCall(false),
189-
GenerateProfile(false), CmdArgs(),
191+
EnableResilienceBypass(false), UseIncrementalLLVMCodeGen(true),
192+
UseSwiftCall(false), GenerateProfile(false), CmdArgs(),
190193
SanitizeCoverage(llvm::SanitizerCoverageOptions()) {}
191194

192195
// Get a hash of all options which influence the llvm compilation but are not

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ def enable_resilience : Flag<["-"], "enable-resilience">,
450450
def enable_class_resilience : Flag<["-"], "enable-class-resilience">,
451451
HelpText<"Enable resilient layout for classes containing resilient value types">;
452452

453+
def enable_resilience_bypass : Flag<["-"], "enable-resilience-bypass">,
454+
HelpText<"Completely bypass resilience when accessing types in resilient frameworks">;
455+
453456
def group_info_path : Separate<["-"], "group-info-path">,
454457
HelpText<"The path to collect the group information of the compiled module">;
455458

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
903903
Opts.EnableClassResilience = true;
904904
}
905905

906+
if (Args.hasArg(OPT_enable_resilience_bypass)) {
907+
Opts.EnableResilienceBypass = true;
908+
}
909+
906910
for (const auto &Lib : Args.getAllArgValues(options::OPT_autolink_library))
907911
Opts.LinkLibraries.push_back(LinkLibrary(Lib, LibraryKind::Library));
908912

lib/IRGen/GenType.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,15 @@ static ProtocolInfo *invalidProtocolInfo() { return (ProtocolInfo*) 1; }
10641064
TypeConverter::TypeConverter(IRGenModule &IGM)
10651065
: IGM(IGM),
10661066
FirstType(invalidTypeInfo()),
1067-
FirstProtocol(invalidProtocolInfo()) {}
1067+
FirstProtocol(invalidProtocolInfo()) {
1068+
// FIXME: In LLDB, everything is completely fragile, so that IRGen can query
1069+
// the size of resilient types. Of course this is not the right long term
1070+
// solution, because it won't work once the swiftmodule file is not in
1071+
// sync with the binary module. Once LLDB can calculate type layouts at
1072+
// runtime (using remote mirrors or some other mechanism), we can remove this.
1073+
if (IGM.IRGen.Opts.EnableResilienceBypass)
1074+
CompletelyFragile = true;
1075+
}
10681076

10691077
TypeConverter::~TypeConverter() {
10701078
// Delete all the converted type infos.

lib/IRGen/GenType.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,17 +222,21 @@ class GenericContextScope {
222222

223223
/// An RAII interface for forcing types to be lowered bypassing resilience.
224224
class CompletelyFragileScope {
225+
bool State;
225226
TypeConverter &TC;
226227
public:
227228
CompletelyFragileScope(TypeConverter &TC) : TC(TC) {
228-
TC.pushCompletelyFragile();
229+
State = TC.isCompletelyFragile();
230+
if (!State)
231+
TC.pushCompletelyFragile();
229232
}
230233

231234
CompletelyFragileScope(IRGenModule &IGM)
232235
: CompletelyFragileScope(IGM.Types) {}
233236

234237
~CompletelyFragileScope() {
235-
TC.popCompletelyFragile();
238+
if (!State)
239+
TC.popCompletelyFragile();
236240
}
237241
};
238242

lib/RemoteAST/RemoteAST.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,19 @@ struct IRGenContext {
6565

6666
private:
6767
IRGenContext(ASTContext &ctx, ModuleDecl *module)
68-
: SILMod(SILModule::createEmptyModule(module, SILOpts)),
68+
: IROpts(createIRGenOptions()),
69+
SILMod(SILModule::createEmptyModule(module, SILOpts)),
6970
IRGen(IROpts, *SILMod),
7071
IGM(IRGen, IRGen.createTargetMachine(), /*SourceFile*/ nullptr,
7172
LLVMContext, "<fake module name>", "<fake output filename>",
7273
"<fake main input filename>") {}
7374

75+
static IRGenOptions createIRGenOptions() {
76+
IRGenOptions IROpts;
77+
IROpts.EnableResilienceBypass = true;
78+
return IROpts;
79+
}
80+
7481
public:
7582
static std::unique_ptr<IRGenContext>
7683
create(ASTContext &ctx, DeclContext *nominalDC) {

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,7 @@ FileUnit *SerializedModuleLoader::loadAST(
200200
isFramework, loadedModuleFile,
201201
&extendedInfo);
202202
if (loadInfo.status == serialization::Status::Valid) {
203-
// In LLDB always use the default resilience strategy, so IRGen can query
204-
// the size of resilient types.
205-
if (!Ctx.LangOpts.DebuggerSupport)
206-
M.setResilienceStrategy(extendedInfo.getResilienceStrategy());
203+
M.setResilienceStrategy(extendedInfo.getResilienceStrategy());
207204

208205
// We've loaded the file. Now try to bring it into the AST.
209206
auto fileUnit = new (Ctx) SerializedASTFile(M, *loadedModuleFile,

test/DebugInfo/resilience.swift

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,36 @@
99
// RUN: %target-swift-frontend -g -I %t -emit-ir -enable-resilience %s -o - \
1010
// RUN: | %FileCheck %s
1111
//
12-
// RUN: %target-swift-frontend -g -I %t -emit-sil -enable-resilience %s -o - \
13-
// RUN: | %FileCheck %s --check-prefix=CHECK-SIL
14-
// RUN: %target-swift-frontend -g -I %t -emit-sil -enable-resilience %s -o - \
15-
// RUN: -debugger-support | %FileCheck %s --check-prefix=CHECK-LLDB
12+
// RUN: %target-swift-frontend -g -I %t -emit-ir -enable-resilience %s -o - \
13+
// RUN: -enable-resilience-bypass | %FileCheck %s --check-prefix=CHECK-LLDB
1614
import resilient_struct
1715

18-
func use<T>(_ t: T) {}
19-
16+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S10resilience1fyyF"()
17+
// CHECK-LLDB-LABEL: define{{( protected)?}} swiftcc void @"$S10resilience1fyyF"()
2018
public func f() {
2119
let s1 = Size(w: 1, h: 2)
22-
use(s1)
20+
takesSize(s1)
2321
// CHECK: %[[ADDR:.*]] = alloca i8*
2422
// CHECK: call void @llvm.dbg.declare(metadata i8** %[[ADDR]],
2523
// CHECK-SAME: metadata ![[V1:[0-9]+]],
2624
// CHECK-SAME: metadata !DIExpression(DW_OP_deref))
2725
// CHECK: %[[S1:.*]] = alloca i8,
2826
// CHECK: store i8* %[[S1]], i8** %[[ADDR]]
29-
// CHECK: ![[V1]] = !DILocalVariable(name: "s1", {{.*}}type: ![[TY:[0-9]+]])
30-
// CHECK: ![[TY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Size",
31-
// FIXME-NOT: size:
32-
// CHECK: =
27+
28+
// CHECK-LLDB: %[[ADDR:.*]] = alloca %T16resilient_struct4SizeV
29+
// CHECK-LLDB: call void @llvm.dbg.declare(metadata %T16resilient_struct4SizeV* %[[ADDR]],
30+
// CHECK-LLDB-SAME: metadata ![[V1:[0-9]+]],
31+
// CHECK-LLDB-SAME: metadata !DIExpression())
3332
}
3433

35-
// CHECK-SIL: // f()
36-
// CHECK-LLDB: // f()
37-
// CHECK-SIL: %0 = alloc_stack $Size, let, name "s1"
38-
// CHECK-LLDB: %0 = metatype $@thin Size.Type
39-
// CHECK-LLDB: debug_value %{{.*}} : $Size, let, name "s1"
34+
35+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S10resilience9takesSizeyy16resilient_struct0C0VF"(%swift.opaque* noalias nocapture)
36+
// CHECK-LLDB-LABEL: define{{( protected)?}} swiftcc void @"$S10resilience9takesSizeyy16resilient_struct0C0VF"(%T16resilient_struct4SizeV* noalias nocapture dereferenceable({{8|16}}))
37+
public func takesSize(_ s: Size) {}
38+
39+
40+
// CHECK: ![[V1]] = !DILocalVariable(name: "s1", {{.*}}type: ![[TY:[0-9]+]])
41+
// CHECK: ![[TY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Size",
42+
43+
// CHECK-LLDB: ![[V1]] = !DILocalVariable(name: "s1", {{.*}}type: ![[TY:[0-9]+]])
44+
// CHECK-LLDB: ![[TY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Size",

0 commit comments

Comments
 (0)