Skip to content

Commit 431007a

Browse files
authored
Merge pull request #58629 from kavon/5.7-proper-fix-for-jump-to-null
[5.7-🍒] Proper fix for ObjC async jump to null
2 parents eea8a9d + 9454d60 commit 431007a

File tree

7 files changed

+81
-35
lines changed

7 files changed

+81
-35
lines changed

lib/SILGen/ExecutorBreadcrumb.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#ifndef SWIFT_SILGEN_EXECUTORBREADCRUMB_H
14+
#define SWIFT_SILGEN_EXECUTORBREADCRUMB_H
15+
1316
#include "swift/SIL/SILValue.h"
1417

1518
namespace swift {
@@ -46,3 +49,5 @@ class ExecutorBreadcrumb {
4649

4750
} // namespace Lowering
4851
} // namespace swift
52+
53+
#endif

lib/SILGen/ResultPlan.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
498498
SILType opaqueResumeType;
499499
SILValue resumeBuf;
500500
SILValue continuation;
501+
ExecutorBreadcrumb breadcrumb;
501502

502503
public:
503504
ForeignAsyncInitializationPlan(SILGenFunction &SGF, SILLocation loc,
@@ -596,6 +597,10 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
596597
return ManagedValue::forUnmanaged(block);
597598
}
598599

600+
void deferExecutorBreadcrumb(ExecutorBreadcrumb &&breadcrumb) override {
601+
this->breadcrumb = breadcrumb;
602+
}
603+
599604
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
600605
ArrayRef<ManagedValue> &directResults,
601606
SILValue bridgedForeignError) override {
@@ -691,6 +696,7 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
691696
// Propagate an error if we have one.
692697
if (errorBlock) {
693698
SGF.B.emitBlock(errorBlock);
699+
breadcrumb.emit(SGF, loc);
694700

695701
Scope errorScope(SGF, loc);
696702

@@ -702,6 +708,7 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
702708
}
703709

704710
SGF.B.emitBlock(resumeBlock);
711+
breadcrumb.emit(SGF, loc);
705712

706713
// The incoming value is the maximally-abstracted result type of the
707714
// continuation. Move it out of the resume buffer and reabstract it if
@@ -771,6 +778,10 @@ class ForeignErrorInitializationPlan final : public ResultPlan {
771778
AbstractionPattern(errorType), errorType);
772779
}
773780

781+
void deferExecutorBreadcrumb(ExecutorBreadcrumb &&breadcrumb) override {
782+
subPlan->deferExecutorBreadcrumb(std::move(breadcrumb));
783+
}
784+
774785
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
775786
ArrayRef<ManagedValue> &directResults,
776787
SILValue bridgedForeignError) override {

lib/SILGen/ResultPlan.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_SILGEN_RESULTPLAN_H
1515

1616
#include "Callee.h"
17+
#include "ExecutorBreadcrumb.h"
1718
#include "ManagedValue.h"
1819
#include "swift/AST/Types.h"
1920
#include "swift/Basic/LLVM.h"
@@ -42,6 +43,11 @@ class ResultPlan {
4243
SILValue bridgedForeignError) = 0;
4344
virtual ~ResultPlan() = default;
4445

46+
/// Defers the emission of the given breadcrumb until \p finish is invoked.
47+
virtual void deferExecutorBreadcrumb(ExecutorBreadcrumb &&breadcrumb) {
48+
llvm_unreachable("this ResultPlan does not handle deferred breadcrumbs!");
49+
}
50+
4551
virtual void
4652
gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
4753
SmallVectorImpl<SILValue> &outList) const = 0;

lib/SILGen/SILGenApply.cpp

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4427,27 +4427,6 @@ class FixLifetimeDestroyCleanup : public Cleanup {
44274427
#endif
44284428
}
44294429
};
4430-
4431-
class EmitBreadcrumbCleanup : public Cleanup {
4432-
ExecutorBreadcrumb breadcrumb;
4433-
4434-
public:
4435-
EmitBreadcrumbCleanup(ExecutorBreadcrumb &&breadcrumb)
4436-
: breadcrumb(std::move(breadcrumb)) {}
4437-
4438-
void emit(SILGenFunction &SGF, CleanupLocation l,
4439-
ForUnwind_t forUnwind) override {
4440-
breadcrumb.emit(SGF, l);
4441-
}
4442-
4443-
void dump(SILGenFunction &SGF) const override {
4444-
#ifndef NDEBUG
4445-
llvm::errs() << "EmitBreadcrumbCleanup "
4446-
<< "State:" << getState()
4447-
<< "NeedsEmit:" << breadcrumb.needsEmit();
4448-
#endif
4449-
}
4450-
};
44514430
} // end anonymous namespace
44524431

44534432
//===----------------------------------------------------------------------===//
@@ -4598,11 +4577,6 @@ RValue SILGenFunction::emitApply(
45984577
rawDirectResult = rawDirectResults[0];
45994578
}
46004579

4601-
if (!calleeTypeInfo.foreign.async) {
4602-
// hop back to the current executor
4603-
breadcrumb.emit(*this, loc);
4604-
}
4605-
46064580
// For objc async calls, lifetime extend the args until the result plan which
46074581
// generates `await_async_continuation`.
46084582
// Lifetime is extended by creating unmanaged copies here and by pushing the
@@ -4614,6 +4588,14 @@ RValue SILGenFunction::emitApply(
46144588
unmanagedCopies.push_back(arg.unmanagedCopy(*this, loc));
46154589
}
46164590
}
4591+
// similarly, we defer the emission of the breadcrumb until the result
4592+
// plan's finish method is called, because it must happen in the
4593+
// successors of the `await_async_continuation` terminator.
4594+
resultPlan->deferExecutorBreadcrumb(std::move(breadcrumb));
4595+
4596+
} else {
4597+
// In the ordinary case, we hop back to the current executor
4598+
breadcrumb.emit(*this, loc);
46174599
}
46184600

46194601
// Pop the argument scope.
@@ -4700,8 +4682,6 @@ RValue SILGenFunction::emitApply(
47004682
for (auto unmanagedCopy : unmanagedCopies) {
47014683
Cleanups.pushCleanup<FixLifetimeDestroyCleanup>(unmanagedCopy);
47024684
}
4703-
// save breadcrumb as a clean-up so it is emitted in result / throw cases.
4704-
Cleanups.pushCleanup<EmitBreadcrumbCleanup>(std::move(breadcrumb));
47054685
} else {
47064686
assert(unmanagedCopies.empty());
47074687
}

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,13 @@ struct StructWithSendableContents {
310310
SENDABLE id StructWithSendableContentsGetSendableComputed(struct StructWithSendableContents contents)
311311
__attribute__((swift_name("getter:StructWithSendableContents.sendableComputed(self:)")));
312312

313+
@interface CostcoManager : NSObject
314+
+ (instancetype)sharedManager;
315+
- (void)isCustomerEnrolledInExecutiveProgram:(NSObject *)customer completion:(void(^)(BOOL enrolled))completion;
316+
@end
317+
318+
@interface Person : NSObject
319+
+ (void)getAsCustomer:(void(^_Nonnull)(NSObject *device))completion;
320+
@end
321+
313322
#pragma clang assume_nonnull end

test/SILGen/objc_async.swift

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func testGeneric2<T: AnyObject, U>(x: GenericObject<T>, y: U) async throws {
177177
// CHECK-LABEL: sil {{.*}}@${{.*}}22testSlowServerFromMain
178178
@MainActor
179179
func testSlowServerFromMain(slowServer: SlowServer) async throws {
180-
// CHECK: hop_to_executor %6 : $MainActor
180+
// CHECK: hop_to_executor {{%.*}} : $MainActor
181181
// CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int
182182
// CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF :
183183
// CHECK: [[ARG:%.*]] = apply [[STRINGINIT]]
@@ -194,8 +194,8 @@ func testSlowServerFromMain(slowServer: SlowServer) async throws {
194194
// CHECK: destroy_value [[ARG]]
195195
// CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]]
196196
// CHECK: [[RESUME]]:
197+
// CHECK: hop_to_executor {{%.*}} : $MainActor
197198
// CHECK: [[RESULT:%.*]] = load [trivial] [[RESUME_BUF]]
198-
// CHECK: hop_to_executor %6 : $MainActor
199199
// CHECK: fix_lifetime [[COPY]]
200200
// CHECK: destroy_value [[COPY]]
201201
// CHECK: dealloc_stack [[RESUME_BUF]]
@@ -223,8 +223,8 @@ func testThrowingMethodFromMain(slowServer: SlowServer) async -> String {
223223
// CHECK: await_async_continuation [[RAW_CONT]] : $Builtin.RawUnsafeContinuation, resume [[RESUME:bb[0-9]+]], error [[ERROR:bb[0-9]+]]
224224

225225
// CHECK: [[RESUME]]
226-
// CHECK: {{.*}} = load [take] [[RESULT_BUF]] : $*String
227226
// CHECK: hop_to_executor {{%.*}} : $MainActor
227+
// CHECK: {{.*}} = load [take] [[RESULT_BUF]] : $*String
228228
// CHECK: fix_lifetime [[STRING_ARG_COPY]] : $NSString
229229
// CHECK: destroy_value [[STRING_ARG_COPY]] : $NSString
230230
// CHECK: dealloc_stack [[RESULT_BUF]] : $*String
@@ -241,3 +241,38 @@ func testThrowingMethodFromMain(slowServer: SlowServer) async -> String {
241241
return "none"
242242
}
243243
}
244+
245+
// rdar://91502776
246+
// CHECK-LABEL: sil hidden [ossa] @$s{{.*}}21checkCostcoMembershipSbyYaF : $@convention(thin) @async () -> Bool {
247+
// CHECK: bb0:
248+
// CHECK: hop_to_executor {{%.*}} : $Optional<Builtin.Executor>
249+
// CHECK: [[FINAL_BUF:%.*]] = alloc_stack $Bool
250+
// CHECK: [[RESULT_BUF:%.*]] = alloc_stack $NSObject
251+
// CHECK: [[METH:%.*]] = objc_method {{%.*}} : $@objc_metatype Person.Type, #Person.asCustomer!foreign
252+
// CHECK: get_async_continuation_addr NSObject, [[RESULT_BUF]] : $*NSObject
253+
// CHECK: = apply [[METH]]
254+
// CHECK: dealloc_stack {{%.*}} : $*@block_storage
255+
// CHECK: await_async_continuation {{%.*}} : $Builtin.RawUnsafeContinuation, resume bb1
256+
// CHECK: bb1:
257+
// CHECK: hop_to_executor {{%.*}} : $Optional<Builtin.Executor>
258+
// CHECK: [[RESULT:%.*]] = load [take] [[RESULT_BUF]] : $*NSObject
259+
// CHECK: objc_method {{%.*}} : $CostcoManager, #CostcoManager.isCustomerEnrolled!foreign
260+
// CHECK: get_async_continuation_addr Bool, [[FINAL_BUF]] : $*Bool
261+
// CHECK: [[BLOCK_ARG:%.*]] = init_block_storage_header [[BLOCK_STORAGE:%.*]] : $*@block_storage
262+
// CHECK: = apply {{%.*}}([[RESULT]], [[BLOCK_ARG]], [[MANAGER:%.*]]) : $@convention(objc_method)
263+
// CHECK: [[EXTEND1:%.*]] = copy_value [[RESULT]] : $NSObject
264+
// CHECK: [[EXTEND2:%.*]] = copy_value [[MANAGER]] : $CostcoManager
265+
// CHECK: dealloc_stack [[BLOCK_STORAGE]] : $*@block_storage
266+
// CHECK: await_async_continuation {{%.*}} : $Builtin.RawUnsafeContinuation, resume bb2
267+
// CHECK: bb2:
268+
// CHECK: hop_to_executor {{%.*}} : $Optional<Builtin.Executor>
269+
// CHECK: [[ANSWER:%.*]] = load [trivial] [[FINAL_BUF]] : $*Bool
270+
// CHECK: fix_lifetime [[EXTEND2]] : $CostcoManager
271+
// CHECK: destroy_value [[EXTEND2]] : $CostcoManager
272+
// CHECK: fix_lifetime [[EXTEND1]] : $NSObject
273+
// CHECK: destroy_value [[EXTEND1]] : $NSObject
274+
// CHECK: return [[ANSWER]] : $Bool
275+
// CHECK: }
276+
func checkCostcoMembership() async -> Bool {
277+
return await CostcoManager.shared().isCustomerEnrolled(inExecutiveProgram: Person.asCustomer())
278+
}

test/SILGen/objc_async_from_swift.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ func testSlowServing(p: SlowServing) async throws {
3131

3232
// CHECK: objc_method {{.*}} $@convention(objc_method) <τ_0_0 where τ_0_0 : SlowServing> (@convention(block) (Int, Optional<NSString>, Optional<NSError>) -> (), τ_0_0) -> ()
3333
// CHECK: hop_to_executor [[GENERIC_EXECUTOR]] :
34-
// CHECK: builtin "willThrow"
35-
// CHECK-NEXT: hop_to_executor [[GENERIC_EXECUTOR]] :
34+
// CHECK: hop_to_executor [[GENERIC_EXECUTOR]] :
35+
// CHECK-NEXT: builtin "willThrow"
3636
let _: (Int, String) = try await p.tryRequestIntAndString()
3737
}
3838

@@ -42,8 +42,8 @@ func testSlowServingAgain(p: SlowServing) async throws {
4242
// CHECK: hop_to_executor [[GENERIC_EXECUTOR]] :
4343
// CHECK: objc_method {{.*}} $@convention(objc_method) <τ_0_0 where τ_0_0 : SlowServing> (@convention(block) (Optional<NSString>, Optional<NSError>) -> (), τ_0_0) -> ()
4444
// CHECK: hop_to_executor [[GENERIC_EXECUTOR]] :
45-
// CHECK: builtin "willThrow"
46-
// CHECK-NEXT: hop_to_executor [[GENERIC_EXECUTOR]] :
45+
// CHECK: hop_to_executor [[GENERIC_EXECUTOR]] :
46+
// CHECK-NEXT: builtin "willThrow"
4747
let _: String = try await p.tryRequestString()
4848
}
4949

0 commit comments

Comments
 (0)