@@ -220,131 +220,111 @@ void SILGenFunction::destroyClassMember(SILLocation cleanupLoc,
220
220
}
221
221
}
222
222
223
- llvm::SmallSetVector<VarDecl *, 4 > findRecursiveLinks (ClassDecl *cd ) {
223
+ void findRecursiveLinks (ClassDecl *cd, llvm::SmallSetVector<VarDecl*, 4 > &result ) {
224
224
auto SelfTy = cd->getDeclaredInterfaceType ();
225
225
226
226
// Collect all stored properties that would form a recursive structure,
227
227
// so we can remove the recursion and prevent the call stack from
228
228
// overflowing.
229
- llvm::SmallSetVector<VarDecl *, 4 > recursiveLinks;
230
229
for (VarDecl *vd : cd->getStoredProperties ()) {
231
230
auto Ty = vd->getInterfaceType ()->getOptionalObjectType ();
232
231
if (Ty && Ty->getCanonicalType () == SelfTy->getCanonicalType ()) {
233
- recursiveLinks .insert (vd);
232
+ result .insert (vd);
234
233
}
235
234
}
236
235
237
236
// NOTE: Right now we only optimize linear recursion, so if there is more than
238
237
// one link, clear out the set and don't perform any recursion optimization.
239
- if (recursiveLinks .size () > 1 ) {
240
- recursiveLinks .clear ();
238
+ if (result .size () > 1 ) {
239
+ result .clear ();
241
240
}
242
-
243
- return recursiveLinks;
244
241
}
245
242
246
- void SILGenFunction::emitRecursiveChainDestruction (
247
- ManagedValue selfValue, ClassDecl *cd,
248
- SmallSetVector<VarDecl *, 4 > recursiveLinks, CleanupLocation cleanupLoc) {
243
+ void SILGenFunction::emitRecursiveChainDestruction (ManagedValue selfValue,
244
+ ClassDecl *cd,
245
+ VarDecl *recursiveLink,
246
+ CleanupLocation cleanupLoc) {
249
247
auto SelfTy = F.mapTypeIntoContext (cd->getDeclaredInterfaceType ());
250
248
251
- assert (recursiveLinks.size () <= 1 && " Only linear recursion supported." );
252
-
253
249
auto SelfTyLowered = getTypeLowering (SelfTy).getLoweredType ();
254
- for (VarDecl *vd : recursiveLinks) {
255
- SILBasicBlock *cleanBB = createBasicBlock ();
256
- SILBasicBlock *noneBB = createBasicBlock ();
257
- SILBasicBlock *notUniqueBB = createBasicBlock ();
258
- SILBasicBlock *uniqueBB = createBasicBlock ();
259
- SILBasicBlock *someBB = createBasicBlock ();
260
- SILBasicBlock *loopBB = createBasicBlock ();
261
-
262
- // var iter = self.link
263
- // self.link = nil
264
- auto Ty = getTypeLowering (F.mapTypeIntoContext (vd->getInterfaceType ()))
265
- .getLoweredType ();
266
- auto optionalNone = B.createOptionalNone (cleanupLoc, Ty);
267
- SILValue varAddr = B.createRefElementAddr (cleanupLoc, selfValue.getValue (),
268
- vd, Ty.getAddressType ());
269
- auto iterAddr = B.createAllocStack (cleanupLoc, Ty);
270
- SILValue addr =
271
- B.createBeginAccess (cleanupLoc, varAddr, SILAccessKind::Modify,
272
- SILAccessEnforcement::Static,
273
- false /* noNestedConflict*/ , false /* fromBuiltin*/ );
274
- SILValue iter =
275
- B.createLoad (cleanupLoc, addr, LoadOwnershipQualifier::Copy);
276
- B.createStore (cleanupLoc, optionalNone, addr,
277
- StoreOwnershipQualifier::Assign);
278
- B.createEndAccess (cleanupLoc, addr, false /* is aborting*/ );
279
- B.createStore (cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Init);
280
-
281
- B.createBranch (cleanupLoc, loopBB);
282
-
283
- // while iter != nil {
284
- B.emitBlock (loopBB);
285
- SILValue operand =
286
- B.createLoad (cleanupLoc, iterAddr, LoadOwnershipQualifier::Copy);
287
- auto operandCopy = B.createCopyValue (cleanupLoc, operand);
288
- auto operandAddr = B.createAllocStack (cleanupLoc, Ty);
289
- B.createStore (cleanupLoc, operandCopy, operandAddr,
290
- StoreOwnershipQualifier::Init);
291
- B.createDestroyValue (cleanupLoc, operand);
292
- B.createSwitchEnumAddr (
293
- cleanupLoc, operandAddr, nullptr ,
294
- {{getASTContext ().getOptionalSomeDecl (), someBB},
295
- {std::make_pair (getASTContext ().getOptionalNoneDecl (), noneBB)}});
296
-
297
- // if isKnownUniquelyReferenced(&iter) {
298
- B.emitBlock (someBB);
299
- B.createDestroyAddr (cleanupLoc, operandAddr);
300
- B.createDeallocStack (cleanupLoc, operandAddr);
301
- auto isUnique = B.createIsUnique (cleanupLoc, iterAddr);
302
- B.createCondBranch (cleanupLoc, isUnique, uniqueBB, notUniqueBB);
303
-
304
- // we have a uniquely referenced link, so we need to deinit
305
- B.emitBlock (uniqueBB);
306
-
307
- // NOTE: We increment the ref count of the tail instead of unlinking it,
308
- // because custom deinit implementations of subclasses may access
309
- // it and it would be semantically wrong to unset it before that.
310
- // Making the tail non-uniquely referenced prevents the recursion.
311
-
312
- // let tail = iter.unsafelyUnwrapped.next
313
- // iter = tail
314
- SILValue _iter =
315
- B.createLoad (cleanupLoc, iterAddr, LoadOwnershipQualifier::Copy);
316
- auto iterBorrow = B.createBeginBorrow (cleanupLoc, _iter);
317
- auto *link = B.createUncheckedEnumData (
318
- cleanupLoc, iterBorrow, getASTContext ().getOptionalSomeDecl (),
319
- SelfTyLowered);
320
- varAddr = B.createRefElementAddr (cleanupLoc, link, vd, Ty.getAddressType ());
321
-
322
- addr = B.createBeginAccess (
323
- cleanupLoc, varAddr, SILAccessKind::Read, SILAccessEnforcement::Static,
324
- false /* noNestedConflict */ , false /* fromBuiltin*/ );
325
- iter = B.createLoad (cleanupLoc, addr, LoadOwnershipQualifier::Copy);
326
- B.createEndAccess (cleanupLoc, addr, false /* is aborting*/ );
327
- B.createStore (cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Assign);
328
250
329
- B.createEndBorrow (cleanupLoc, iterBorrow);
330
-
331
- B.createDestroyValue (cleanupLoc, _iter);
332
-
333
- B.createBranch (cleanupLoc, loopBB);
334
-
335
- // the next link in the chain is not unique, so we are done here
336
- B.emitBlock (notUniqueBB);
337
- B.createBranch (cleanupLoc, cleanBB);
338
-
339
- // we reached the end of the chain
340
- B.emitBlock (noneBB);
341
- B.createDeallocStack (cleanupLoc, operandAddr);
342
- B.createBranch (cleanupLoc, cleanBB);
343
-
344
- B.emitBlock (cleanBB);
345
- B.createDestroyAddr (cleanupLoc, iterAddr);
346
- B.createDeallocStack (cleanupLoc, iterAddr);
347
- }
251
+ SILBasicBlock *cleanBB = createBasicBlock ();
252
+ SILBasicBlock *noneBB = createBasicBlock ();
253
+ SILBasicBlock *notUniqueBB = createBasicBlock ();
254
+ SILBasicBlock *uniqueBB = createBasicBlock ();
255
+ SILBasicBlock *someBB = createBasicBlock ();
256
+ SILBasicBlock *loopBB = createBasicBlock ();
257
+
258
+ // var iter = self.link
259
+ // self.link = nil
260
+ auto Ty = getTypeLowering (F.mapTypeIntoContext (recursiveLink->getInterfaceType ())).getLoweredType ();
261
+ auto optionalNone = B.createOptionalNone (cleanupLoc, Ty);
262
+ SILValue varAddr =
263
+ B.createRefElementAddr (cleanupLoc, selfValue.getValue (), recursiveLink,
264
+ Ty.getAddressType ());
265
+ auto iterAddr = B.createAllocStack (cleanupLoc, Ty);
266
+ SILValue addr = B.createBeginAccess (
267
+ cleanupLoc, varAddr, SILAccessKind::Modify, SILAccessEnforcement::Static,
268
+ true /* noNestedConflict*/ , false /* fromBuiltin*/ );
269
+ SILValue iter = B.createLoad (cleanupLoc, addr, LoadOwnershipQualifier::Take);
270
+ B.createStore (cleanupLoc, optionalNone, addr, StoreOwnershipQualifier::Init);
271
+ B.createEndAccess (cleanupLoc, addr, false /* is aborting*/ );
272
+ B.createStore (cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Init);
273
+
274
+ B.createBranch (cleanupLoc, loopBB);
275
+
276
+ // 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)}});
282
+
283
+ // if isKnownUniquelyReferenced(&iter) {
284
+ B.emitBlock (someBB);
285
+ auto isUnique = B.createIsUnique (cleanupLoc, iterAddr);
286
+ B.createCondBranch (cleanupLoc, isUnique, uniqueBB, notUniqueBB);
287
+
288
+ // 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);
312
+
313
+ B.createStore (cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Assign);
314
+
315
+ B.createBranch (cleanupLoc, loopBB);
316
+
317
+ // the next link in the chain is not unique, so we are done here
318
+ B.emitBlock (notUniqueBB);
319
+ B.createBranch (cleanupLoc, cleanBB);
320
+
321
+ // we reached the end of the chain
322
+ B.emitBlock (noneBB);
323
+ B.createBranch (cleanupLoc, cleanBB);
324
+
325
+ B.emitBlock (cleanBB);
326
+ B.createDestroyAddr (cleanupLoc, iterAddr);
327
+ B.createDeallocStack (cleanupLoc, iterAddr);
348
328
}
349
329
350
330
void SILGenFunction::emitClassMemberDestruction (ManagedValue selfValue,
@@ -375,7 +355,8 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
375
355
finishBB);
376
356
}
377
357
378
- auto recursiveLinks = findRecursiveLinks (cd);
358
+ llvm::SmallSetVector<VarDecl*, 4 > recursiveLinks;
359
+ findRecursiveLinks (cd, recursiveLinks);
379
360
380
361
// / Destroy all members.
381
362
{
@@ -388,8 +369,10 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
388
369
destroyClassMember (cleanupLoc, selfValue, vd);
389
370
}
390
371
391
- if (!recursiveLinks.empty ())
392
- emitRecursiveChainDestruction (selfValue, cd, recursiveLinks, cleanupLoc);
372
+ if (!recursiveLinks.empty ()) {
373
+ assert (recursiveLinks.size () == 1 && " Only linear recursion supported." );
374
+ emitRecursiveChainDestruction (selfValue, cd, recursiveLinks[0 ], cleanupLoc);
375
+ }
393
376
394
377
if (finishBB)
395
378
B.createBranch (cleanupLoc, finishBB);
0 commit comments