@@ -35,39 +35,70 @@ static void diagnose(SILModule &M, SILLocation loc, ArgTypes... args) {
35
35
M.getASTContext ().Diags .diagnose (loc.getSourceLoc (), Diagnostic (args...));
36
36
}
37
37
38
+ enum class PartialInitializationKind {
39
+ // / The box contains a fully-initialized value.
40
+ IsNotInitialization,
41
+
42
+ // / The box contains a class instance that we own, but the instance has
43
+ // / not been initialized and should be freed with a special SIL
44
+ // / instruction made for this purpose.
45
+ IsReinitialization,
46
+
47
+ // / The box contains an undefined value that should be ignored.
48
+ IsInitialization,
49
+ };
50
+
38
51
// / Emit the sequence that an assign instruction lowers to once we know
39
52
// / if it is an initialization or an assignment. If it is an assignment,
40
53
// / a live-in value can be provided to optimize out the reload.
41
54
static void LowerAssignInstruction (SILBuilder &B, AssignInst *Inst,
42
- IsInitialization_t isInitialization) {
43
- DEBUG (llvm::dbgs () << " *** Lowering [isInit=" << ( bool ) isInitialization
55
+ PartialInitializationKind isInitialization) {
56
+ DEBUG (llvm::dbgs () << " *** Lowering [isInit=" << unsigned ( isInitialization)
44
57
<< " ]: " << *Inst << " \n " );
45
58
46
59
++NumAssignRewritten;
47
60
48
61
SILValue Src = Inst->getSrc ();
62
+ SILLocation Loc = Inst->getLoc ();
49
63
50
- // If this is an initialization, or the storage type is trivial, we
51
- // can just replace the assignment with a store.
52
-
53
- // Otherwise, if it has trivial type, we can always just replace the
54
- // assignment with a store. If it has non-trivial type and is an
55
- // initialization, we can also replace it with a store.
56
- if (isInitialization == IsInitialization ||
64
+ if (isInitialization == PartialInitializationKind::IsInitialization ||
57
65
Inst->getDest ()->getType ().isTrivial (Inst->getModule ())) {
58
- B.createStore (Inst->getLoc (), Src, Inst->getDest ());
66
+
67
+ // If this is an initialization, or the storage type is trivial, we
68
+ // can just replace the assignment with a store.
69
+ assert (isInitialization != PartialInitializationKind::IsReinitialization);
70
+ B.createStore (Loc, Src, Inst->getDest ());
71
+ } else if (isInitialization == PartialInitializationKind::IsReinitialization) {
72
+
73
+ // We have a case where a convenience initializer on a class
74
+ // delegates to a factory initializer from a protocol extension.
75
+ // Factory initializers give us a whole new instance, so the existing
76
+ // instance, which has not been initialized and never will be, must be
77
+ // freed using dealloc_partial_ref.
78
+ SILValue Pointer = B.createLoad (Loc, Inst->getDest ());
79
+ B.createStore (Loc, Src, Inst->getDest ());
80
+
81
+ auto MetatypeTy = CanMetatypeType::get (
82
+ Inst->getDest ()->getType ().getSwiftRValueType (),
83
+ MetatypeRepresentation::Thick);
84
+ auto SILMetatypeTy = SILType::getPrimitiveObjectType (MetatypeTy);
85
+ SILValue Metatype = B.createValueMetatype (Loc, SILMetatypeTy, Pointer);
86
+
87
+ B.createDeallocPartialRef (Loc, Pointer, Metatype);
59
88
} else {
89
+ assert (isInitialization == PartialInitializationKind::IsNotInitialization);
90
+
60
91
// Otherwise, we need to replace the assignment with the full
61
- // load/store/release dance. Note that the new value is already
92
+ // load/store/release dance. Note that the new value is already
62
93
// considered to be retained (by the semantics of the storage type),
63
94
// and we're transferring that ownership count into the destination.
64
95
65
96
// This is basically TypeLowering::emitStoreOfCopy, except that if we have
66
97
// a known incoming value, we can avoid the load.
67
- SILValue IncomingVal = B.createLoad (Inst-> getLoc () , Inst->getDest ());
98
+ SILValue IncomingVal = B.createLoad (Loc , Inst->getDest ());
68
99
B.createStore (Inst->getLoc (), Src, Inst->getDest ());
69
100
70
- B.emitReleaseValueOperation (Inst-> getLoc () , IncomingVal);
101
+ B.emitReleaseValueOperation (Loc , IncomingVal);
71
102
}
72
103
73
104
Inst->eraseFromParent ();
@@ -1632,12 +1663,24 @@ void LifetimeChecker::updateInstructionForInitState(DIMemoryUse &InstInfo) {
1632
1663
InstInfo.Inst = nullptr ;
1633
1664
NonLoadUses.erase (Inst);
1634
1665
1666
+ PartialInitializationKind PartialInitKind;
1667
+
1668
+ if (TheMemory.isClassInitSelf () &&
1669
+ Kind == DIUseKind::SelfInit) {
1670
+ assert (InitKind == IsInitialization);
1671
+ PartialInitKind = PartialInitializationKind::IsReinitialization;
1672
+ } else {
1673
+ PartialInitKind = (InitKind == IsInitialization
1674
+ ? PartialInitializationKind::IsInitialization
1675
+ : PartialInitializationKind::IsNotInitialization);
1676
+ }
1677
+
1635
1678
unsigned FirstElement = InstInfo.FirstElement ;
1636
1679
unsigned NumElements = InstInfo.NumElements ;
1637
1680
1638
1681
SmallVector<SILInstruction*, 4 > InsertedInsts;
1639
1682
SILBuilderWithScope B (Inst, &InsertedInsts);
1640
- LowerAssignInstruction (B, AI, InitKind );
1683
+ LowerAssignInstruction (B, AI, PartialInitKind );
1641
1684
1642
1685
// If lowering of the assign introduced any new loads or stores, keep track
1643
1686
// of them.
@@ -1646,7 +1689,11 @@ void LifetimeChecker::updateInstructionForInitState(DIMemoryUse &InstInfo) {
1646
1689
NonLoadUses[I] = Uses.size ();
1647
1690
Uses.push_back (DIMemoryUse (I, Kind, FirstElement, NumElements));
1648
1691
} else if (isa<LoadInst>(I)) {
1649
- Uses.push_back (DIMemoryUse (I, Load, FirstElement, NumElements));
1692
+ // If we have a re-initialization, the value must be a class,
1693
+ // and the load is just there so we can free the uninitialized
1694
+ // object husk; it's not an actual use of 'self'.
1695
+ if (PartialInitKind != PartialInitializationKind::IsReinitialization)
1696
+ Uses.push_back (DIMemoryUse (I, Load, FirstElement, NumElements));
1650
1697
}
1651
1698
}
1652
1699
return ;
@@ -2541,7 +2588,8 @@ static bool lowerRawSILOperations(SILFunction &Fn) {
2541
2588
// Unprocessed assigns just lower into assignments, not initializations.
2542
2589
if (auto *AI = dyn_cast<AssignInst>(Inst)) {
2543
2590
SILBuilderWithScope B (AI);
2544
- LowerAssignInstruction (B, AI, IsNotInitialization);
2591
+ LowerAssignInstruction (B, AI,
2592
+ PartialInitializationKind::IsNotInitialization);
2545
2593
// Assign lowering may split the block. If it did,
2546
2594
// reset our iteration range to the block after the insertion.
2547
2595
if (B.getInsertionBB () != &BB)
0 commit comments