@@ -1071,7 +1071,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
1071
1071
// it for later. Once we've collected all of the conditional init/assigns,
1072
1072
// we can insert a single control variable for the memory object for the
1073
1073
// whole function.
1074
- if (!Use.onlyTouchesTrivialElements (TheMemory))
1074
+ //
1075
+ // For root class initializers, we must keep track of initializations of
1076
+ // trivial stored properties also, since we need to know when the object
1077
+ // has been fully initialized when deciding if a strong_release should
1078
+ // lower to a partial_dealloc_ref.
1079
+ if (TheMemory.isRootClassSelf () ||
1080
+ !Use.onlyTouchesTrivialElements (TheMemory))
1075
1081
HasConditionalInitAssign = true ;
1076
1082
return ;
1077
1083
}
@@ -2177,12 +2183,12 @@ static void updateControlVariable(SILLocation Loc,
2177
2183
}
2178
2184
2179
2185
// / Test a bit in the control variable at the current insertion point.
2180
- static SILValue testControlVariable (SILLocation Loc,
2181
- unsigned Elt,
2182
- SILValue ControlVariableAddr,
2183
- Identifier &ShiftRightFn,
2184
- Identifier &TruncateFn,
2185
- SILBuilder &B) {
2186
+ static SILValue testControlVariableBit (SILLocation Loc,
2187
+ unsigned Elt,
2188
+ SILValue ControlVariableAddr,
2189
+ Identifier &ShiftRightFn,
2190
+ Identifier &TruncateFn,
2191
+ SILBuilder &B) {
2186
2192
SILValue ControlVariable =
2187
2193
B.createLoad (Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
2188
2194
@@ -2215,6 +2221,32 @@ static SILValue testControlVariable(SILLocation Loc,
2215
2221
{}, CondVal);
2216
2222
}
2217
2223
2224
+ // / Test if all bits in the control variable are set at the current
2225
+ // / insertion point.
2226
+ static SILValue testAllControlVariableBits (SILLocation Loc,
2227
+ SILValue ControlVariableAddr,
2228
+ Identifier &CmpEqFn,
2229
+ SILBuilder &B) {
2230
+ SILValue ControlVariable =
2231
+ B.createLoad (Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
2232
+
2233
+ SILValue CondVal = ControlVariable;
2234
+ CanBuiltinIntegerType IVType = CondVal->getType ().castTo <BuiltinIntegerType>();
2235
+
2236
+ if (IVType->getFixedWidth () == 1 )
2237
+ return CondVal;
2238
+
2239
+ SILValue AllBitsSet = B.createIntegerLiteral (Loc, CondVal->getType (), -1 );
2240
+ if (!CmpEqFn.get ())
2241
+ CmpEqFn = getBinaryFunction (" cmp_eq" , CondVal->getType (),
2242
+ B.getASTContext ());
2243
+ SILValue Args[] = { CondVal, AllBitsSet };
2244
+
2245
+ return B.createBuiltin (Loc, CmpEqFn,
2246
+ SILType::getBuiltinIntegerType (1 , B.getASTContext ()),
2247
+ {}, Args);
2248
+ }
2249
+
2218
2250
// / handleConditionalInitAssign - This memory object has some stores
2219
2251
// / into (some element of) it that is either an init or an assign based on the
2220
2252
// / control flow path through the function, or have a destroy event that happens
@@ -2276,7 +2308,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
2276
2308
// If this ambiguous store is only of trivial types, then we don't need to
2277
2309
// do anything special. We don't even need keep the init bit for the
2278
2310
// element precise.
2279
- if (Use.onlyTouchesTrivialElements (TheMemory))
2311
+ //
2312
+ // For root class initializers, we must keep track of initializations of
2313
+ // trivial stored properties also, since we need to know when the object
2314
+ // has been fully initialized when deciding if a strong_release should
2315
+ // lower to a partial_dealloc_ref.
2316
+ if (!TheMemory.isRootClassSelf () &&
2317
+ Use.onlyTouchesTrivialElements (TheMemory))
2280
2318
continue ;
2281
2319
2282
2320
B.setInsertionPoint (Use.Inst );
@@ -2315,9 +2353,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
2315
2353
// initialization.
2316
2354
for (unsigned Elt = Use.FirstElement , e = Elt+Use.NumElements ;
2317
2355
Elt != e; ++Elt) {
2318
- auto CondVal = testControlVariable (Loc, Elt, ControlVariableAddr,
2319
- ShiftRightFn, TruncateFn,
2320
- B);
2356
+ auto CondVal = testControlVariableBit (Loc, Elt, ControlVariableAddr,
2357
+ ShiftRightFn, TruncateFn,
2358
+ B);
2321
2359
2322
2360
SILBasicBlock *TrueBB, *FalseBB, *ContBB;
2323
2361
InsertCFGDiamond (CondVal, Loc, B,
@@ -2386,7 +2424,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
2386
2424
void LifetimeChecker::
2387
2425
handleConditionalDestroys (SILValue ControlVariableAddr) {
2388
2426
SILBuilderWithScope B (TheMemory.getUninitializedValue ());
2389
- Identifier ShiftRightFn, TruncateFn;
2427
+ Identifier ShiftRightFn, TruncateFn, CmpEqFn ;
2390
2428
2391
2429
unsigned NumMemoryElements = TheMemory.getNumElements ();
2392
2430
@@ -2456,9 +2494,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2456
2494
2457
2495
// Insert a load of the liveness bitmask and split the CFG into a diamond
2458
2496
// right before the destroy_addr, if we haven't already loaded it.
2459
- auto CondVal = testControlVariable (Loc, Elt, ControlVariableAddr,
2460
- ShiftRightFn, TruncateFn,
2461
- B);
2497
+ auto CondVal = testControlVariableBit (Loc, Elt, ControlVariableAddr,
2498
+ ShiftRightFn, TruncateFn,
2499
+ B);
2462
2500
2463
2501
SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
2464
2502
@@ -2477,11 +2515,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2477
2515
// depending on if the self box was initialized or not.
2478
2516
auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc,
2479
2517
SILInstruction *Release) {
2480
- auto CondVal = testControlVariable (Loc, SelfInitializedElt,
2481
- ControlVariableAddr,
2482
- ShiftRightFn,
2483
- TruncateFn,
2484
- B);
2518
+ auto CondVal = testControlVariableBit (Loc, SelfInitializedElt,
2519
+ ControlVariableAddr,
2520
+ ShiftRightFn,
2521
+ TruncateFn,
2522
+ B);
2485
2523
2486
2524
SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock;
2487
2525
@@ -2513,12 +2551,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2513
2551
// Just conditionally destroy each memory element, and for classes,
2514
2552
// also free the partially initialized object.
2515
2553
if (!TheMemory.isNonRootClassSelf ()) {
2516
- destroyMemoryElements (Loc, Availability);
2517
- processUninitializedRelease (Release, false , B.getInsertionPoint ());
2554
+ assert (!Availability.isAllYes () &&
2555
+ " Should not end up here if fully initialized" );
2556
+
2557
+ // For root class initializers, we check if all proeprties were
2558
+ // dynamically initialized, and if so, treat this as a release of
2559
+ // an initialized 'self', instead of tearing down the fields
2560
+ // one by one and deallocating memory.
2561
+ //
2562
+ // This is required for correctness, since the condition that
2563
+ // allows 'self' to escape is that all stored properties were
2564
+ // initialized. So we cannot deallocate the memory if 'self' may
2565
+ // have escaped.
2566
+ //
2567
+ // This also means the deinitializer will run if all stored
2568
+ // properties were initialized.
2569
+ if (TheMemory.isClassInitSelf () &&
2570
+ Availability.hasAny (DIKind::Partial)) {
2571
+ auto CondVal = testAllControlVariableBits (Loc, ControlVariableAddr,
2572
+ CmpEqFn, B);
2573
+
2574
+ SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
2575
+
2576
+ InsertCFGDiamond (CondVal, Loc, B,
2577
+ ReleaseBlock, DeallocBlock, ContBlock);
2578
+
2579
+ // If true, self was fully initialized and must be released.
2580
+ B.setInsertionPoint (ReleaseBlock->begin ());
2581
+ B.setCurrentDebugScope (ReleaseBlock->begin ()->getDebugScope ());
2582
+ Release->moveBefore (&*B.getInsertionPoint ());
2583
+
2584
+ // If false, self is uninitialized and must be freed.
2585
+ B.setInsertionPoint (DeallocBlock->begin ());
2586
+ B.setCurrentDebugScope (DeallocBlock->begin ()->getDebugScope ());
2587
+ destroyMemoryElements (Loc, Availability);
2588
+ processUninitializedRelease (Release, false , B.getInsertionPoint ());
2589
+ } else {
2590
+ destroyMemoryElements (Loc, Availability);
2591
+ processUninitializedRelease (Release, false , B.getInsertionPoint ());
2592
+
2593
+ // The original strong_release or destroy_addr instruction is
2594
+ // always dead at this point.
2595
+ deleteDeadRelease (CDElt.ReleaseID );
2596
+ }
2518
2597
2519
- // The original strong_release or destroy_addr instruction is
2520
- // always dead at this point.
2521
- deleteDeadRelease (CDElt.ReleaseID );
2522
2598
continue ;
2523
2599
}
2524
2600
@@ -2564,11 +2640,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2564
2640
// self.init or super.init may or may not have been called.
2565
2641
// We have not yet stored 'self' into the box.
2566
2642
2567
- auto CondVal = testControlVariable (Loc, SuperInitElt,
2568
- ControlVariableAddr,
2569
- ShiftRightFn,
2570
- TruncateFn,
2571
- B);
2643
+ auto CondVal = testControlVariableBit (Loc, SuperInitElt,
2644
+ ControlVariableAddr,
2645
+ ShiftRightFn,
2646
+ TruncateFn,
2647
+ B);
2572
2648
2573
2649
SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock;
2574
2650
@@ -2598,11 +2674,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2598
2674
// self.init or super.init may or may not have been called.
2599
2675
// We may or may have stored 'self' into the box.
2600
2676
2601
- auto CondVal = testControlVariable (Loc, SuperInitElt,
2602
- ControlVariableAddr,
2603
- ShiftRightFn,
2604
- TruncateFn,
2605
- B);
2677
+ auto CondVal = testControlVariableBit (Loc, SuperInitElt,
2678
+ ControlVariableAddr,
2679
+ ShiftRightFn,
2680
+ TruncateFn,
2681
+ B);
2606
2682
2607
2683
SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock;
2608
2684
0 commit comments