@@ -1071,7 +1071,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
10711071 // it for later. Once we've collected all of the conditional init/assigns,
10721072 // we can insert a single control variable for the memory object for the
10731073 // 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))
10751081 HasConditionalInitAssign = true ;
10761082 return ;
10771083 }
@@ -2177,12 +2183,12 @@ static void updateControlVariable(SILLocation Loc,
21772183}
21782184
21792185// / 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) {
21862192 SILValue ControlVariable =
21872193 B.createLoad (Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
21882194
@@ -2215,6 +2221,32 @@ static SILValue testControlVariable(SILLocation Loc,
22152221 {}, CondVal);
22162222}
22172223
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+
22182250// / handleConditionalInitAssign - This memory object has some stores
22192251// / into (some element of) it that is either an init or an assign based on the
22202252// / control flow path through the function, or have a destroy event that happens
@@ -2276,7 +2308,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
22762308 // If this ambiguous store is only of trivial types, then we don't need to
22772309 // do anything special. We don't even need keep the init bit for the
22782310 // 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))
22802318 continue ;
22812319
22822320 B.setInsertionPoint (Use.Inst );
@@ -2315,9 +2353,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
23152353 // initialization.
23162354 for (unsigned Elt = Use.FirstElement , e = Elt+Use.NumElements ;
23172355 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);
23212359
23222360 SILBasicBlock *TrueBB, *FalseBB, *ContBB;
23232361 InsertCFGDiamond (CondVal, Loc, B,
@@ -2386,7 +2424,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
23862424void LifetimeChecker::
23872425handleConditionalDestroys (SILValue ControlVariableAddr) {
23882426 SILBuilderWithScope B (TheMemory.getUninitializedValue ());
2389- Identifier ShiftRightFn, TruncateFn;
2427+ Identifier ShiftRightFn, TruncateFn, CmpEqFn ;
23902428
23912429 unsigned NumMemoryElements = TheMemory.getNumElements ();
23922430
@@ -2456,9 +2494,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
24562494
24572495 // Insert a load of the liveness bitmask and split the CFG into a diamond
24582496 // 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);
24622500
24632501 SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
24642502
@@ -2477,11 +2515,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
24772515 // depending on if the self box was initialized or not.
24782516 auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc,
24792517 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);
24852523
24862524 SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock;
24872525
@@ -2513,12 +2551,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25132551 // Just conditionally destroy each memory element, and for classes,
25142552 // also free the partially initialized object.
25152553 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+ }
25182597
2519- // The original strong_release or destroy_addr instruction is
2520- // always dead at this point.
2521- deleteDeadRelease (CDElt.ReleaseID );
25222598 continue ;
25232599 }
25242600
@@ -2564,11 +2640,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25642640 // self.init or super.init may or may not have been called.
25652641 // We have not yet stored 'self' into the box.
25662642
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);
25722648
25732649 SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock;
25742650
@@ -2598,11 +2674,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25982674 // self.init or super.init may or may not have been called.
25992675 // We may or may have stored 'self' into the box.
26002676
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);
26062682
26072683 SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock;
26082684
0 commit comments