Skip to content

Commit 8967b5e

Browse files
committed
add some "no invalidations" tests for the sysimage
Test that defining certain handpicked type-method pairs (as a user) doesn't result in 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 787e0d9 commit 8967b5e

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-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: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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, Int32, UInt32, Int64, UInt64, Int128, UInt128, BigInt)
72+
@testset "construction of old int type from new type" begin
73+
broken = (UInt16, Int, UInt)
74+
(Int === Int64) && (broken = (broken..., Int32))
75+
@testset "T: $T" for T int_types
76+
@test test_expr((n -> :(function Base.$T(::$n) end)), Integer) broken=(T broken)
77+
end
78+
end
79+
@testset "construction of new int type from old type" begin
80+
broken = ()
81+
@testset "T: $T" for T int_types
82+
@test test_expr((n -> :(function $n(::$T) end)), Integer) broken=(T broken)
83+
end
84+
end
85+
@testset "arithmetic between old int types and new int type" begin
86+
ops = (:+, :*, :<<, :>>, :>>>)
87+
broken = ()
88+
@testset "T: $T" for T int_types
89+
@testset "op: $op" for op ops
90+
@test (
91+
test_expr((n -> :(function Base.$op(::$n, ::$T) end)), Integer) &&
92+
test_expr((n -> :(function Base.$op(::$T, ::$n) end)), Integer)
93+
) broken=((T, op) broken)
94+
end
95+
end
96+
end
97+
@testset "promotion between old int types and new int type" begin
98+
broken = (Bool, UInt8, Int)
99+
@testset "T: $T" for T int_types
100+
@test (
101+
test_expr((n -> :(function Base.promote_rule(::Type{$T}, ::Type{$n}) end)), Integer) &&
102+
test_expr((n -> :(function Base.promote_rule(::Type{$n}, ::Type{$T}) end)), Integer)
103+
) broken=(T broken)
104+
end
105+
end
106+
@testset "unary functions" begin
107+
fs = (zero, one)
108+
broken = (zero, one)
109+
@testset "f: $f" for f fs
110+
@test test_expr((n -> :(function Base.$f(::$n) end)), Integer) broken=(f broken)
111+
end
112+
end
113+
end
114+
end

0 commit comments

Comments
 (0)