Skip to content

Commit 2fc945e

Browse files
committed
add some "no invalidations" tests for the sysimage
Test that adding certain handpicked type-method pairs doesn't cause any invalidation of the sysimage. Some of the tests are marked as broken. Merging this will make the contribution process more demanding: when someone makes a PR they might need to fix unrelated type stability issues, or decrease `max_methods` for some function before being able to merge their initial PR. However that's better than ignoring the constant danger of type instability/invalidation regressions making the sysimage and precompilation less useful.
1 parent 8e03cb1 commit 2fc945e

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

test/choosetests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const TESTNAMES = [
1616
"operators", "ordering", "path", "ccall", "parse", "loading", "gmp",
1717
"sorting", "spawn", "backtrace", "exceptions",
1818
"file", "read", "version", "namedtuple",
19-
"mpfr", "broadcast", "complex",
19+
"mpfr", "broadcast", "complex", "no_invalidations",
2020
"floatapprox", "stdlib", "reflection", "regex", "float16",
2121
"combinatorics", "sysinfo", "env", "rounding", "ranges", "mod2pi",
2222
"euler", "show", "client", "terminfo",

test/no_invalidations.jl

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
using Test
4+
5+
module ThereAreNoInvalidations
6+
function julia_expr_cmd(expr::Expr)
7+
`$(Base.julia_cmd()) -e $expr`
8+
end
9+
function readline_julia_expr_cmd(expr::Expr)
10+
open(readline, julia_expr_cmd(expr))
11+
end
12+
function invalidations_expr(expr::Expr)
13+
quote
14+
try
15+
let invs = ccall(:jl_debug_method_invalidation, Any, (Cint,), 1)
16+
@eval $expr
17+
invs
18+
end
19+
finally
20+
ccall(:jl_debug_method_invalidation, Any, (Cint,), 0)
21+
end
22+
end
23+
end
24+
function there_are_no_invalidations_expr(expr::Expr)
25+
e = invalidations_expr(expr)
26+
quote
27+
let invalidations = $e
28+
show(isempty(invalidations))
29+
end
30+
end
31+
end
32+
function there_are_no_invalidations(expr::Expr)
33+
e = there_are_no_invalidations_expr(expr)
34+
s = readline_julia_expr_cmd(e)
35+
parse(Bool, s)
36+
end
37+
end
38+
39+
function type_expr(f, supertype::Type)
40+
type_name = :T
41+
rest = f(type_name)
42+
quote
43+
struct $type_name <: $supertype end
44+
$rest
45+
end
46+
end
47+
48+
function test_expr(f, supertype::Type)
49+
e = type_expr(f, supertype)
50+
ThereAreNoInvalidations.there_are_no_invalidations(e)
51+
end
52+
53+
@testset "no invalidations test set" begin
54+
@testset "2-arg `show` for various new types" begin
55+
stypes = (Integer, AbstractString, DenseVector{UInt8}, DenseMatrix{Float32}, AbstractUnitRange{Int})
56+
broken = (AbstractString,)
57+
@testset "S: $S" for S stypes
58+
@test test_expr((n -> :(function Base.show(::IO, ::$n) end)), S) broken=(S broken)
59+
end
60+
end
61+
@testset "new subtype of `AbstractString`" begin
62+
@testset "index-related" begin
63+
fs = (thisind, prevind, nextind)
64+
broken = (thisind, prevind, nextind)
65+
@testset "f: $f" for f fs
66+
@test test_expr((n -> :(function Base.$f(::$n, ::Int) end)), AbstractString) broken=(f broken)
67+
end
68+
end
69+
end
70+
@testset "new subtype of `Integer`" begin
71+
int_types = (Bool, Int8, UInt8, Int16, UInt16, Int, UInt, BigInt)
72+
@testset "construction of old int type from new type" begin
73+
broken = (Int8, UInt8, UInt16, Int, UInt)
74+
@testset "T: $T" for T int_types
75+
@test test_expr((n -> :(function Base.$T(::$n) end)), Integer) broken=(T broken)
76+
end
77+
end
78+
@testset "construction of new int type from old type" begin
79+
broken = ()
80+
@testset "T: $T" for T int_types
81+
@test test_expr((n -> :(function $n(::$T) end)), Integer) broken=(T broken)
82+
end
83+
end
84+
@testset "arithmetic between old int types and new int type" begin
85+
ops = (:+, :*)
86+
broken = ()
87+
@testset "T: $T" for T int_types
88+
@testset "op: $op" for op ops
89+
@test (
90+
test_expr((n -> :(function Base.$op(::$n, ::$T) end)), Integer) &&
91+
test_expr((n -> :(function Base.$op(::$T, ::$n) end)), Integer)
92+
) broken=((T, op) broken)
93+
end
94+
end
95+
end
96+
@testset "promotion between old int types and new int type" begin
97+
broken = (Bool, UInt8, Int)
98+
@testset "T: $T" for T int_types
99+
@test (
100+
test_expr((n -> :(function Base.promote_rule(::Type{$T}, ::Type{$n}) end)), Integer) &&
101+
test_expr((n -> :(function Base.promote_rule(::Type{$n}, ::Type{$T}) end)), Integer)
102+
) broken=(T broken)
103+
end
104+
end
105+
@testset "unary functions" begin
106+
@test test_expr((n -> :(function Base.zero(::$n) end)), Integer) broken=true
107+
@test test_expr((n -> :(function Base.one(::$n) end)), Integer) broken=true
108+
end
109+
end
110+
end

0 commit comments

Comments
 (0)