Skip to content

Commit f5ce249

Browse files
authored
Compiler: avoid type instability in access to PartialStruct field (#57553)
The `Base.getproperty` method for `PartialStruct` has a type assert to ensure type stable access of the field `undef`. However Compiler.jl has `Compiler.getproperty === Core.getfield`. Introduce a getter for this field of `PartialStruct` into Compiler.jl and use it. I guess this should improve compiler performance, and it should help avoid spurious invalidation.
1 parent 5f13cd2 commit f5ce249

File tree

4 files changed

+21
-13
lines changed

4 files changed

+21
-13
lines changed

Compiler/src/Compiler.jl

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ const modifyproperty! = Core.modifyfield!
8383
const replaceproperty! = Core.replacefield!
8484
const _DOCS_ALIASING_WARNING = ""
8585

86+
function _getundef(p::PartialStruct)
87+
Base.getproperty(p, :undef)
88+
end
89+
8690
ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false)
8791

8892
eval(x) = Core.eval(Compiler, x)

Compiler/src/typeinfer.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid::
514514
rettype_const = result_type.parameters[1]
515515
const_flags = 0x2
516516
elseif isa(result_type, PartialStruct)
517-
rettype_const = (result_type.undef, result_type.fields)
517+
rettype_const = (_getundef(result_type), result_type.fields)
518518
const_flags = 0x2
519519
elseif isa(result_type, InterConditional)
520520
rettype_const = result_type

Compiler/src/typelattice.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ end
318318
fields = vartyp.fields
319319
thenfields = thentype === Bottom ? nothing : copy(fields)
320320
elsefields = elsetype === Bottom ? nothing : copy(fields)
321-
undef = copy(vartyp.undef)
321+
undef = copy(_getundef(vartyp))
322322
if 1 fldidx length(fields)
323323
thenfields === nothing || (thenfields[fldidx] = thentype)
324324
elsefields === nothing || (elsefields[fldidx] = elsetype)
@@ -548,7 +548,7 @@ end
548548
if isa(a, PartialStruct)
549549
isa(b, PartialStruct) || return false
550550
length(a.fields) == length(b.fields) || return false
551-
a.undef == b.undef || return false
551+
_getundef(a) == _getundef(b) || return false
552552
widenconst(a) == widenconst(b) || return false
553553
a.fields === b.fields && return true # fast path
554554
for i in 1:length(a.fields)

Compiler/src/typelimits.jl

+14-10
Original file line numberDiff line numberDiff line change
@@ -329,17 +329,19 @@ end
329329
is_field_maybe_undef(t::Const, i) = !isdefined(t.val, i)
330330

331331
function n_initialized(pstruct::PartialStruct)
332-
i = findfirst(pstruct.undef)
332+
pstruct_undef = _getundef(pstruct)
333+
i = findfirst(pstruct_undef)
333334
nmin = datatype_min_ninitialized(pstruct.typ)
334-
i === nothing && return max(length(pstruct.undef), nmin)
335+
i === nothing && return max(length(pstruct_undef), nmin)
335336
n = i::Int - 1
336337
@assert n nmin
337338
n
338339
end
339340

340341
function is_field_maybe_undef(pstruct::PartialStruct, fi)
341342
fi 1 || return true
342-
fi length(pstruct.undef) && return pstruct.undef[fi]
343+
pstruct_undef = _getundef(pstruct)
344+
fi length(pstruct_undef) && return pstruct_undef[fi]
343345
fi > datatype_min_ninitialized(pstruct.typ)
344346
end
345347

@@ -350,8 +352,9 @@ function partialstruct_getfield(pstruct::PartialStruct, fi::Integer)
350352
end
351353

352354
function refines_definedness_information(pstruct::PartialStruct)
353-
nflds = length(pstruct.undef)
354-
something(findfirst(pstruct.undef), nflds + 1) - 1 > datatype_min_ninitialized(pstruct.typ)
355+
pstruct_undef = _getundef(pstruct)
356+
nflds = length(pstruct_undef)
357+
something(findfirst(pstruct_undef), nflds + 1) - 1 > datatype_min_ninitialized(pstruct.typ)
355358
end
356359

357360
function define_field(pstruct::PartialStruct, fi::Int)
@@ -362,19 +365,20 @@ function define_field(pstruct::PartialStruct, fi::Int)
362365

363366
new = expand_partialstruct(pstruct, fi)
364367
if new === nothing
365-
new = PartialStruct(fallback_lattice, pstruct.typ, copy(pstruct.undef), copy(pstruct.fields))
368+
new = PartialStruct(fallback_lattice, pstruct.typ, copy(_getundef(pstruct)), copy(pstruct.fields))
366369
end
367-
new.undef[fi] = false
370+
_getundef(new)[fi] = false
368371
return new
369372
end
370373

371374
function expand_partialstruct(pstruct::PartialStruct, until::Int)
372-
n = length(pstruct.undef)
375+
pstruct_undef = _getundef(pstruct)
376+
n = length(pstruct_undef)
373377
until n && return nothing
374378

375379
undef = partialstruct_init_undef(pstruct.typ, until; all_defined = false)
376380
for i in 1:n
377-
undef[i] &= pstruct.undef[i]
381+
undef[i] &= pstruct_undef[i]
378382
end
379383
nf = length(pstruct.fields)
380384
typ = pstruct.typ
@@ -393,7 +397,7 @@ end
393397
@assert n_initialized(typea) n_initialized(typeb) "typeb ⊑ typea is assumed"
394398
elseif typeb isa PartialStruct
395399
@assert n_initialized(typea) n_initialized(typeb) &&
396-
all(b < a for (a, b) in zip(typea.undef, typeb.undef)) "typeb ⊑ typea is assumed"
400+
all(b < a for (a, b) in zip(_getundef(typea), _getundef(typeb))) "typeb ⊑ typea is assumed"
397401
else
398402
return false
399403
end

0 commit comments

Comments
 (0)