Skip to content

Commit

Permalink
Add some broken tests for invalidation
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy committed Jun 3, 2020
1 parent 65c2a03 commit dfe2fc9
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
1 change: 1 addition & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ end

==(x::Expr, y::Expr) = x.head === y.head && isequal(x.args, y.args)
==(x::QuoteNode, y::QuoteNode) = isequal(x.value, y.value)
==(stmt1::Core.PhiNode, stmt2::Core.PhiNode) = stmt1.edges == stmt2.edges && stmt1.values == stmt2.values

"""
macroexpand(m::Module, x; recursive=true)
Expand Down
112 changes: 112 additions & 0 deletions test/worlds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,115 @@ end
notify(c26506_1)
wait(c26506_2)
@test result26506[1] == 3


## Invalidation tests

function instance(f, types)
m = which(f, types)
inst = nothing
tt = Tuple{typeof(f), types...}
specs = m.specializations
if isa(specs, Nothing)
elseif isa(specs, Core.SimpleVector)
for i = 1:length(specs)
if isassigned(specs, i)
mi = specs[i]::Core.MethodInstance
if mi.specTypes === tt
inst = mi
break
end
end
end
else
Base.visit(specs) do mi
if mi.specTypes === tt
inst = mi
end
end
end
return inst
end

function worlds(mi::Core.MethodInstance)
w = Tuple{UInt,UInt}[]
if isdefined(mi, :cache)
ci = mi.cache
push!(w, (ci.min_world, ci.max_world))
while isdefined(ci, :next)
ci = ci.next
push!(w, (ci.min_world, ci.max_world))
end
end
return w
end

# avoid adding this to Base
function equal(ci1::Core.CodeInfo, ci2::Core.CodeInfo)
return ci1.code == ci2.code &&
ci1.codelocs == ci2.codelocs &&
ci1.ssavaluetypes == ci2.ssavaluetypes &&
ci1.ssaflags == ci2.ssaflags &&
ci1.method_for_inference_limit_heuristics == ci2.method_for_inference_limit_heuristics &&
ci1.linetable == ci2.linetable &&
ci1.slotnames == ci2.slotnames &&
ci1.slotflags == ci2.slotflags &&
ci1.slottypes == ci2.slottypes &&
ci1.rettype == ci2.rettype
end
equal(p1::Pair, p2::Pair) = p1.second == p2.second && equal(p1.first, p2.first)

## Union-splitting based on state-of-the-world: check that each invalidation corresponds to new code
applyf35855(c) = f35855(c[1])
f35855(::Int) = 1
f35855(::Float64) = 2
applyf35855([1])
applyf35855([1.0])
applyf35855(Any[1])
wint = worlds(instance(applyf35855, (Vector{Int},)))
wfloat = worlds(instance(applyf35855, (Vector{Float64},)))
wany2 = worlds(instance(applyf35855, (Vector{Any},)))
src2 = code_typed(applyf35855, (Vector{Any},))[1]
f35855(::String) = 3
applyf35855(Any[1])
@test worlds(instance(applyf35855, (Vector{Int},))) == wint
@test worlds(instance(applyf35855, (Vector{Float64},))) == wfloat
wany3 = worlds(instance(applyf35855, (Vector{Any},)))
src3 = code_typed(applyf35855, (Vector{Any},))[1]
@test (wany3 == wany2) == equal(src3, src2) # don't invalidate unless you also change the code
f35855(::AbstractVector) = 4 # next test would pass if this were ::Vector{Int}
applyf35855(Any[1])
wany4 = worlds(instance(applyf35855, (Vector{Any},)))
src4 = code_typed(applyf35855, (Vector{Any},))[1]
@test_broken (wany4 == wany3) == equal(src4, src3)
f35855(::Dict) = 5
applyf35855(Any[1])
wany5 = worlds(instance(applyf35855, (Vector{Any},)))
src5 = code_typed(applyf35855, (Vector{Any},))[1]
@test (wany5 == wany4) == equal(src5, src4)
f35855(::Set) = 6 # with current settings, this shouldn't invalidate
applyf35855(Any[1])
wany6 = worlds(instance(applyf35855, (Vector{Any},)))
src6 = code_typed(applyf35855, (Vector{Any},))[1]
@test (wany6 == wany5) == equal(src6, src5)

## ambiguities do not trigger invalidation
using Printf
Printf.gen("%f")
mi = instance(+, (AbstractChar, UInt8))
w = worlds(mi)

abstract type FixedPoint35855{T <: Integer} <: Real end
struct Normed35855 <: FixedPoint35855{UInt8}
i::UInt8
Normed35855(i::Integer, _) = new(i % UInt8)
end
(::Type{X})(x::Real) where X<:FixedPoint35855{T} where T = X(round(T, typemax(T)*x), 0)

@test_broken worlds(mi) == w

mi = instance(convert, (Type{Nothing}, String))
w = worlds(mi)
abstract type Colorant35855 end
Base.convert(::Type{C}, c) where C<:Colorant35855 = false
@test_broken worlds(mi) == w

0 comments on commit dfe2fc9

Please sign in to comment.