@@ -1072,7 +1072,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
10721072 // it for later. Once we've collected all of the conditional init/assigns,
10731073 // we can insert a single control variable for the memory object for the
10741074 // 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))
10761082 HasConditionalInitAssign = true ;
10771083 return ;
10781084 }
@@ -2186,12 +2192,12 @@ static void updateControlVariable(SILLocation Loc,
21862192}
21872193
21882194// / 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) {
21952201 SILValue ControlVariable =
21962202 B.createLoad (Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
21972203
@@ -2224,6 +2230,32 @@ static SILValue testControlVariable(SILLocation Loc,
22242230 {}, CondVal);
22252231}
22262232
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+
22272259// / handleConditionalInitAssign - This memory object has some stores
22282260// / into (some element of) it that is either an init or an assign based on the
22292261// / control flow path through the function, or have a destroy event that happens
@@ -2285,7 +2317,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
22852317 // If this ambiguous store is only of trivial types, then we don't need to
22862318 // do anything special. We don't even need keep the init bit for the
22872319 // 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))
22892327 continue ;
22902328
22912329 B.setInsertionPoint (Use.Inst );
@@ -2324,9 +2362,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
23242362 // initialization.
23252363 for (unsigned Elt = Use.FirstElement , e = Elt+Use.NumElements ;
23262364 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);
23302368
23312369 SILBasicBlock *TrueBB, *FalseBB, *ContBB;
23322370 InsertCFGDiamond (CondVal, Loc, B,
@@ -2395,7 +2433,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
23952433void LifetimeChecker::
23962434handleConditionalDestroys (SILValue ControlVariableAddr) {
23972435 SILBuilderWithScope B (TheMemory.getUninitializedValue ());
2398- Identifier ShiftRightFn, TruncateFn;
2436+ Identifier ShiftRightFn, TruncateFn, CmpEqFn ;
23992437
24002438 unsigned NumMemoryElements = TheMemory.getNumElements ();
24012439
@@ -2465,9 +2503,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
24652503
24662504 // Insert a load of the liveness bitmask and split the CFG into a diamond
24672505 // 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);
24712509
24722510 SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
24732511
@@ -2486,11 +2524,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
24862524 // depending on if the self box was initialized or not.
24872525 auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc,
24882526 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);
24942532
24952533 SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock;
24962534
@@ -2522,12 +2560,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25222560 // Just conditionally destroy each memory element, and for classes,
25232561 // also free the partially initialized object.
25242562 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+ }
25272606
2528- // The original strong_release or destroy_addr instruction is
2529- // always dead at this point.
2530- deleteDeadRelease (CDElt.ReleaseID );
25312607 continue ;
25322608 }
25332609
@@ -2573,11 +2649,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25732649 // self.init or super.init may or may not have been called.
25742650 // We have not yet stored 'self' into the box.
25752651
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);
25812657
25822658 SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock;
25832659
@@ -2607,11 +2683,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
26072683 // self.init or super.init may or may not have been called.
26082684 // We may or may have stored 'self' into the box.
26092685
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);
26152691
26162692 SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock;
26172693
0 commit comments