@@ -1072,7 +1072,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
1072
1072
// it for later. Once we've collected all of the conditional init/assigns,
1073
1073
// we can insert a single control variable for the memory object for the
1074
1074
// whole function.
1075
- if (!Use.onlyTouchesTrivialElements (TheMemory))
1075
+ //
1076
+ // For root class initializers, we must keep track of initializations of
1077
+ // trivial stored properties also, since we need to know when the object
1078
+ // has been fully initialized when deciding if a strong_release should
1079
+ // lower to a partial_dealloc_ref.
1080
+ if (TheMemory.isRootClassSelf () ||
1081
+ !Use.onlyTouchesTrivialElements (TheMemory))
1076
1082
HasConditionalInitAssign = true ;
1077
1083
return ;
1078
1084
}
@@ -2186,12 +2192,12 @@ static void updateControlVariable(SILLocation Loc,
2186
2192
}
2187
2193
2188
2194
// / Test a bit in the control variable at the current insertion point.
2189
- static SILValue testControlVariable (SILLocation Loc,
2190
- unsigned Elt,
2191
- SILValue ControlVariableAddr,
2192
- Identifier &ShiftRightFn,
2193
- Identifier &TruncateFn,
2194
- SILBuilder &B) {
2195
+ static SILValue testControlVariableBit (SILLocation Loc,
2196
+ unsigned Elt,
2197
+ SILValue ControlVariableAddr,
2198
+ Identifier &ShiftRightFn,
2199
+ Identifier &TruncateFn,
2200
+ SILBuilder &B) {
2195
2201
SILValue ControlVariable =
2196
2202
B.createLoad (Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
2197
2203
@@ -2224,6 +2230,32 @@ static SILValue testControlVariable(SILLocation Loc,
2224
2230
{}, CondVal);
2225
2231
}
2226
2232
2233
+ // / Test if all bits in the control variable are set at the current
2234
+ // / insertion point.
2235
+ static SILValue testAllControlVariableBits (SILLocation Loc,
2236
+ SILValue ControlVariableAddr,
2237
+ Identifier &CmpEqFn,
2238
+ SILBuilder &B) {
2239
+ SILValue ControlVariable =
2240
+ B.createLoad (Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
2241
+
2242
+ SILValue CondVal = ControlVariable;
2243
+ CanBuiltinIntegerType IVType = CondVal->getType ().castTo <BuiltinIntegerType>();
2244
+
2245
+ if (IVType->getFixedWidth () == 1 )
2246
+ return CondVal;
2247
+
2248
+ SILValue AllBitsSet = B.createIntegerLiteral (Loc, CondVal->getType (), -1 );
2249
+ if (!CmpEqFn.get ())
2250
+ CmpEqFn = getBinaryFunction (" cmp_eq" , CondVal->getType (),
2251
+ B.getASTContext ());
2252
+ SILValue Args[] = { CondVal, AllBitsSet };
2253
+
2254
+ return B.createBuiltin (Loc, CmpEqFn,
2255
+ SILType::getBuiltinIntegerType (1 , B.getASTContext ()),
2256
+ {}, Args);
2257
+ }
2258
+
2227
2259
// / handleConditionalInitAssign - This memory object has some stores
2228
2260
// / into (some element of) it that is either an init or an assign based on the
2229
2261
// / control flow path through the function, or have a destroy event that happens
@@ -2285,7 +2317,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
2285
2317
// If this ambiguous store is only of trivial types, then we don't need to
2286
2318
// do anything special. We don't even need keep the init bit for the
2287
2319
// element precise.
2288
- if (Use.onlyTouchesTrivialElements (TheMemory))
2320
+ //
2321
+ // For root class initializers, we must keep track of initializations of
2322
+ // trivial stored properties also, since we need to know when the object
2323
+ // has been fully initialized when deciding if a strong_release should
2324
+ // lower to a partial_dealloc_ref.
2325
+ if (!TheMemory.isRootClassSelf () &&
2326
+ Use.onlyTouchesTrivialElements (TheMemory))
2289
2327
continue ;
2290
2328
2291
2329
B.setInsertionPoint (Use.Inst );
@@ -2324,9 +2362,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
2324
2362
// initialization.
2325
2363
for (unsigned Elt = Use.FirstElement , e = Elt+Use.NumElements ;
2326
2364
Elt != e; ++Elt) {
2327
- auto CondVal = testControlVariable (Loc, Elt, ControlVariableAddr,
2328
- ShiftRightFn, TruncateFn,
2329
- B);
2365
+ auto CondVal = testControlVariableBit (Loc, Elt, ControlVariableAddr,
2366
+ ShiftRightFn, TruncateFn,
2367
+ B);
2330
2368
2331
2369
SILBasicBlock *TrueBB, *FalseBB, *ContBB;
2332
2370
InsertCFGDiamond (CondVal, Loc, B,
@@ -2395,7 +2433,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
2395
2433
void LifetimeChecker::
2396
2434
handleConditionalDestroys (SILValue ControlVariableAddr) {
2397
2435
SILBuilderWithScope B (TheMemory.getUninitializedValue ());
2398
- Identifier ShiftRightFn, TruncateFn;
2436
+ Identifier ShiftRightFn, TruncateFn, CmpEqFn ;
2399
2437
2400
2438
unsigned NumMemoryElements = TheMemory.getNumElements ();
2401
2439
@@ -2465,9 +2503,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2465
2503
2466
2504
// Insert a load of the liveness bitmask and split the CFG into a diamond
2467
2505
// right before the destroy_addr, if we haven't already loaded it.
2468
- auto CondVal = testControlVariable (Loc, Elt, ControlVariableAddr,
2469
- ShiftRightFn, TruncateFn,
2470
- B);
2506
+ auto CondVal = testControlVariableBit (Loc, Elt, ControlVariableAddr,
2507
+ ShiftRightFn, TruncateFn,
2508
+ B);
2471
2509
2472
2510
SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
2473
2511
@@ -2486,11 +2524,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2486
2524
// depending on if the self box was initialized or not.
2487
2525
auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc,
2488
2526
SILInstruction *Release) {
2489
- auto CondVal = testControlVariable (Loc, SelfInitializedElt,
2490
- ControlVariableAddr,
2491
- ShiftRightFn,
2492
- TruncateFn,
2493
- B);
2527
+ auto CondVal = testControlVariableBit (Loc, SelfInitializedElt,
2528
+ ControlVariableAddr,
2529
+ ShiftRightFn,
2530
+ TruncateFn,
2531
+ B);
2494
2532
2495
2533
SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock;
2496
2534
@@ -2522,12 +2560,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2522
2560
// Just conditionally destroy each memory element, and for classes,
2523
2561
// also free the partially initialized object.
2524
2562
if (!TheMemory.isNonRootClassSelf ()) {
2525
- destroyMemoryElements (Loc, Availability);
2526
- processUninitializedRelease (Release, false , B.getInsertionPoint ());
2563
+ assert (!Availability.isAllYes () &&
2564
+ " Should not end up here if fully initialized" );
2565
+
2566
+ // For root class initializers, we check if all proeprties were
2567
+ // dynamically initialized, and if so, treat this as a release of
2568
+ // an initialized 'self', instead of tearing down the fields
2569
+ // one by one and deallocating memory.
2570
+ //
2571
+ // This is required for correctness, since the condition that
2572
+ // allows 'self' to escape is that all stored properties were
2573
+ // initialized. So we cannot deallocate the memory if 'self' may
2574
+ // have escaped.
2575
+ //
2576
+ // This also means the deinitializer will run if all stored
2577
+ // properties were initialized.
2578
+ if (TheMemory.isClassInitSelf () &&
2579
+ Availability.hasAny (DIKind::Partial)) {
2580
+ auto CondVal = testAllControlVariableBits (Loc, ControlVariableAddr,
2581
+ CmpEqFn, B);
2582
+
2583
+ SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
2584
+
2585
+ InsertCFGDiamond (CondVal, Loc, B,
2586
+ ReleaseBlock, DeallocBlock, ContBlock);
2587
+
2588
+ // If true, self was fully initialized and must be released.
2589
+ B.setInsertionPoint (ReleaseBlock->begin ());
2590
+ B.setCurrentDebugScope (ReleaseBlock->begin ()->getDebugScope ());
2591
+ Release->moveBefore (&*B.getInsertionPoint ());
2592
+
2593
+ // If false, self is uninitialized and must be freed.
2594
+ B.setInsertionPoint (DeallocBlock->begin ());
2595
+ B.setCurrentDebugScope (DeallocBlock->begin ()->getDebugScope ());
2596
+ destroyMemoryElements (Loc, Availability);
2597
+ processUninitializedRelease (Release, false , B.getInsertionPoint ());
2598
+ } else {
2599
+ destroyMemoryElements (Loc, Availability);
2600
+ processUninitializedRelease (Release, false , B.getInsertionPoint ());
2601
+
2602
+ // The original strong_release or destroy_addr instruction is
2603
+ // always dead at this point.
2604
+ deleteDeadRelease (CDElt.ReleaseID );
2605
+ }
2527
2606
2528
- // The original strong_release or destroy_addr instruction is
2529
- // always dead at this point.
2530
- deleteDeadRelease (CDElt.ReleaseID );
2531
2607
continue ;
2532
2608
}
2533
2609
@@ -2573,11 +2649,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2573
2649
// self.init or super.init may or may not have been called.
2574
2650
// We have not yet stored 'self' into the box.
2575
2651
2576
- auto CondVal = testControlVariable (Loc, SuperInitElt,
2577
- ControlVariableAddr,
2578
- ShiftRightFn,
2579
- TruncateFn,
2580
- B);
2652
+ auto CondVal = testControlVariableBit (Loc, SuperInitElt,
2653
+ ControlVariableAddr,
2654
+ ShiftRightFn,
2655
+ TruncateFn,
2656
+ B);
2581
2657
2582
2658
SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock;
2583
2659
@@ -2607,11 +2683,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
2607
2683
// self.init or super.init may or may not have been called.
2608
2684
// We may or may have stored 'self' into the box.
2609
2685
2610
- auto CondVal = testControlVariable (Loc, SuperInitElt,
2611
- ControlVariableAddr,
2612
- ShiftRightFn,
2613
- TruncateFn,
2614
- B);
2686
+ auto CondVal = testControlVariableBit (Loc, SuperInitElt,
2687
+ ControlVariableAddr,
2688
+ ShiftRightFn,
2689
+ TruncateFn,
2690
+ B);
2615
2691
2616
2692
SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock;
2617
2693
0 commit comments