@@ -55,8 +55,8 @@ julia> code_escapes((String,)) do s
55
55
return obj
56
56
end
57
57
# 1(↑ _2::String) in Main at REPL[2]:2
58
- 2 ↑ 1 ─ % 1 = % new (Base. RefValue{String}, _2):: Base.RefValue{String} │╻╷╷ Ref
59
- 3 ◌ └── return % 1 │
58
+ ↑ 1 ─ % 1 = % new (Base. RefValue{String}, _2):: Base.RefValue{String}
59
+ ◌ └── return % 1
60
60
```
61
61
62
62
The key observation here is that this backward analysis allows escape information to flow
@@ -73,13 +73,13 @@ julia> code_escapes((Bool, String, String)) do cnd, s, t
73
73
end
74
74
return obj
75
75
end
76
- # 3(↑ _2::Bool, ↑ _3::String, ↑ _4::String) in Main at REPL[3]:2
77
- 2 ◌ 1 ─ goto # 3 if not _2 │
78
- 3 ↑ 2 ─ % 2 = % new (Base. RefValue{String}, _3):: Base.RefValue{String} │╻╷╷ Ref
79
- ◌ └── goto # 4 │
80
- 5 ↑ 3 ─ % 4 = % new (Base. RefValue{String}, _4):: Base.RefValue{String} │╻╷╷ Ref
81
- 7 ↑ 4 ┄ % 5 = φ (# 2 => %2, #3 => %4)::Base.RefValue{String} │
82
- ◌ └── return % 5 │
76
+ # 3(✓ _2::Bool, ↑ _3::String, ↑ _4::String) in Main at REPL[3]:2
77
+ ◌ 1 ─ goto # 3 if not _2
78
+ ↑ 2 ─ % 2 = % new (Base. RefValue{String}, _3):: Base.RefValue{String}
79
+ ◌ └── goto # 4
80
+ ↑ 3 ─ % 4 = % new (Base. RefValue{String}, _4):: Base.RefValue{String}
81
+ ↑ 4 ┄ % 5 = φ (# 2 => %2, #3 => %4)::Base.RefValue{String}
82
+ ◌ └── return % 5
83
83
```
84
84
85
85
### [Alias Analysis](@id EA-Alias-Analysis)
@@ -107,10 +107,10 @@ julia> code_escapes((String,)) do s
107
107
return v
108
108
end
109
109
# 5(↑ _2::String) in Main at REPL[7]:2
110
- 2 ✓′ 1 ─ % 1 = % new (SafeRef{String}, " init" ):: SafeRef{String} │╻╷ SafeRef
111
- 3 ◌ │ Base. setfield! (% 1 , :x , _2):: String │╻╷ setindex!
112
- 4 ↑ │ % 3 = Base. getfield (% 1 , :x ):: String │╻╷ getindex
113
- 5 ◌ └── return % 3 │
110
+ ✓′ 1 ─ % 1 = % new (SafeRef{String}, " init" ):: SafeRef{String}
111
+ ◌ │ Base. setfield! (% 1 , :x , _2):: String
112
+ ↑ │ % 3 = Base. getfield (% 1 , :x ):: String
113
+ ◌ └── return % 3
114
114
```
115
115
In the example above, `ReturnEscape` imposed on `%3` (corresponding to `v`) is _not_ directly
116
116
propagated to `%1` (corresponding to `obj`) but rather that `ReturnEscape` is only propagated
@@ -139,16 +139,16 @@ julia> code_escapes((Bool, String,)) do cond, x
139
139
y = ϕ1[]
140
140
return y
141
141
end
142
- # 7(↑ _2::Bool, ↑ _3::String) in Main at REPL[8]:2
143
- 2 ◌ 1 ─ goto # 3 if not _2 │
144
- 3 ✓′ 2 ─ % 2 = % new (SafeRef{String}, " foo" ):: SafeRef{String} │╻╷ SafeRef
145
- ◌ └── goto # 4 │
146
- 5 ✓′ 3 ─ % 4 = % new (SafeRef{String}, " bar" ):: SafeRef{String} │╻╷ SafeRef
147
- 7 ✓′ 4 ┄ % 5 = φ (# 2 => %2, #3 => %4)::SafeRef{String} │
148
- ✓′ │ % 6 = φ (# 2 => %2, #3 => %4)::SafeRef{String} │
149
- ◌ │ Base. setfield! (% 5 , :x , _3):: String │╻ setindex!
150
- 8 ↑ │ % 8 = Base. getfield (% 6 , :x ):: String │╻╷ getindex
151
- 9 ◌ └── return % 8 │
142
+ # 7(✓ _2::Bool, ↑ _3::String) in Main at REPL[8]:2
143
+ ◌ 1 ─ goto # 3 if not _2
144
+ ✓′ 2 ─ % 2 = % new (SafeRef{String}, " foo" ):: SafeRef{String}
145
+ ◌ └── goto # 4
146
+ ✓′ 3 ─ % 4 = % new (SafeRef{String}, " bar" ):: SafeRef{String}
147
+ ✓′ 4 ┄ % 5 = φ (# 2 => %2, #3 => %4)::SafeRef{String}
148
+ ✓′ │ % 6 = φ (# 2 => %2, #3 => %4)::SafeRef{String}
149
+ ◌ │ Base. setfield! (% 5 , :x , _3):: String
150
+ ↑ │ % 8 = Base. getfield (% 6 , :x ):: String
151
+ ◌ └── return % 8
152
152
```
153
153
`ϕ1 = %5` and `ϕ2 = %6` are aliased and thus `ReturnEscape` imposed on `%8 = Base.getfield(%6, :x)::String` (corresponding to `y = ϕ1[]`)
154
154
needs to be propagated to `Base.setfield!(%5, :x, _3)::String` (corresponding to `ϕ2[] = x`).
@@ -176,7 +176,7 @@ julia> code_escapes((String,)) do s
176
176
push! (ary, SafeRef (s))
177
177
return ary[1 ], length (ary)
178
178
end
179
- # 21 (↑ _2::String) in Main at none :2
179
+ # 9 (↑ _2::String) in Main at REPL[9] :2
180
180
* ′ 1 ── % 1 = $ (Expr (:foreigncall , :(:jl_alloc_array_1d ), Vector{Any}, svec (Any, Int64), 0 , :(:ccall ), Vector{Any}, 0 , 0 )):: Vector{Any}
181
181
↑ │ % 2 = % new (SafeRef{String}, _2):: SafeRef{String}
182
182
◌ │ % 3 = Core. lshr_int (1 , 63 ):: Int64
@@ -218,7 +218,7 @@ julia> code_escapes((String,String)) do s, t
218
218
ary[2 ] = SafeRef (t)
219
219
return ary[1 ], length (ary)
220
220
end
221
- # 23 (↑ _2::String, * _3::String) in Main at none :2
221
+ # 11 (↑ _2::String, * _3::String) in Main at REPL[10] :2
222
222
* ′ 1 ─ % 1 = $ (Expr (:foreigncall , :(:jl_alloc_array_1d ), Vector{Any}, svec (Any, Int64), 0 , :(:ccall ), Vector{Any}, 2 , 2 )):: Vector{Any}
223
223
↑ │ % 2 = % new (SafeRef{String}, _2):: SafeRef{String}
224
224
◌ │ Base. arrayset (true , % 1 , % 2 , 1 ):: Vector{Any}
@@ -264,7 +264,7 @@ julia> code_escapes((String,String)) do s, t
264
264
ary[2 ] = SafeRef (t)
265
265
return ary[1 ], length (ary)
266
266
end
267
- # 27 (↑ _2::String, ↑ _3::String) in Main at none :2
267
+ # 13 (↑ _2::String, ↑ _3::String) in Main at REPL[11] :2
268
268
◌ 1 ─ % 1 = Main. nothing :: Core.Const (nothing )
269
269
◌ │ % 2 = Main. nothing :: Core.Const (nothing )
270
270
◌ │ % 3 = Core. tuple (% 1 , % 2 ):: Core.Const ((nothing , nothing ))
@@ -310,7 +310,7 @@ julia> code_escapes((String,String)) do s, t
310
310
push! (ary, SafeRef (t))
311
311
ary[1 ], length (ary)
312
312
end
313
- # 31 (↑ _2::String, ↑ _3::String) in Main at none :2
313
+ # 15 (↑ _2::String, ↑ _3::String) in Main at REPL[12] :2
314
314
* ′ 1 ── % 1 = $ (Expr (:foreigncall , :(:jl_alloc_array_1d ), Vector{Any}, svec (Any, Int64), 0 , :(:ccall ), Vector{Any}, 0 , 0 )):: Vector{Any}
315
315
↑ │ % 2 = % new (SafeRef{String}, _2):: SafeRef{String}
316
316
◌ │ % 3 = Core. lshr_int (1 , 63 ):: Int64
@@ -395,24 +395,24 @@ julia> code_escapes() do
395
395
end
396
396
return t
397
397
end
398
- # 9 () in Main at REPL[12 ]:2
399
- 2 X 1 ── % 1 = % new (Base. RefValue{String}):: Base.RefValue{String} │╻╷ Ref
400
- 4 ◌ 2 ── % 2 = $ (Expr (:enter , # 8)) │
401
- 5 ◌ 3 ── % 3 = Base. isdefined (% 1 , :x ):: Bool │╻╷ get′
402
- ◌ └─── goto # 5 if not %3 ││
403
- ↑ 4 ── % 5 = Base. getfield (% 1 , :x ):: String ││╻ getindex
404
- ◌ └─── goto # 6 ││
405
- ◌ 5 ── Main. throw (% 1 ):: Union{} ││
406
- ◌ └─── unreachable ││
407
- ◌ 6 ── $ (Expr (:leave , 1 )) │
408
- ◌ 7 ── goto # 10 │
409
- ◌ 8 ── $ (Expr (:leave , 1 )) │
410
- ◌ 9 ── % 12 = $ (Expr (:the_exception )):: Any │
411
- 7 ↑ │ % 13 = Main. typeof (% 12 ):: DataType │
412
- 8 ◌ │ invoke Main. rethrow_escape! ():: Any │
413
- ◌ └─── $ (Expr (:pop_exception , :(% 2 ))):: Any │
414
- 10 ↑ 10 ┄ % 16 = φ (# 7 => %5, #9 => %13)::Union{DataType, String} │
415
- ◌ └─── return % 16 │
398
+ # 17 () in Main at REPL[16 ]:2
399
+ X 1 ── % 1 = % new (Base. RefValue{String}):: Base.RefValue{String}
400
+ ◌ 2 ── % 2 = $ (Expr (:enter , # 8))
401
+ ◌ 3 ── % 3 = Base. isdefined (% 1 , :x ):: Bool
402
+ ◌ └─── goto # 5 if not %3
403
+ ↑ 4 ── % 5 = Base. getfield (% 1 , :x ):: String
404
+ ◌ └─── goto # 6
405
+ ◌ 5 ── Main. throw (% 1 ):: Union{}
406
+ ◌ └─── unreachable
407
+ ◌ 6 ── $ (Expr (:leave , 1 ))
408
+ ◌ 7 ── goto # 10
409
+ ◌ 8 ── $ (Expr (:leave , 1 ))
410
+ ✓ 9 ── % 12 = $ (Expr (:the_exception )):: Any
411
+ ↑ │ % 13 = Main. typeof (% 12 ):: DataType
412
+ ◌ │ invoke Main. rethrow_escape! ():: Any
413
+ ◌ └─── $ (Expr (:pop_exception , :(% 2 ))):: Any
414
+ ↑ 10 ┄ % 16 = φ (# 7 => %5, #9 => %13)::Union{DataType, String}
415
+ ◌ └─── return % 16
416
416
```
417
417
418
418
It requires a global analysis in order to correctly reason about all possible escapes via
@@ -439,34 +439,34 @@ julia> result = code_escapes((String,String)) do s1, s2
439
439
s2 = get′ (r2) # still `r2` doesn't escape fully
440
440
return s2
441
441
end
442
- # 11 (X _2::String, ↑ _3::String) in Main at REPL[13 ]:2
443
- 2 X 1 ── % 1 = % new (Base. RefValue{String}, _2):: Base.RefValue{String} │╻╷╷ Ref
444
- 3 * ′ └─── % 2 = % new (Base. RefValue{String}, _3):: Base.RefValue{String} │╻╷╷ Ref
445
- 5 ◌ 2 ── % 3 = $ (Expr (:enter , # 8)) │
446
- * ′ └─── % 4 = ϒ (% 2 ):: Base.RefValue{String} │
447
- 6 ◌ 3 ── % 5 = Base. isdefined (% 1 , :x ):: Bool │╻╷ get′
448
- ◌ └─── goto # 5 if not %5 ││
449
- X 4 ── Base. getfield (% 1 , :x ):: String ││╻ getindex
450
- ◌ └─── goto # 6 ││
451
- ◌ 5 ── Main. throw (% 1 ):: Union{} ││
452
- ◌ └─── unreachable ││
453
- 7 ◌ 6 ── nothing :: typeof (Core. sizeof) │╻ sizeof
454
- ◌ │ nothing :: Int64 ││
455
- ◌ └─── $ (Expr (:leave , 1 )) │
456
- ◌ 7 ── goto # 10 │
457
- * ′ 8 ── % 15 = φᶜ (% 4 ):: Base.RefValue{String} │
458
- ◌ └─── $ (Expr (:leave , 1 )) │
459
- X 9 ── % 17 = $ (Expr (:the_exception )):: Any │
460
- 9 ◌ │ (Main. g = % 17 ):: Any │
461
- ◌ └─── $ (Expr (:pop_exception , :(% 3 ))):: Any │
462
- 11 * ′ 10 ┄ % 20 = φ (# 7 => %2, #9 => %15)::Base.RefValue{String} │
463
- ◌ │ % 21 = Base. isdefined (% 20 , :x ):: Bool ││╻ isassigned
464
- ◌ └─── goto # 12 if not %21 ││
465
- ↑ 11 ─ % 23 = Base. getfield (% 20 , :x ):: String │││╻ getproperty
466
- ◌ └─── goto # 13 ││
467
- ◌ 12 ─ Main. throw (% 20 ):: Union{} ││
468
- ◌ └─── unreachable ││
469
- 12 ◌ 13 ─ return % 23 │
442
+ # 19 (X _2::String, ↑ _3::String) in Main at REPL[17 ]:2
443
+ X 1 ── % 1 = % new (Base. RefValue{String}, _2):: Base.RefValue{String}
444
+ * ′ └─── % 2 = % new (Base. RefValue{String}, _3):: Base.RefValue{String}
445
+ ◌ 2 ── % 3 = $ (Expr (:enter , # 8))
446
+ * ′ └─── % 4 = ϒ (% 2 ):: Base.RefValue{String}
447
+ ◌ 3 ── % 5 = Base. isdefined (% 1 , :x ):: Bool
448
+ ◌ └─── goto # 5 if not %5
449
+ X 4 ── Base. getfield (% 1 , :x ):: String
450
+ ◌ └─── goto # 6
451
+ ◌ 5 ── Main. throw (% 1 ):: Union{}
452
+ ◌ └─── unreachable
453
+ ◌ 6 ── nothing :: typeof (Core. sizeof)
454
+ ◌ │ nothing :: Int64
455
+ ◌ └─── $ (Expr (:leave , 1 ))
456
+ ◌ 7 ── goto # 10
457
+ * ′ 8 ── % 15 = φᶜ (% 4 ):: Base.RefValue{String}
458
+ ◌ └─── $ (Expr (:leave , 1 ))
459
+ X 9 ── % 17 = $ (Expr (:the_exception )):: Any
460
+ ◌ │ (Main. g = % 17 ):: Any
461
+ ◌ └─── $ (Expr (:pop_exception , :(% 3 ))):: Any
462
+ * ′ 10 ┄ % 20 = φ (# 7 => %2, #9 => %15)::Base.RefValue{String}
463
+ ◌ │ % 21 = Base. isdefined (% 20 , :x ):: Bool
464
+ ◌ └─── goto # 12 if not %21
465
+ ↑ 11 ─ % 23 = Base. getfield (% 20 , :x ):: String
466
+ ◌ └─── goto # 13
467
+ ◌ 12 ─ Main. throw (% 20 ):: Union{}
468
+ ◌ └─── unreachable
469
+ ◌ 13 ─ return % 23
470
470
```
471
471
472
472
## Analysis Usage
0 commit comments