Skip to content

Commit a2bd36a

Browse files
authored
Merge pull request #38556 from meg-gupta/fixobjcasyncsilgen
Fix arg cleanup for objc continuations
2 parents 2c43247 + 3372ab7 commit a2bd36a

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

lib/SILGen/ManagedValue.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ ManagedValue ManagedValue::copy(SILGenFunction &SGF, SILLocation loc) const {
3737
return SGF.emitManagedRValueWithCleanup(buf, lowering);
3838
}
3939

40+
// Emit an unmanaged copy of this value
41+
// WARNING: Callers of this API should manage the cleanup of this value!
42+
ManagedValue ManagedValue::unmanagedCopy(SILGenFunction &SGF,
43+
SILLocation loc) const {
44+
auto &lowering = SGF.getTypeLowering(getType());
45+
if (lowering.isTrivial())
46+
return *this;
47+
48+
if (getType().isObject()) {
49+
auto copy = SGF.B.emitCopyValueOperation(loc, getValue());
50+
return ManagedValue::forUnmanaged(copy);
51+
}
52+
53+
SILValue buf = SGF.emitTemporaryAllocation(loc, getType());
54+
SGF.B.createCopyAddr(loc, getValue(), buf, IsNotTake, IsInitialization);
55+
return ManagedValue::forUnmanaged(buf);
56+
}
57+
4058
/// Emit a copy of this value with independent ownership.
4159
ManagedValue ManagedValue::formalAccessCopy(SILGenFunction &SGF,
4260
SILLocation loc) {

lib/SILGen/ManagedValue.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ class ManagedValue {
270270
/// Emit a copy of this value with independent ownership.
271271
ManagedValue copy(SILGenFunction &SGF, SILLocation loc) const;
272272

273+
/// Returns an unmanaged copy of this value.
274+
/// WARNING: Callers of this API should manage the cleanup of this value!
275+
ManagedValue unmanagedCopy(SILGenFunction &SGF, SILLocation loc) const;
276+
273277
/// Emit a copy of this value with independent ownership into the current
274278
/// formal evaluation scope.
275279
ManagedValue formalAccessCopy(SILGenFunction &SGF, SILLocation loc);

lib/SILGen/SILGenApply.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4307,6 +4307,29 @@ bool SILGenModule::isNonMutatingSelfIndirect(SILDeclRef methodRef) {
43074307
return self.isFormalIndirect();
43084308
}
43094309

4310+
namespace {
4311+
/// Cleanup to insert fix_lifetime and destroy
4312+
class FixLifetimeDestroyCleanup : public Cleanup {
4313+
SILValue val;
4314+
4315+
public:
4316+
FixLifetimeDestroyCleanup(SILValue val) : val(val) {}
4317+
4318+
void emit(SILGenFunction &SGF, CleanupLocation l,
4319+
ForUnwind_t forUnwind) override {
4320+
SGF.B.emitFixLifetime(l, val);
4321+
SGF.B.emitDestroyOperation(l, val);
4322+
}
4323+
4324+
void dump(SILGenFunction &SGF) const override {
4325+
#ifndef NDEBUG
4326+
llvm::errs() << "FixLifetimeDestroyCleanup "
4327+
<< "State:" << getState() << " "
4328+
<< "Value: " << val << "\n";
4329+
#endif
4330+
}
4331+
};
4332+
} // end anonymous namespace
43104333

43114334
//===----------------------------------------------------------------------===//
43124335
// Top Level Entrypoints
@@ -4456,6 +4479,19 @@ RValue SILGenFunction::emitApply(
44564479
// hop back to the current executor
44574480
breadcrumb.emit(*this, loc);
44584481

4482+
// For objc async calls, lifetime extend the args until the result plan which
4483+
// generates `await_async_continuation`.
4484+
// Lifetime is extended by creating unmanaged copies here and by pushing the
4485+
// cleanups required just before the result plan is generated.
4486+
SmallVector<ManagedValue, 8> unmanagedCopies;
4487+
if (calleeTypeInfo.foreign.async) {
4488+
for (auto arg : args) {
4489+
if (arg.hasCleanup()) {
4490+
unmanagedCopies.push_back(arg.unmanagedCopy(*this, loc));
4491+
}
4492+
}
4493+
}
4494+
44594495
// Pop the argument scope.
44604496
argScope.pop();
44614497

@@ -4531,12 +4567,30 @@ RValue SILGenFunction::emitApply(
45314567
emitForeignErrorCheck(loc, directResults, errorTemp, doesNotThrow,
45324568
*foreignError);
45334569
}
4534-
4570+
4571+
// For objc async calls, push cleanup to be used on throw paths in the result
4572+
// planner.
4573+
for (unsigned i : indices(unmanagedCopies)) {
4574+
SILValue value = unmanagedCopies[i].getValue();
4575+
Cleanups.pushCleanup<FixLifetimeDestroyCleanup>(value);
4576+
unmanagedCopies[i] = ManagedValue(value, Cleanups.getTopCleanup());
4577+
}
4578+
45354579
auto directResultsArray = makeArrayRef(directResults);
45364580
RValue result =
45374581
resultPlan->finish(*this, loc, substResultType, directResultsArray);
45384582
assert(directResultsArray.empty() && "didn't claim all direct results");
45394583

4584+
// For objc async calls, generate cleanup on the resume path here and forward
4585+
// the previously pushed cleanups.
4586+
if (calleeTypeInfo.foreign.async) {
4587+
for (auto unmanagedCopy : unmanagedCopies) {
4588+
auto value = unmanagedCopy.forward(*this);
4589+
B.emitFixLifetime(loc, value);
4590+
B.emitDestroyOperation(loc, value);
4591+
}
4592+
}
4593+
45404594
return result;
45414595
}
45424596

test/SILGen/objc_async.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import ObjCConcurrency
88
// CHECK-LABEL: sil {{.*}}@${{.*}}14testSlowServer
99
func testSlowServer(slowServer: SlowServer) async throws {
1010
// CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int
11+
// CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF :
12+
// CHECK: [[ARG:%.*]] = apply [[STRINGINIT]]
1113
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> ()
1214
// CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]]
1315
// CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation<Int, Never> ([[CONT]] : $Builtin.RawUnsafeContinuation)
@@ -16,10 +18,14 @@ func testSlowServer(slowServer: SlowServer) async throws {
1618
// CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT]]
1719
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<Int, Never>, Int) -> ()
1820
// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]]
19-
// CHECK: apply [[METHOD]]({{.*}}, [[BLOCK]], %0)
21+
// CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0)
22+
// CHECK: [[COPY:%.*]] = copy_value [[ARG]]
23+
// CHECK: destroy_value [[ARG]]
2024
// CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]]
2125
// CHECK: [[RESUME]]:
2226
// CHECK: [[RESULT:%.*]] = load [trivial] [[RESUME_BUF]]
27+
// CHECK: fix_lifetime [[COPY]]
28+
// CHECK: destroy_value [[COPY]]
2329
// CHECK: dealloc_stack [[RESUME_BUF]]
2430
let _: Int = await slowServer.doSomethingSlow("mail")
2531

0 commit comments

Comments
 (0)