Skip to content

Commit 5940796

Browse files
committed
SIL: Add an is_escaping_closure instruction
Will be used to verify that withoutActuallyEscaping's block does not escape the closure. ``%escaping = is_escaping_closure %closure`` tests the reference count. If the closure is not uniquely referenced it prints out and error message and returns true. Otherwise, it returns false. The returned result can be used with a ``cond_fail %escaping`` instruction to abort the program. rdar://35525730
1 parent 347ff6a commit 5940796

26 files changed

+181
-2
lines changed

docs/SIL.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2848,6 +2848,19 @@ memory object or a reference to a pinned object. Returns 1 if the
28482848
strong reference count is 1 or the object has been marked pinned by
28492849
strong_pin.
28502850

2851+
is_escaping_closure
2852+
```````````````````
2853+
2854+
::
2855+
sil-instruction ::= 'is_escaping_closure' sil-operand
2856+
2857+
%1 = is_escaping_closure %0 : $@callee_guaranteed () -> ()
2858+
// %0 must be an escaping swift closure.
2859+
// %1 will be of type Builtin.Int1
2860+
2861+
Checks whether the context reference is not nil and bigger than one and returns
2862+
true if it is.
2863+
28512864
copy_block
28522865
``````````
28532866
::

include/swift/Runtime/HeapObject.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,23 @@ SWIFT_RUNTIME_EXPORT
280280
bool swift_isUniquelyReferencedOrPinned_nonNull_native(
281281
const struct HeapObject *);
282282

283+
/// Is this native Swift pointer non-null and has a reference count greater than
284+
/// one.
285+
/// This runtime call will print an error message if the closure is escaping but
286+
/// it will not abort.
287+
SWIFT_RUNTIME_EXPORT
288+
bool swift_isEscapingClosure(const struct HeapObject *object);
289+
290+
/// Is this native Swift pointer non-null and has a reference count greater than
291+
/// one.
292+
/// This runtime call will print an error message with file name and location if
293+
/// the closure is escaping but it will not abort.
294+
SWIFT_RUNTIME_EXPORT
295+
bool swift_isEscapingClosureAtFileLocation(const struct HeapObject *object,
296+
const unsigned char *filename,
297+
int32_t filenameLength,
298+
int32_t line);
299+
283300
/// Deallocate the given memory.
284301
///
285302
/// It must have been returned by swift_allocObject and the strong reference

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,23 @@ FUNCTION(IsUniquelyReferencedOrPinned_nonNull_native,
677677
ARGS(RefCountedPtrTy),
678678
ATTRS(NoUnwind, ZExt))
679679

680+
// bool swift_isEscapingClosure(const struct HeapObject *object);
681+
FUNCTION(IsEscapingClosure, swift_isEscapingClosure,
682+
C_CC,
683+
RETURNS(Int1Ty),
684+
ARGS(RefCountedPtrTy),
685+
ATTRS(NoUnwind, ZExt))
686+
687+
// bool swift_isEscapingClosureAtFileLocation(const struct HeapObject *object,
688+
// const unsigned char *filename,
689+
// int32_t filenameLength,
690+
// int32_t line);
691+
FUNCTION(IsEscapingClosureAtFileLocation, swift_isEscapingClosureAtFileLocation,
692+
C_CC,
693+
RETURNS(Int1Ty),
694+
ARGS(RefCountedPtrTy, Int8PtrTy, Int32Ty, Int32Ty),
695+
ATTRS(NoUnwind, ZExt))
696+
680697
// void swift_arrayInitWithCopy(opaque*, opaque*, size_t, type*);
681698
FUNCTION(ArrayInitWithCopy, swift_arrayInitWithCopy, C_CC,
682699
RETURNS(VoidTy),

include/swift/SIL/SILBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,12 @@ class SILBuilder {
15381538
return insert(new (getModule()) IsUniqueOrPinnedInst(
15391539
getSILDebugLocation(Loc), value, Int1Ty));
15401540
}
1541+
IsEscapingClosureInst *createIsEscapingClosure(SILLocation Loc,
1542+
SILValue operand) {
1543+
auto Int1Ty = SILType::getBuiltinIntegerType(1, getASTContext());
1544+
return insert(new (getModule()) IsEscapingClosureInst(
1545+
getSILDebugLocation(Loc), operand, Int1Ty));
1546+
}
15411547

15421548
DeallocStackInst *createDeallocStack(SILLocation Loc, SILValue operand) {
15431549
return insert(new (getModule())

include/swift/SIL/SILCloner.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,6 +2013,14 @@ visitIsUniqueOrPinnedInst(IsUniqueOrPinnedInst *Inst) {
20132013
getBuilder().createIsUniqueOrPinned(getOpLocation(Inst->getLoc()),
20142014
getOpValue(Inst->getOperand())));
20152015
}
2016+
template <typename ImplClass>
2017+
void SILCloner<ImplClass>::visitIsEscapingClosureInst(
2018+
IsEscapingClosureInst *Inst) {
2019+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
2020+
doPostProcess(
2021+
Inst, getBuilder().createIsEscapingClosure(
2022+
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
2023+
}
20162024

20172025
template<typename ImplClass>
20182026
void

include/swift/SIL/SILInstruction.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6197,6 +6197,18 @@ class IsUniqueOrPinnedInst
61976197
: UnaryInstructionBase(DebugLoc, Operand, BoolTy) {}
61986198
};
61996199

6200+
/// Given an escaping closure return true iff it has a non-nil context and the
6201+
/// context has a strong reference count greater than 1.
6202+
class IsEscapingClosureInst
6203+
: public UnaryInstructionBase<SILInstructionKind::IsEscapingClosureInst,
6204+
SingleValueInstruction> {
6205+
friend SILBuilder;
6206+
6207+
IsEscapingClosureInst(SILDebugLocation DebugLoc, SILValue Operand,
6208+
SILType BoolTy)
6209+
: UnaryInstructionBase(DebugLoc, Operand, BoolTy) {}
6210+
};
6211+
62006212
//===----------------------------------------------------------------------===//
62016213
// DeallocationInsts
62026214
//===----------------------------------------------------------------------===//

include/swift/SIL/SILNodes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,9 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
379379
SINGLE_VALUE_INST(IsUniqueOrPinnedInst, is_unique_or_pinned,
380380
SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
381381

382+
SINGLE_VALUE_INST(IsEscapingClosureInst, is_escaping_closure,
383+
SingleValueInstruction, MayRead, DoesNotRelease)
384+
382385
// Accessing memory
383386
SINGLE_VALUE_INST(LoadInst, load,
384387
SingleValueInstruction, MayRead, DoesNotRelease)

lib/IRGen/GenHeap.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "swift/Basic/SourceLoc.h"
2626
#include "swift/ABI/MetadataValues.h"
27+
#include "swift/AST/ASTContext.h"
2728
#include "swift/AST/GenericEnvironment.h"
2829
#include "swift/AST/IRGenOptions.h"
2930

@@ -1430,6 +1431,20 @@ emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull,
14301431
return call;
14311432
}
14321433

1434+
llvm::Value *IRGenFunction::emitIsEscapingClosureCall(llvm::Value *value,
1435+
SourceLoc sourceLoc) {
1436+
auto loc = SILLocation::decode(sourceLoc, IGM.Context.SourceMgr);
1437+
auto line = llvm::ConstantInt::get(IGM.Int32Ty, loc.Line);
1438+
auto filename = IGM.getAddrOfGlobalString(loc.Filename);
1439+
auto filenameLength =
1440+
llvm::ConstantInt::get(IGM.Int32Ty, loc.Filename.size());
1441+
llvm::CallInst *call =
1442+
Builder.CreateCall(IGM.getIsEscapingClosureAtFileLocationFn(),
1443+
{value, filename, filenameLength, line});
1444+
call->setDoesNotThrow();
1445+
return call;
1446+
}
1447+
14331448
namespace {
14341449
/// Basic layout and common operations for box types.
14351450
class BoxTypeInfo : public HeapTypeInfo<BoxTypeInfo> {

lib/IRGen/IRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ class IRGenFunction {
435435
llvm::Value *emitIsUniqueCall(llvm::Value *value, SourceLoc loc,
436436
bool isNonNull, bool checkPinned);
437437

438+
llvm::Value *emitIsEscapingClosureCall(llvm::Value *value, SourceLoc loc);
439+
438440
//--- Expression emission ------------------------------------------------------
439441
public:
440442
void emitFakeExplosion(const TypeInfo &type, Explosion &explosion);

lib/IRGen/IRGenSIL.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,7 @@ class IRGenSILFunction :
10271027
void visitStoreUnownedInst(StoreUnownedInst *i);
10281028
void visitIsUniqueInst(IsUniqueInst *i);
10291029
void visitIsUniqueOrPinnedInst(IsUniqueOrPinnedInst *i);
1030+
void visitIsEscapingClosureInst(IsEscapingClosureInst *i);
10301031
void visitDeallocStackInst(DeallocStackInst *i);
10311032
void visitDeallocBoxInst(DeallocBoxInst *i);
10321033
void visitDeallocRefInst(DeallocRefInst *i);
@@ -3883,6 +3884,27 @@ visitIsUniqueOrPinnedInst(swift::IsUniqueOrPinnedInst *i) {
38833884
setLoweredExplosion(i, out);
38843885
}
38853886

3887+
void IRGenSILFunction::visitIsEscapingClosureInst(
3888+
swift::IsEscapingClosureInst *i) {
3889+
assert(i->getOperand()->getType().is<SILFunctionType>() &&
3890+
i->getOperand()
3891+
->getType()
3892+
.getAs<SILFunctionType>()
3893+
->getExtInfo()
3894+
.hasContext() &&
3895+
"Must have a closure operand");
3896+
3897+
Explosion closure = getLoweredExplosion(i->getOperand());
3898+
auto func = closure.claimNext();
3899+
(void)func;
3900+
auto context = closure.claimNext();
3901+
3902+
auto result = emitIsEscapingClosureCall(context, i->getLoc().getSourceLoc());
3903+
Explosion out;
3904+
out.add(result);
3905+
setLoweredExplosion(i, out);
3906+
}
3907+
38863908
void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
38873909
const TypeInfo &type,
38883910
llvm::Value *addr) {

0 commit comments

Comments
 (0)