Skip to content

Commit 2e81826

Browse files
authored
Merge pull request #42378 from atrick/5.7-fix-cast-ownership
5.7 fix cast ownership
2 parents c37cd91 + d71eb70 commit 2e81826

21 files changed

+678
-115
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
12481248
/// Whether this is the AnyObject type.
12491249
bool isAnyObject();
12501250

1251+
/// Return true if this type is potentially an AnyObject existential after
1252+
/// substitution.
1253+
bool isPotentiallyAnyObject();
1254+
12511255
/// Whether this is an existential composition containing
12521256
/// Error.
12531257
bool isExistentialWithError();

include/swift/SIL/DynamicCasts.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class SILType;
3535
enum class CastConsumptionKind : uint8_t;
3636
struct SILDynamicCastInst;
3737

38+
/// Returns true if the ownership of all references in this type are preserved
39+
/// (without unbalanced retains or releases) during dynamic casting.
40+
bool doesCastPreserveOwnershipForTypes(SILModule &module, CanType sourceType,
41+
CanType targetType);
42+
3843
enum class DynamicCastFeasibility {
3944
/// The cast will always succeed.
4045
WillSucceed,
@@ -82,10 +87,17 @@ bool emitSuccessfulIndirectUnconditionalCast(
8287
bool emitSuccessfulIndirectUnconditionalCast(SILBuilder &B, SILLocation loc,
8388
SILDynamicCastInst dynamicCast);
8489

90+
/// Can the given cast be performed by the scalar checked-cast instructions in
91+
/// the current SIL stage, or do we need to use the indirect instructions?
92+
bool canSILUseScalarCheckedCastInstructions(SILModule &M,
93+
CanType sourceType,
94+
CanType targetType);
95+
8596
/// Can the given cast be performed by the scalar checked-cast
86-
/// instructions, or does we need to use the indirect instructions?
87-
bool canUseScalarCheckedCastInstructions(SILModule &M,
88-
CanType sourceType,CanType targetType);
97+
/// instructions at IRGen, or do we need to use the indirect instructions?
98+
bool canIRGenUseScalarCheckedCastInstructions(SILModule &M,
99+
CanType sourceType,
100+
CanType targetType);
89101

90102
/// Carry out the operations required for an indirect conditional cast
91103
/// using a scalar cast operation.
@@ -435,8 +447,8 @@ struct SILDynamicCastInst {
435447
llvm_unreachable("covered switch");
436448
}
437449

438-
bool canUseScalarCheckedCastInstructions() const {
439-
return swift::canUseScalarCheckedCastInstructions(
450+
bool canSILUseScalarCheckedCastInstructions() const {
451+
return swift::canSILUseScalarCheckedCastInstructions(
440452
getModule(), getSourceFormalType(), getTargetFormalType());
441453
}
442454
};

include/swift/SIL/OwnershipUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ class ForwardingOperand {
189189
return use->getOwnershipConstraint();
190190
}
191191

192-
bool isDirectlyForwarding() const {
192+
bool preservesOwnership() const {
193193
auto &mixin = *OwnershipForwardingMixin::get(use->getUser());
194-
return mixin.isDirectlyForwarding();
194+
return mixin.preservesOwnership();
195195
}
196196

197197
ValueOwnershipKind getForwardingOwnershipKind() const;

include/swift/SIL/SILInstruction.h

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,39 +1112,31 @@ class CopyLikeInstruction {
11121112
/// initializes the kind field on our object is run before our constructor runs.
11131113
class OwnershipForwardingMixin {
11141114
ValueOwnershipKind ownershipKind;
1115-
bool directlyForwards;
1115+
bool preservesOwnershipFlag;
11161116

11171117
protected:
11181118
OwnershipForwardingMixin(SILInstructionKind kind,
11191119
ValueOwnershipKind ownershipKind,
1120-
bool isDirectlyForwarding = true)
1121-
: ownershipKind(ownershipKind), directlyForwards(isDirectlyForwarding) {
1120+
bool preservesOwnership = true)
1121+
: ownershipKind(ownershipKind),
1122+
preservesOwnershipFlag(preservesOwnership) {
11221123
assert(isa(kind) && "Invalid subclass?!");
11231124
assert(ownershipKind && "invalid forwarding ownership");
1124-
assert((directlyForwards || ownershipKind != OwnershipKind::Guaranteed) &&
1125+
assert((preservesOwnershipFlag
1126+
|| ownershipKind != OwnershipKind::Guaranteed) &&
11251127
"Non directly forwarding instructions can not forward guaranteed "
11261128
"ownership");
11271129
}
11281130

11291131
public:
1130-
/// If an instruction is directly forwarding, then any operand op whose
1131-
/// ownership it forwards into a result r must have the property that op and r
1132-
/// are "rc identical". This means that they are representing the same set of
1133-
/// underlying lifetimes (plural b/c of aggregates).
1132+
/// A forwarding instruction preserved ownership if it has a
1133+
/// dynamically non-trivial result in which all references are forwarded from
1134+
/// the operand.
11341135
///
1135-
/// An instruction that is not directly forwarding, can not have guaranteed
1136-
/// ownership since without direct forwarding, there isn't necessarily any
1137-
/// connection in between the operand's lifetime and the value's lifetime.
1138-
///
1139-
/// An example of this is checked_cast_br where when performing the following:
1140-
///
1141-
/// __SwiftValue(AnyHashable(Klass())) to OtherKlass()
1142-
///
1143-
/// we will look through the __SwiftValue(AnyHashable(X)) any just cast Klass
1144-
/// to OtherKlass. This means that the result argument would no longer be
1145-
/// rc-identical to the operand and default case and thus we can not propagate
1146-
/// forward any form of guaranteed ownership.
1147-
bool isDirectlyForwarding() const { return directlyForwards; }
1136+
/// A cast can only forward guaranteed values if it preserves ownership. Such
1137+
/// casts cannot release any references within their operand's value and
1138+
/// cannot retain any references owned by their result.
1139+
bool preservesOwnership() const { return preservesOwnershipFlag; }
11481140

11491141
/// Forwarding ownership is determined by the forwarding instruction's
11501142
/// constant ownership attribute. If forwarding ownership is owned, then the
@@ -1160,7 +1152,7 @@ class OwnershipForwardingMixin {
11601152
return ownershipKind;
11611153
}
11621154
void setForwardingOwnershipKind(ValueOwnershipKind newKind) {
1163-
assert((isDirectlyForwarding() || newKind != OwnershipKind::Guaranteed) &&
1155+
assert((preservesOwnership() || newKind != OwnershipKind::Guaranteed) &&
11641156
"Non directly forwarding instructions can not forward guaranteed "
11651157
"ownership");
11661158
ownershipKind = newKind;
@@ -8083,9 +8075,9 @@ class OwnershipForwardingTermInst : public TermInst,
80838075
OwnershipForwardingTermInst(SILInstructionKind kind,
80848076
SILDebugLocation debugLoc,
80858077
ValueOwnershipKind ownershipKind,
8086-
bool isDirectlyForwarding = true)
8078+
bool preservesOwnership = true)
80878079
: TermInst(kind, debugLoc),
8088-
OwnershipForwardingMixin(kind, ownershipKind, isDirectlyForwarding) {
8080+
OwnershipForwardingMixin(kind, ownershipKind, preservesOwnership) {
80898081
assert(classof(kind));
80908082
}
80918083

@@ -9062,16 +9054,12 @@ class CheckedCastBranchInst final
90629054
SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB,
90639055
ProfileCounter Target1Count,
90649056
ProfileCounter Target2Count,
9065-
ValueOwnershipKind forwardingOwnershipKind)
9057+
ValueOwnershipKind forwardingOwnershipKind,
9058+
bool preservesOwnership)
90669059
: UnaryInstructionWithTypeDependentOperandsBase(
90679060
DebugLoc, Operand, TypeDependentOperands, SuccessBB, FailureBB,
90689061
Target1Count, Target2Count, forwardingOwnershipKind,
9069-
// We are always directly forwarding unless we are casting an
9070-
// AnyObject. This is b/c an AnyObject could contain a boxed
9071-
// AnyObject(Class()) that we unwrap as part of the cast. In such a
9072-
// case, we would return a different value and potentially end the
9073-
// lifetime of the operand value.
9074-
!Operand->getType().isAnyObject()),
9062+
preservesOwnership),
90759063
DestLoweredTy(DestLoweredTy), DestFormalTy(DestFormalTy),
90769064
IsExact(IsExact) {}
90779065

include/swift/SIL/TypeSubstCloner.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
269269
auto FalseCount = inst->getFalseBBCount();
270270

271271
// Try to use the scalar cast instruction.
272-
if (canUseScalarCheckedCastInstructions(B.getModule(),
273-
sourceType, targetType)) {
272+
if (canSILUseScalarCheckedCastInstructions(B.getModule(),
273+
sourceType, targetType)) {
274274
emitIndirectConditionalCastWithScalar(
275275
B, SwiftMod, loc, inst->getConsumptionKind(), src, sourceType, dest,
276276
targetType, succBB, failBB, TrueCount, FalseCount);

lib/AST/Type.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,20 @@ bool TypeBase::isAnyObject() {
978978
return canTy.getExistentialLayout().isAnyObject();
979979
}
980980

981+
// Distinguish between class-bound types that might be AnyObject vs other
982+
// class-bound types. Only types that are potentially AnyObject might have a
983+
// transparent runtime type wrapper like __SwiftValue. This must look through
984+
// all optional types because dynamic casting sees through them.
985+
bool TypeBase::isPotentiallyAnyObject() {
986+
Type unwrappedTy = lookThroughAllOptionalTypes();
987+
if (auto archetype = unwrappedTy->getAs<ArchetypeType>()) {
988+
// Does archetype have any requirements that contradict AnyObject?
989+
// 'T : AnyObject' requires a layout constraint, not a conformance.
990+
return archetype->getConformsTo().empty() && !archetype->getSuperclass();
991+
}
992+
return unwrappedTy->isAnyObject();
993+
}
994+
981995
bool ExistentialLayout::isErrorExistential() const {
982996
auto protocols = getProtocols();
983997
return (!hasExplicitAnyObject &&

lib/SIL/IR/SILInstructions.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/Basic/AssertImplements.h"
2020
#include "swift/Basic/Unicode.h"
2121
#include "swift/Basic/type_traits.h"
22+
#include "swift/SIL/DynamicCasts.h"
2223
#include "swift/SIL/FormalLinkage.h"
2324
#include "swift/SIL/Projection.h"
2425
#include "swift/SIL/SILBuilder.h"
@@ -2283,16 +2284,18 @@ CheckedCastBranchInst *CheckedCastBranchInst::create(
22832284
SILBasicBlock *FailureBB, SILFunction &F,
22842285
ProfileCounter Target1Count, ProfileCounter Target2Count,
22852286
ValueOwnershipKind forwardingOwnershipKind) {
2286-
SILModule &Mod = F.getModule();
2287+
SILModule &module = F.getModule();
2288+
bool preservesOwnership = doesCastPreserveOwnershipForTypes(
2289+
module, Operand->getType().getASTType(), DestFormalTy);
22872290
SmallVector<SILValue, 8> TypeDependentOperands;
22882291
collectTypeDependentOperands(TypeDependentOperands, F, DestFormalTy);
22892292
unsigned size =
22902293
totalSizeToAlloc<swift::Operand>(1 + TypeDependentOperands.size());
2291-
void *Buffer = Mod.allocateInst(size, alignof(CheckedCastBranchInst));
2294+
void *Buffer = module.allocateInst(size, alignof(CheckedCastBranchInst));
22922295
return ::new (Buffer) CheckedCastBranchInst(
22932296
DebugLoc, IsExact, Operand, TypeDependentOperands, DestLoweredTy,
22942297
DestFormalTy, SuccessBB, FailureBB, Target1Count, Target2Count,
2295-
forwardingOwnershipKind);
2298+
forwardingOwnershipKind, preservesOwnership);
22962299
}
22972300

22982301
MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty,

0 commit comments

Comments
 (0)