14
14
#include " RValue.h"
15
15
#include " SILGenFunction.h"
16
16
#include " SILGenFunctionBuilder.h"
17
+ #include " SwitchEnumBuilder.h"
17
18
#include " swift/AST/GenericSignature.h"
18
19
#include " swift/AST/SubstitutionMap.h"
19
20
#include " swift/SIL/TypeLowering.h"
@@ -220,21 +221,34 @@ void SILGenFunction::destroyClassMember(SILLocation cleanupLoc,
220
221
}
221
222
}
222
223
224
+ // Finds stored properties that have the same type as `cd` and thus form
225
+ // a recursive structure.
226
+ //
227
+ // Example:
228
+ //
229
+ // class Node<T> {
230
+ // let element: T
231
+ // let next: Node<T>?
232
+ // }
233
+ //
234
+ // In the above example `next` is a recursive link and would be recognized
235
+ // by this function and added to the result set.
223
236
void findRecursiveLinks (ClassDecl *cd, llvm::SmallSetVector<VarDecl*, 4 > &result) {
224
- auto SelfTy = cd->getDeclaredInterfaceType ();
237
+ auto selfTy = cd->getDeclaredInterfaceType ();
225
238
226
239
// Collect all stored properties that would form a recursive structure,
227
240
// so we can remove the recursion and prevent the call stack from
228
241
// overflowing.
229
242
for (VarDecl *vd : cd->getStoredProperties ()) {
230
243
auto Ty = vd->getInterfaceType ()->getOptionalObjectType ();
231
- if (Ty && Ty->getCanonicalType () == SelfTy ->getCanonicalType ()) {
244
+ if (Ty && Ty->getCanonicalType () == selfTy ->getCanonicalType ()) {
232
245
result.insert (vd);
233
246
}
234
247
}
235
248
236
- // NOTE: Right now we only optimize linear recursion, so if there is more than
237
- // one link, clear out the set and don't perform any recursion optimization.
249
+ // NOTE: Right now we only optimize linear recursion, so if there is more
250
+ // than one stored property of the same type, clear out the set and don't
251
+ // perform any recursion optimization.
238
252
if (result.size () > 1 ) {
239
253
result.clear ();
240
254
}
@@ -244,9 +258,9 @@ void SILGenFunction::emitRecursiveChainDestruction(ManagedValue selfValue,
244
258
ClassDecl *cd,
245
259
VarDecl *recursiveLink,
246
260
CleanupLocation cleanupLoc) {
247
- auto SelfTy = F.mapTypeIntoContext (cd->getDeclaredInterfaceType ());
261
+ auto selfTy = F.mapTypeIntoContext (cd->getDeclaredInterfaceType ());
248
262
249
- auto SelfTyLowered = getTypeLowering (SelfTy ).getLoweredType ();
263
+ auto selfTyLowered = getTypeLowering (selfTy ).getLoweredType ();
250
264
251
265
SILBasicBlock *cleanBB = createBasicBlock ();
252
266
SILBasicBlock *noneBB = createBasicBlock ();
@@ -262,7 +276,7 @@ void SILGenFunction::emitRecursiveChainDestruction(ManagedValue selfValue,
262
276
SILValue varAddr =
263
277
B.createRefElementAddr (cleanupLoc, selfValue.getValue (), recursiveLink,
264
278
Ty.getAddressType ());
265
- auto iterAddr = B.createAllocStack (cleanupLoc, Ty);
279
+ auto * iterAddr = B.createAllocStack (cleanupLoc, Ty);
266
280
SILValue addr = B.createBeginAccess (
267
281
cleanupLoc, varAddr, SILAccessKind::Modify, SILAccessEnforcement::Static,
268
282
true /* noNestedConflict*/ , false /* fromBuiltin*/ );
@@ -274,57 +288,77 @@ void SILGenFunction::emitRecursiveChainDestruction(ManagedValue selfValue,
274
288
B.createBranch (cleanupLoc, loopBB);
275
289
276
290
// while iter != nil {
277
- B.emitBlock (loopBB);
278
- B.createSwitchEnumAddr (
279
- cleanupLoc, iterAddr, nullptr ,
280
- {{getASTContext ().getOptionalSomeDecl (), someBB},
281
- {std::make_pair (getASTContext ().getOptionalNoneDecl (), noneBB)}});
291
+ {
292
+ B.emitBlock (loopBB);
293
+ auto iterBorrow =
294
+ ManagedValue::forUnmanaged (iterAddr).borrow (*this , cleanupLoc);
295
+ SwitchEnumBuilder switchBuilder (B, cleanupLoc, iterBorrow);
296
+ switchBuilder.addOptionalSomeCase (someBB);
297
+ switchBuilder.addOptionalNoneCase (noneBB);
298
+ std::move (switchBuilder).emit ();
299
+ }
282
300
283
301
// if isKnownUniquelyReferenced(&iter) {
284
- B.emitBlock (someBB);
285
- auto isUnique = B.createIsUnique (cleanupLoc, iterAddr);
286
- B.createCondBranch (cleanupLoc, isUnique, uniqueBB, notUniqueBB);
302
+ {
303
+ B.emitBlock (someBB);
304
+ auto isUnique = B.createIsUnique (cleanupLoc, iterAddr);
305
+ B.createCondBranch (cleanupLoc, isUnique, uniqueBB, notUniqueBB);
306
+ }
287
307
288
308
// we have a uniquely referenced link, so we need to deinit
289
- B.emitBlock (uniqueBB);
290
-
291
- // NOTE: We increment the ref count of the tail instead of unlinking it,
292
- // because custom deinit implementations of subclasses may access
293
- // it and it would be semantically wrong to unset it before that.
294
- // Making the tail non-uniquely referenced prevents the recursion.
295
-
296
- // let tail = iter.unsafelyUnwrapped.next
297
- // iter = tail
298
- SILValue iterBorrow = B.createLoadBorrow (cleanupLoc, iterAddr);
299
- auto *link = B.createUncheckedEnumData (cleanupLoc, iterBorrow,
300
- getASTContext ().getOptionalSomeDecl (),
301
- SelfTyLowered);
302
-
303
- varAddr = B.createRefElementAddr (cleanupLoc, link, recursiveLink,
304
- Ty.getAddressType ());
305
-
306
- addr = B.createBeginAccess (
307
- cleanupLoc, varAddr, SILAccessKind::Read, SILAccessEnforcement::Static,
308
- true /* noNestedConflict */ , false /* fromBuiltin*/ );
309
- iter = B.createLoad (cleanupLoc, addr, LoadOwnershipQualifier::Copy);
310
- B.createEndAccess (cleanupLoc, addr, false /* is aborting*/ );
311
- B.createEndBorrow (cleanupLoc, iterBorrow);
309
+ {
310
+ B.emitBlock (uniqueBB);
312
311
313
- B.createStore (cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Assign);
312
+ // NOTE: We increment the ref count of the tail instead of unlinking it,
313
+ // because custom deinit implementations of subclasses may access
314
+ // it and it would be semantically wrong to unset it before that.
315
+ // Making the tail non-uniquely referenced prevents the recursion.
314
316
315
- B.createBranch (cleanupLoc, loopBB);
317
+ // let tail = iter.unsafelyUnwrapped.next
318
+ // iter = tail
319
+ SILValue iterBorrow = B.createLoadBorrow (cleanupLoc, iterAddr);
320
+ auto *link = B.createUncheckedEnumData (
321
+ cleanupLoc, iterBorrow, getASTContext ().getOptionalSomeDecl (),
322
+ selfTyLowered);
323
+
324
+ varAddr = B.createRefElementAddr (cleanupLoc, link, recursiveLink,
325
+ Ty.getAddressType ());
326
+
327
+ addr = B.createBeginAccess (
328
+ cleanupLoc, varAddr, SILAccessKind::Read, SILAccessEnforcement::Static,
329
+ true /* noNestedConflict */ , false /* fromBuiltin*/ );
330
+
331
+ // The deinit of `iter` will decrement the ref count of the field
332
+ // containing the next element and potentially leading to its
333
+ // deinitialization, causing the recursion. The prevent that,
334
+ // we `load [copy]` here to ensure the object stays alive until
335
+ // we explicitly release it in the next step of the iteration.
336
+ iter = B.createLoad (cleanupLoc, addr, LoadOwnershipQualifier::Copy);
337
+ B.createEndAccess (cleanupLoc, addr, false /* is aborting*/ );
338
+ B.createEndBorrow (cleanupLoc, iterBorrow);
339
+
340
+ B.createStore (cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Assign);
341
+
342
+ B.createBranch (cleanupLoc, loopBB);
343
+ }
316
344
317
345
// the next link in the chain is not unique, so we are done here
318
- B.emitBlock (notUniqueBB);
319
- B.createBranch (cleanupLoc, cleanBB);
346
+ {
347
+ B.emitBlock (notUniqueBB);
348
+ B.createBranch (cleanupLoc, cleanBB);
349
+ }
320
350
321
351
// we reached the end of the chain
322
- B.emitBlock (noneBB);
323
- B.createBranch (cleanupLoc, cleanBB);
352
+ {
353
+ B.emitBlock (noneBB);
354
+ B.createBranch (cleanupLoc, cleanBB);
355
+ }
324
356
325
- B.emitBlock (cleanBB);
326
- B.createDestroyAddr (cleanupLoc, iterAddr);
327
- B.createDeallocStack (cleanupLoc, iterAddr);
357
+ {
358
+ B.emitBlock (cleanBB);
359
+ B.createDestroyAddr (cleanupLoc, iterAddr);
360
+ B.createDeallocStack (cleanupLoc, iterAddr);
361
+ }
328
362
}
329
363
330
364
void SILGenFunction::emitClassMemberDestruction (ManagedValue selfValue,
@@ -355,6 +389,10 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
355
389
finishBB);
356
390
}
357
391
392
+ // Before we destroy all fields, we check if any of them are
393
+ // recursively the same type as `self`, so we can iteratively
394
+ // deinitialize them, to prevent deep recursion and potential
395
+ // stack overflows.
358
396
llvm::SmallSetVector<VarDecl*, 4 > recursiveLinks;
359
397
findRecursiveLinks (cd, recursiveLinks);
360
398
0 commit comments