I am trying to understand memory deallocation behavior at the SIL level.
I have this simple swift program:
import Foundation
class A {
let x: Int
init(x: Int) {
self.x = x
}
}
var _ = A(x: 42)
The SIL that's generated for it looks as below:
1 // Truncated only to show relevant code
2 // main
3 sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
4 bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
5 %2 = metatype $@thick A.Type // user: %6
6 %3 = integer_literal $Builtin.Int64, 42 // user: %4
7 %4 = struct $Int (%3 : $Builtin.Int64) // user: %6
8 // function_ref A.__allocating_init(x:)
9 %5 = function_ref @$s4heap1AC1xACSi_tcfC : $@convention(method) (Int, @thick A.Type) -> @owned A // user: %6
10 %6 = apply %5(%4, %2) : $@convention(method) (Int, @thick A.Type) -> @owned A // user: %7
11 strong_release %6 : $A // id: %7
12 %8 = integer_literal $Builtin.Int32, 0 // user: %9
13 %9 = struct $Int32 (%8 : $Builtin.Int32) // user: %10
14 return %9 : $Int32 // id: %10
15 } // end sil function 'main'
16
17 // A.__deallocating_deinit
18 sil hidden @$s4heap1ACfD : $@convention(method) (@owned A) -> () {
19 // %0 "self" // users: %3, %1
20 bb0(%0 : $A):
21 debug_value %0 : $A, let, name "self", argno 1, implicit // id: %1
22 // function_ref A.deinit
23 %2 = function_ref @$s4heap1ACfd : $@convention(method) (@guaranteed A) -> @owned Builtin.NativeObject // user: %3
24 %3 = apply %2(%0) : $@convention(method) (@guaranteed A) -> @owned Builtin.NativeObject // user: %4
25 %4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $A // user: %5
26 dealloc_ref %4 : $A // id: %5
27 %6 = tuple () // user: %7
28 return %6 : $() // id: %7
29 } // end sil function '$s4heap1ACfD'
I believe line 26 is responsible for freeing memory allocated for an object of type A
. This makes sense as dealloc_ref
bypasses the reference counting mechanism and deallocated the object on the heap.
However, if I comment out line 26 in the SIL code, leaks
shows me that there is a memory leak. I would expect that strong_release
on line 11 should achieve the same outcome -- since the object's reference count will go to zero and it should be cleaned up. In order to make sure the reference count is actually going to 0 I added multiple strong_release
instructions and the memory still leaks.
Have I misunderstood what strong_release
does?