@@ -239,6 +239,13 @@ struct EscapeUtilityTypes {
239
239
///
240
240
let followStores : Bool
241
241
242
+ /// Set to true if an address is stored.
243
+ /// This unusual situation can happen if an address is converted to a raw pointer and that pointer
244
+ /// is stored to a memory location.
245
+ /// In this case the walkers need to follow load instructions even if the visitor and current projection
246
+ /// path don't say so.
247
+ let addressIsStored : Bool
248
+
242
249
/// Not nil, if the exact type of the current value is know.
243
250
///
244
251
/// This is used for destructor analysis.
@@ -251,20 +258,29 @@ struct EscapeUtilityTypes {
251
258
let knownType : Type ?
252
259
253
260
func with( projectionPath: SmallProjectionPath ) -> Self {
254
- return Self ( projectionPath: projectionPath, followStores: self . followStores, knownType: self . knownType)
261
+ return Self ( projectionPath: projectionPath, followStores: self . followStores,
262
+ addressIsStored: self . addressIsStored, knownType: self . knownType)
255
263
}
256
264
257
265
func with( followStores: Bool ) -> Self {
258
- return Self ( projectionPath: self . projectionPath, followStores: followStores, knownType: self . knownType)
266
+ return Self ( projectionPath: self . projectionPath, followStores: followStores,
267
+ addressIsStored: self . addressIsStored, knownType: self . knownType)
259
268
}
260
269
270
+ func with( addressStored: Bool ) -> Self {
271
+ return Self ( projectionPath: self . projectionPath, followStores: self . followStores, addressIsStored: addressStored,
272
+ knownType: self . knownType)
273
+ }
274
+
261
275
func with( knownType: Type ? ) -> Self {
262
- return Self ( projectionPath: self . projectionPath, followStores: self . followStores, knownType: knownType)
276
+ return Self ( projectionPath: self . projectionPath, followStores: self . followStores,
277
+ addressIsStored: self . addressIsStored, knownType: knownType)
263
278
}
264
279
265
280
func merge( with other: EscapePath ) -> EscapePath {
266
281
let mergedPath = self . projectionPath. merge ( with: other. projectionPath)
267
282
let mergedFollowStores = self . followStores || other. followStores
283
+ let mergedAddrStored = self . addressIsStored || other. addressIsStored
268
284
let mergedKnownType : Type ?
269
285
if let ty = self . knownType {
270
286
if let otherTy = other. knownType, ty != otherTy {
@@ -275,7 +291,8 @@ struct EscapeUtilityTypes {
275
291
} else {
276
292
mergedKnownType = other. knownType
277
293
}
278
- return EscapePath ( projectionPath: mergedPath, followStores: mergedFollowStores, knownType: mergedKnownType)
294
+ return EscapePath ( projectionPath: mergedPath, followStores: mergedFollowStores,
295
+ addressIsStored: mergedAddrStored, knownType: mergedKnownType)
279
296
}
280
297
}
281
298
@@ -362,7 +379,10 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
362
379
}
363
380
case is StoreInst , is StoreWeakInst , is StoreUnownedInst :
364
381
let store = instruction as! StoringInstruction
365
- assert ( operand == store. sourceOperand )
382
+ assert ( operand == store. sourceOperand)
383
+ if !followLoads( at: path) {
384
+ return walkUp ( address: store. destination, path: path. with ( addressStored: true ) )
385
+ }
366
386
return walkUp ( address: store. destination, path: path)
367
387
case is DestroyValueInst , is ReleaseValueInst , is StrongReleaseInst :
368
388
if handleDestroy ( of: operand. value, path: path) == . abortWalk {
@@ -456,7 +476,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
456
476
return walkUp ( value: store. source, path: path)
457
477
}
458
478
case let copyAddr as CopyAddrInst :
459
- if !followLoads( at: path. projectionPath ) {
479
+ if !followLoads( at: path) {
460
480
return . continueWalk
461
481
}
462
482
if operand == copyAddr. sourceOperand {
@@ -491,7 +511,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
491
511
// 2. something can escape in a destructor when the context is destroyed
492
512
return walkDownUses ( ofValue: pai, path: path. with ( knownType: nil ) )
493
513
case is LoadInst , is LoadWeakInst , is LoadUnownedInst , is LoadBorrowInst :
494
- if !followLoads( at: path. projectionPath ) {
514
+ if !followLoads( at: path) {
495
515
return . continueWalk
496
516
}
497
517
let svi = instruction as! SingleValueInstruction
@@ -561,7 +581,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
561
581
}
562
582
563
583
// Indirect arguments cannot escape the function, but loaded values from such can.
564
- if !followLoads( at: path. projectionPath ) &&
584
+ if !followLoads( at: path) &&
565
585
// Except for begin_apply: it can yield an address value.
566
586
!apply. isBeginApplyWithIndirectResults {
567
587
return . continueWalk
@@ -622,7 +642,8 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
622
642
// Continue at the destination of an arg-to-arg escape.
623
643
let arg = argOp. value
624
644
625
- let p = Path ( projectionPath: toPath, followStores: false , knownType: nil )
645
+ let p = Path ( projectionPath: toPath, followStores: false , addressIsStored: argPath. addressIsStored,
646
+ knownType: nil )
626
647
if walkUp ( addressOrValue: arg, path: p) == . abortWalk {
627
648
return . abortWalk
628
649
}
@@ -634,8 +655,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
634
655
return isEscaping
635
656
}
636
657
637
- let p = Path ( projectionPath: toPath, followStores: false , knownType: exclusive ? argPath. knownType : nil )
638
-
658
+ let p = Path ( projectionPath: toPath, followStores: false , addressIsStored: argPath. addressIsStored,
659
+ knownType: exclusive ? argPath. knownType : nil )
660
+
639
661
if walkDownUses ( ofValue: result, path: p) == . abortWalk {
640
662
return . abortWalk
641
663
}
@@ -700,7 +722,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
700
722
case let ap as ApplyInst :
701
723
return walkUpApplyResult ( apply: ap, path: path. with ( knownType: nil ) )
702
724
case is LoadInst , is LoadWeakInst , is LoadUnownedInst , is LoadBorrowInst :
703
- if !followLoads( at: path. projectionPath ) {
725
+ if !followLoads( at: path) {
704
726
// When walking up we shouldn't end up at a load where followLoads is false,
705
727
// because going from a (non-followLoads) address to a load always involves a class indirection.
706
728
// There is one exception: loading a raw pointer, e.g.
@@ -743,7 +765,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
743
765
case is AllocStackInst :
744
766
return cachedWalkDown ( addressOrValue: def, path: path. with ( knownType: nil ) )
745
767
case let arg as FunctionArgument :
746
- if !followLoads( at: path. projectionPath ) && arg. convention. isExclusiveIndirect && !path. followStores {
768
+ if !followLoads( at: path) && arg. convention. isExclusiveIndirect && !path. followStores {
747
769
return cachedWalkDown ( addressOrValue: def, path: path. with ( knownType: nil ) )
748
770
} else {
749
771
return isEscaping
@@ -781,7 +803,8 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
781
803
}
782
804
let arg = argOp. value
783
805
784
- let p = Path ( projectionPath: effect. pathPattern, followStores: path. followStores, knownType: nil )
806
+ let p = Path ( projectionPath: effect. pathPattern, followStores: path. followStores,
807
+ addressIsStored: path. addressIsStored, knownType: nil )
785
808
if walkUp ( addressOrValue: arg, path: p) == . abortWalk {
786
809
return . abortWalk
787
810
}
@@ -840,10 +863,11 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
840
863
return false
841
864
}
842
865
843
- private func followLoads( at path: SmallProjectionPath ) -> Bool {
866
+ private func followLoads( at path: Path ) -> Bool {
844
867
return visitor. followLoads ||
845
868
// When part of a class field we have to follow loads.
846
- path. mayHaveClassProjection
869
+ path. projectionPath. mayHaveClassProjection ||
870
+ path. addressIsStored
847
871
}
848
872
849
873
private func pathForArgumentEscapeChecking( _ path: SmallProjectionPath ) -> SmallProjectionPath {
@@ -867,7 +891,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
867
891
868
892
private extension SmallProjectionPath {
869
893
var escapePath : EscapeUtilityTypes . EscapePath {
870
- EscapeUtilityTypes . EscapePath ( projectionPath: self , followStores: false , knownType: nil )
894
+ EscapeUtilityTypes . EscapePath ( projectionPath: self , followStores: false , addressIsStored : false , knownType: nil )
871
895
}
872
896
}
873
897
0 commit comments