Skip to content

Commit a3df253

Browse files
authored
Merge branch 'master' into gb/memset
2 parents a891be2 + 636a35d commit a3df253

File tree

126 files changed

+3849
-1855
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+3849
-1855
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
.DS_Store
3535
.idea/*
3636
.vscode/*
37+
.zed/*
3738
*.heapsnapshot
3839
.cache
3940
# Buildkite: Ignore the entire .buildkite directory

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ julia-deps: | $(DIRS) $(build_datarootdir)/julia/base $(build_datarootdir)/julia
8282
julia-stdlib: | $(DIRS) julia-deps
8383
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/stdlib
8484

85-
julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/julia.1 $(build_datarootdir)/julia/julia-config.jl
85+
julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/julia.1 $(build_datarootdir)/julia/julia-config.jl $(build_datarootdir)/julia/juliac.jl $(build_datarootdir)/julia/juliac-buildscript.jl
8686
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/base
8787

8888
julia-libccalltest: julia-deps
@@ -181,7 +181,7 @@ $(build_sysconfdir)/julia/startup.jl: $(JULIAHOME)/etc/startup.jl | $(build_sysc
181181
@echo Creating usr/etc/julia/startup.jl
182182
@cp $< $@
183183

184-
$(build_datarootdir)/julia/julia-config.jl: $(JULIAHOME)/contrib/julia-config.jl | $(build_datarootdir)/julia
184+
$(build_datarootdir)/julia/%: $(JULIAHOME)/contrib/% | $(build_datarootdir)/julia
185185
$(INSTALL_M) $< $(dir $@)
186186

187187
$(build_depsbindir)/stringreplace: $(JULIAHOME)/contrib/stringreplace.c | $(build_depsbindir)
@@ -410,7 +410,7 @@ endif
410410
$(INSTALL_F) $(JULIAHOME)/contrib/julia.appdata.xml $(DESTDIR)$(datarootdir)/metainfo/
411411
# Install terminal info database
412412
ifneq ($(WITH_TERMINFO),0)
413-
cp -R -L $(build_datarootdir)/terminfo $(DESTDIR)$(datarootdir)
413+
cp -R -L $(build_datarootdir)/julia/terminfo $(DESTDIR)$(datarootdir)/julia/
414414
endif
415415

416416
# Update RPATH entries and JL_SYSTEM_IMAGE_PATH if $(private_libdir_rel) != $(build_private_libdir_rel)

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Julia v1.12 Release Notes
44
New language features
55
---------------------
66

7+
- New option `--trim` for building "trimmed" binaries, where code not provably reachable from entry points
8+
is removed. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]).
79
- A new keyword argument `usings::Bool` has been added to `names`. By using this, we can now
810
find all the names available in module `A` by `names(A; all=true, imported=true, usings=true)`. ([#54609])
911
- the `@atomic(...)` macro family supports now the reference assignment syntax, e.g.
@@ -35,6 +37,10 @@ Language changes
3537
expression within a given `:toplevel` expression to make use of macros
3638
defined earlier in the same `:toplevel` expression. ([#53515])
3739

40+
- Trivial infinite loops (like `while true; end`) are no longer undefined
41+
behavior. Infinite loops that actually do things (e.g. have side effects
42+
or sleep) were never and are still not undefined behavior. ([#52999])
43+
3844
Compiler/Runtime improvements
3945
-----------------------------
4046

@@ -57,6 +63,7 @@ variables. ([#53742]).
5763
* New `--trace-compile-timing` option to report how long each method reported by `--trace-compile` took
5864
to compile, in ms. ([#54662])
5965
* `--trace-compile` now prints recompiled methods in yellow or with a trailing comment if color is not supported ([#55763])
66+
* New `--trace-dispatch` option to report methods that are dynamically dispatched ([#55848]).
6067

6168
Multi-threading changes
6269
-----------------------

base/Base.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,6 @@ end
306306
include("hashing.jl")
307307
include("rounding.jl")
308308
include("div.jl")
309-
include("rawbigints.jl")
310309
include("float.jl")
311310
include("twiceprecision.jl")
312311
include("complex.jl")

base/abstractarray.jl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,11 +1101,8 @@ function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle:
11011101
end
11021102
else
11031103
# Dual-iterator implementation
1104-
ret = iterate(iterdest)
1105-
@inbounds for a in src
1106-
idx, state = ret::NTuple{2,Any}
1107-
dest[idx] = a
1108-
ret = iterate(iterdest, state)
1104+
for (Idest, Isrc) in zip(iterdest, itersrc)
1105+
@inbounds dest[Idest] = src[Isrc]
11091106
end
11101107
end
11111108
end

base/abstractdict.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ Dict{String, Float64} with 3 entries:
392392
393393
julia> ans == mergewith(+)(a, b)
394394
true
395+
396+
julia> mergewith(-, Dict(), Dict(:a=>1)) # Combining function only used if key is present in both
397+
Dict{Any, Any} with 1 entry:
398+
:a => 1
395399
```
396400
"""
397401
mergewith(combine, d::AbstractDict, others::AbstractDict...) =

base/compiler/abstractinterpretation.jl

Lines changed: 783 additions & 621 deletions
Large diffs are not rendered by default.

base/compiler/inferencestate.jl

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ mutable struct InferenceState
236236
slottypes::Vector{Any}
237237
src::CodeInfo
238238
cfg::CFG
239-
method_info::MethodInfo
239+
spec_info::SpecInfo
240240

241241
#= intermediate states for local abstract interpretation =#
242242
currbb::Int
@@ -251,6 +251,7 @@ mutable struct InferenceState
251251
stmt_info::Vector{CallInfo}
252252

253253
#= intermediate states for interprocedural abstract interpretation =#
254+
tasks::Vector{WorkThunk}
254255
pclimitations::IdSet{InferenceState} # causes of precision restrictions (LimitedAccuracy) on currpc ssavalue
255256
limitations::IdSet{InferenceState} # causes of precision restrictions (LimitedAccuracy) on return
256257
cycle_backedges::Vector{Tuple{InferenceState, Int}} # call-graph backedges connecting from callee to caller
@@ -293,7 +294,7 @@ mutable struct InferenceState
293294
sptypes = sptypes_from_meth_instance(mi)
294295
code = src.code::Vector{Any}
295296
cfg = compute_basic_blocks(code)
296-
method_info = MethodInfo(src)
297+
spec_info = SpecInfo(src)
297298

298299
currbb = currpc = 1
299300
ip = BitSet(1) # TODO BitSetBoundedMinPrioritySet(1)
@@ -328,6 +329,7 @@ mutable struct InferenceState
328329
limitations = IdSet{InferenceState}()
329330
cycle_backedges = Vector{Tuple{InferenceState,Int}}()
330331
callstack = AbsIntState[]
332+
tasks = WorkThunk[]
331333

332334
valid_worlds = WorldRange(1, get_world_counter())
333335
bestguess = Bottom
@@ -349,9 +351,9 @@ mutable struct InferenceState
349351
restrict_abstract_call_sites = isa(def, Module)
350352

351353
this = new(
352-
mi, world, mod, sptypes, slottypes, src, cfg, method_info,
354+
mi, world, mod, sptypes, slottypes, src, cfg, spec_info,
353355
currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, ssavaluetypes, stmt_edges, stmt_info,
354-
pclimitations, limitations, cycle_backedges, callstack, 0, 0, 0,
356+
tasks, pclimitations, limitations, cycle_backedges, callstack, 0, 0, 0,
355357
result, unreachable, valid_worlds, bestguess, exc_bestguess, ipo_effects,
356358
restrict_abstract_call_sites, cache_mode, insert_coverage,
357359
interp)
@@ -789,7 +791,7 @@ end
789791

790792
# TODO add `result::InferenceResult` and put the irinterp result into the inference cache?
791793
mutable struct IRInterpretationState
792-
const method_info::MethodInfo
794+
const spec_info::SpecInfo
793795
const ir::IRCode
794796
const mi::MethodInstance
795797
const world::UInt
@@ -800,13 +802,14 @@ mutable struct IRInterpretationState
800802
const ssa_refined::BitSet
801803
const lazyreachability::LazyCFGReachability
802804
valid_worlds::WorldRange
805+
const tasks::Vector{WorkThunk}
803806
const edges::Vector{Any}
804807
callstack #::Vector{AbsIntState}
805808
frameid::Int
806809
parentid::Int
807810

808811
function IRInterpretationState(interp::AbstractInterpreter,
809-
method_info::MethodInfo, ir::IRCode, mi::MethodInstance, argtypes::Vector{Any},
812+
spec_info::SpecInfo, ir::IRCode, mi::MethodInstance, argtypes::Vector{Any},
810813
world::UInt, min_world::UInt, max_world::UInt)
811814
curridx = 1
812815
given_argtypes = Vector{Any}(undef, length(argtypes))
@@ -825,10 +828,11 @@ mutable struct IRInterpretationState
825828
ssa_refined = BitSet()
826829
lazyreachability = LazyCFGReachability(ir)
827830
valid_worlds = WorldRange(min_world, max_world == typemax(UInt) ? get_world_counter() : max_world)
831+
tasks = WorkThunk[]
828832
edges = Any[]
829833
callstack = AbsIntState[]
830-
return new(method_info, ir, mi, world, curridx, argtypes_refined, ir.sptypes, tpdum,
831-
ssa_refined, lazyreachability, valid_worlds, edges, callstack, 0, 0)
834+
return new(spec_info, ir, mi, world, curridx, argtypes_refined, ir.sptypes, tpdum,
835+
ssa_refined, lazyreachability, valid_worlds, tasks, edges, callstack, 0, 0)
832836
end
833837
end
834838

@@ -841,14 +845,13 @@ function IRInterpretationState(interp::AbstractInterpreter,
841845
else
842846
isa(src, CodeInfo) || return nothing
843847
end
844-
method_info = MethodInfo(src)
848+
spec_info = SpecInfo(src)
845849
ir = inflate_ir(src, mi)
846850
argtypes = va_process_argtypes(optimizer_lattice(interp), argtypes, src.nargs, src.isva)
847-
return IRInterpretationState(interp, method_info, ir, mi, argtypes, world,
851+
return IRInterpretationState(interp, spec_info, ir, mi, argtypes, world,
848852
codeinst.min_world, codeinst.max_world)
849853
end
850854

851-
852855
# AbsIntState
853856
# ===========
854857

@@ -870,6 +873,7 @@ function print_callstack(frame::AbsIntState)
870873
print(frame_instance(sv))
871874
is_cached(sv) || print(" [uncached]")
872875
sv.parentid == idx - 1 || print(" [parent=", sv.parentid, "]")
876+
isempty(callers_in_cycle(sv)) || print(" [cycle=", sv.cycleid, "]")
873877
println()
874878
@assert sv.frameid == idx
875879
end
@@ -922,11 +926,11 @@ is_constproped(::IRInterpretationState) = true
922926
is_cached(sv::InferenceState) = !iszero(sv.cache_mode & CACHE_MODE_GLOBAL)
923927
is_cached(::IRInterpretationState) = false
924928

925-
method_info(sv::InferenceState) = sv.method_info
926-
method_info(sv::IRInterpretationState) = sv.method_info
929+
spec_info(sv::InferenceState) = sv.spec_info
930+
spec_info(sv::IRInterpretationState) = sv.spec_info
927931

928-
propagate_inbounds(sv::AbsIntState) = method_info(sv).propagate_inbounds
929-
method_for_inference_limit_heuristics(sv::AbsIntState) = method_info(sv).method_for_inference_limit_heuristics
932+
propagate_inbounds(sv::AbsIntState) = spec_info(sv).propagate_inbounds
933+
method_for_inference_limit_heuristics(sv::AbsIntState) = spec_info(sv).method_for_inference_limit_heuristics
930934

931935
frame_world(sv::InferenceState) = sv.world
932936
frame_world(sv::IRInterpretationState) = sv.world
@@ -994,7 +998,10 @@ of the same cycle, only if it is part of a cycle with multiple frames.
994998
function callers_in_cycle(sv::InferenceState)
995999
callstack = sv.callstack::Vector{AbsIntState}
9961000
cycletop = cycleid = sv.cycleid
997-
while cycletop < length(callstack) && (callstack[cycletop + 1]::InferenceState).cycleid == cycleid
1001+
while cycletop < length(callstack)
1002+
frame = callstack[cycletop + 1]
1003+
frame isa InferenceState || break
1004+
frame.cycleid == cycleid || break
9981005
cycletop += 1
9991006
end
10001007
return AbsIntCycle(callstack, cycletop == cycleid ? 0 : cycleid, cycletop)
@@ -1054,6 +1061,7 @@ function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::
10541061
effects = Effects(effects; effect_free=ALWAYS_TRUE)
10551062
end
10561063
caller.ipo_effects = merge_effects(caller.ipo_effects, effects)
1064+
nothing
10571065
end
10581066
merge_effects!(::AbstractInterpreter, ::IRInterpretationState, ::Effects) = return
10591067

@@ -1116,3 +1124,90 @@ function get_max_methods_for_module(mod::Module)
11161124
max_methods < 0 && return nothing
11171125
return max_methods
11181126
end
1127+
1128+
"""
1129+
Future{T}
1130+
1131+
Delayed return value for a value of type `T`, similar to RefValue{T}, but
1132+
explicitly represents completed as a `Bool` rather than as `isdefined`.
1133+
Set once with `f[] = v` and accessed with `f[]` afterwards.
1134+
1135+
Can also be constructed with the `completed` flag value and a closure to
1136+
produce `x`, as well as the additional arguments to avoid always capturing the
1137+
same couple of values.
1138+
"""
1139+
struct Future{T}
1140+
later::Union{Nothing,RefValue{T}}
1141+
now::Union{Nothing,T}
1142+
Future{T}() where {T} = new{T}(RefValue{T}(), nothing)
1143+
Future{T}(x) where {T} = new{T}(nothing, x)
1144+
Future(x::T) where {T} = new{T}(nothing, x)
1145+
end
1146+
isready(f::Future) = f.later === nothing
1147+
getindex(f::Future{T}) where {T} = (later = f.later; later === nothing ? f.now::T : later[])
1148+
setindex!(f::Future, v) = something(f.later)[] = v
1149+
convert(::Type{Future{T}}, x) where {T} = Future{T}(x) # support return type conversion
1150+
convert(::Type{Future{T}}, x::Future) where {T} = x::Future{T}
1151+
function Future{T}(f, immediate::Bool, interp::AbstractInterpreter, sv::AbsIntState) where {T}
1152+
if immediate
1153+
return Future{T}(f(interp, sv))
1154+
else
1155+
@assert applicable(f, interp, sv)
1156+
result = Future{T}()
1157+
push!(sv.tasks, function (interp, sv)
1158+
result[] = f(interp, sv)
1159+
return true
1160+
end)
1161+
return result
1162+
end
1163+
end
1164+
function Future{T}(f, prev::Future{S}, interp::AbstractInterpreter, sv::AbsIntState) where {T, S}
1165+
later = prev.later
1166+
if later === nothing
1167+
return Future{T}(f(prev[], interp, sv))
1168+
else
1169+
@assert Core._hasmethod(Tuple{Core.Typeof(f), S, typeof(interp), typeof(sv)})
1170+
result = Future{T}()
1171+
push!(sv.tasks, function (interp, sv)
1172+
result[] = f(later[], interp, sv) # capture just later, instead of all of prev
1173+
return true
1174+
end)
1175+
return result
1176+
end
1177+
end
1178+
1179+
1180+
"""
1181+
doworkloop(args...)
1182+
1183+
Run a tasks inside the abstract interpreter, returning false if there are none.
1184+
Tasks will be run in DFS post-order tree order, such that all child tasks will
1185+
be run in the order scheduled, prior to running any subsequent tasks. This
1186+
allows tasks to generate more child tasks, which will be run before anything else.
1187+
Each task will be run repeatedly when returning `false`, until it returns `true`.
1188+
"""
1189+
function doworkloop(interp::AbstractInterpreter, sv::AbsIntState)
1190+
tasks = sv.tasks
1191+
prev = length(tasks)
1192+
prev == 0 && return false
1193+
task = pop!(tasks)
1194+
completed = task(interp, sv)
1195+
tasks = sv.tasks # allow dropping gc root over the previous call
1196+
completed isa Bool || throw(TypeError(:return, "", Bool, task)) # print the task on failure as part of the error message, instead of just "@ workloop:line"
1197+
completed || push!(tasks, task)
1198+
# efficient post-order visitor: items pushed are executed in reverse post order such
1199+
# that later items are executed before earlier ones, but are fully executed
1200+
# (including any dependencies scheduled by them) before going on to the next item
1201+
reverse!(tasks, #=start=#prev)
1202+
return true
1203+
end
1204+
1205+
1206+
#macro workthunk(name::Symbol, body)
1207+
# name = esc(name)
1208+
# body = esc(body)
1209+
# return replace_linenums!(
1210+
# :(function $name($(esc(interp)), $(esc(sv)))
1211+
# $body
1212+
# end), __source__)
1213+
#end

base/compiler/optimize.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -644,10 +644,10 @@ function ((; code_cache)::GetNativeEscapeCache)(mi::MethodInstance)
644644
return false
645645
end
646646

647-
function refine_effects!(interp::AbstractInterpreter, sv::PostOptAnalysisState)
647+
function refine_effects!(interp::AbstractInterpreter, opt::OptimizationState, sv::PostOptAnalysisState)
648648
if !is_effect_free(sv.result.ipo_effects) && sv.all_effect_free && !isempty(sv.ea_analysis_pending)
649649
ir = sv.ir
650-
nargs = length(ir.argtypes)
650+
nargs = Int(opt.src.nargs)
651651
estate = EscapeAnalysis.analyze_escapes(ir, nargs, optimizer_lattice(interp), GetNativeEscapeCache(interp))
652652
argescapes = EscapeAnalysis.ArgEscapeCache(estate)
653653
stack_analysis_result!(sv.result, argescapes)
@@ -939,7 +939,8 @@ function check_inconsistentcy!(sv::PostOptAnalysisState, scanner::BBScanner)
939939
end
940940
end
941941

942-
function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result::InferenceResult)
942+
function ipo_dataflow_analysis!(interp::AbstractInterpreter, opt::OptimizationState,
943+
ir::IRCode, result::InferenceResult)
943944
if !is_ipo_dataflow_analysis_profitable(result.ipo_effects)
944945
return false
945946
end
@@ -967,13 +968,13 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result:
967968
end
968969
end
969970

970-
return refine_effects!(interp, sv)
971+
return refine_effects!(interp, opt, sv)
971972
end
972973

973974
# run the optimization work
974975
function optimize(interp::AbstractInterpreter, opt::OptimizationState, caller::InferenceResult)
975-
@timeit "optimizer" ir = run_passes_ipo_safe(opt.src, opt, caller)
976-
ipo_dataflow_analysis!(interp, ir, caller)
976+
@timeit "optimizer" ir = run_passes_ipo_safe(opt.src, opt)
977+
ipo_dataflow_analysis!(interp, opt, ir, caller)
977978
return finish(interp, opt, ir, caller)
978979
end
979980

@@ -995,7 +996,6 @@ matchpass(::Nothing, _, _) = false
995996
function run_passes_ipo_safe(
996997
ci::CodeInfo,
997998
sv::OptimizationState,
998-
caller::InferenceResult,
999999
optimize_until = nothing, # run all passes by default
10001000
)
10011001
__stage__ = 0 # used by @pass

0 commit comments

Comments
 (0)