Skip to content

Commit 9655803

Browse files
committed
[SILGen] Disable swift_willThrow(Typed) call in functions that cannot allocate
Prior to throwing, Swift emits a call to `swift_willThrow(Typed)`, which allows various diagnostic tools (such as debuggers and testing libraries) to intercept errors at the point where they are initially thrown. Since `swift_willThrow(Typed)` can be hooked by arbitrary code at runtime, there is no way for it to meet performance constraints like @_noLocks or @_noAllocation. Therefore, in a function that has those performance constraints specified, disable emission of the call to `swift_willThrow(Typed)`. Fixes rdar://140230684.
1 parent 3cd48ec commit 9655803

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

lib/SILGen/SILGenStmt.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,24 @@ SILGenFunction::getTryApplyErrorDest(SILLocation loc,
15311531
return destBB;
15321532
}
15331533

1534+
/// Determine whether the given performance constraints allow the emission of
1535+
/// the willThrow call, which can be dynamically hooked to allocate memory.
1536+
static bool performanceConstraintsAllowWillThrow(
1537+
PerformanceConstraints perfConstraints
1538+
) {
1539+
switch (perfConstraints) {
1540+
case PerformanceConstraints::None:
1541+
return true;
1542+
1543+
case PerformanceConstraints::NoAllocation:
1544+
case PerformanceConstraints::NoLocks:
1545+
case PerformanceConstraints::NoRuntime:
1546+
case PerformanceConstraints::NoExistentials:
1547+
case PerformanceConstraints::NoObjCBridging:
1548+
return false;
1549+
}
1550+
}
1551+
15341552
void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
15351553
bool emitWillThrow) {
15361554
assert(ThrowDest.isValid() &&
@@ -1566,7 +1584,8 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
15661584
bool isExistentialBox = exnMV.getType() == existentialBoxType;
15671585

15681586
// If we are supposed to emit a call to swift_willThrow(Typed), do so now.
1569-
if (emitWillThrow) {
1587+
if (emitWillThrow &&
1588+
performanceConstraintsAllowWillThrow(F.getPerfConstraints())) {
15701589
ASTContext &ctx = SGM.getASTContext();
15711590
if (isExistentialBox) {
15721591
// Generate a call to the 'swift_willThrow' runtime function to allow the

test/SILGen/typed_throws.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ func throwsConcrete() throws(MyError) {
2727
throw .fail
2828
}
2929

30+
// CHECK-LABEL: sil hidden [no_locks] [ossa] @$s12typed_throws0B25ConcreteWithoutAllocatingyyAA7MyErrorOYKF : $@convention(thin) () -> @error MyError
31+
@_noLocks
32+
func throwsConcreteWithoutAllocating() throws(MyError) {
33+
// CHECK-NOT: swift_willThrowTyped
34+
// CHECK: throw [[ERROR:%.*]] : $MyError
35+
// CHECK: return
36+
throw .fail
37+
}
38+
3039
class ClassError: Error { }
3140

3241
// CHECK-LABEL: sil hidden [ossa] @$s12typed_throws0B10ClassErroryyAA0cD0CYKF : $@convention(thin) () -> @error ClassError

test/SILOptimizer/performance-annotations.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,29 @@ func testCatch(_ b: Bool) throws -> Int? {
125125
}
126126
}
127127

128+
enum ErrorEnum: Error {
129+
case failed
130+
case tryAgain
131+
}
132+
133+
@_noLocks
134+
func concreteError(_ b: Bool) throws(ErrorEnum) -> Int {
135+
if b {
136+
return 28
137+
}
138+
139+
throw .tryAgain
140+
}
141+
142+
@_noLocks
143+
func testCatchConcrete(_ b: Bool) -> Int {
144+
do {
145+
return try concreteError(b)
146+
} catch {
147+
return 17
148+
}
149+
}
150+
128151
@_noLocks
129152
func testRecursion(_ i: Int) -> Int {
130153
if i > 0 {

0 commit comments

Comments
 (0)