• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #38002

06 Feb 2025 06:14AM UTC coverage: 20.322% (-2.4%) from 22.722%
#38002

push

local

web-flow
bpart: Fully switch to partitioned semantics (#57253)

This is the final PR in the binding partitions series (modulo bugs and
tweaks), i.e. it closes #54654 and thus closes #40399, which was the
original design sketch.

This thus activates the full designed semantics for binding partitions,
in particular allowing safe replacement of const bindings. It in
particular allows struct redefinitions. This thus closes
timholy/Revise.jl#18 and also closes #38584.

The biggest semantic change here is probably that this gets rid of the
notion of "resolvedness" of a binding. Previously, a lot of the behavior
of our implementation depended on when bindings were "resolved", which
could happen at basically an arbitrary point (in the compiler, in REPL
completion, in a different thread), making a lot of the semantics around
bindings ill- or at least implementation-defined. There are several
related issues in the bugtracker, so this closes #14055 closes #44604
closes #46354 closes #30277

It is also the last step to close #24569.
It also supports bindings for undef->defined transitions and thus closes
#53958 closes #54733 - however, this is not activated yet for
performance reasons and may need some further optimization.

Since resolvedness no longer exists, we need to replace it with some
hopefully more well-defined semantics. I will describe the semantics
below, but before I do I will make two notes:

1. There are a number of cases where these semantics will behave
slightly differently than the old semantics absent some other task going
around resolving random bindings.
2. The new behavior (except for the replacement stuff) was generally
permissible under the old semantics if the bindings happened to be
resolved at the right time.

With all that said, there are essentially three "strengths" of bindings:

1. Implicit Bindings: Anything implicitly obtained from `using Mod`, "no
binding", plus slightly more exotic corner cases around conflicts

2. Weakly declared bindin... (continued)

11 of 111 new or added lines in 7 files covered. (9.91%)

1273 existing lines in 68 files now uncovered.

9908 of 48755 relevant lines covered (20.32%)

105126.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.42
/base/Base.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
const start_base_include = time_ns()
4

5
include("reflection.jl")
6
include("refpointer.jl")
7

8
# now replace the Pair constructor (relevant for NamedTuples) with one that calls our Base.convert
9
delete_method(which(Pair{Any,Any}, (Any, Any)))
10
@eval function (P::Type{Pair{A, B}})(@nospecialize(a), @nospecialize(b)) where {A, B}
11
    @inline
38✔
12
    return $(Expr(:new, :P, :(a isa A ? a : convert(A, a)), :(b isa B ? b : convert(B, b))))
65,719✔
13
end
14

15
# The REPL stdlib hooks into Base using this Ref
16
const REPL_MODULE_REF = Ref{Module}(Base)
17
process_sysimg_args!()
18

19
include(strcat(BUILDROOT, "build_h.jl"))     # include($BUILDROOT/base/build_h.jl)
20
include(strcat(BUILDROOT, "version_git.jl")) # include($BUILDROOT/base/version_git.jl)
21

22
# Initialize DL_LOAD_PATH as early as possible.  We are defining things here in
23
# a slightly more verbose fashion than usual, because we're running so early.
24
const DL_LOAD_PATH = String[]
25
let os = ccall(:jl_get_UNAME, Any, ())
26
    if os === :Darwin || os === :Apple
27
        if Base.DARWIN_FRAMEWORK
28
            push!(DL_LOAD_PATH, "@loader_path/Frameworks")
29
        end
30
        push!(DL_LOAD_PATH, "@loader_path")
31
    end
32
end
33

34
# subarrays
35
include("subarray.jl")
36
include("views.jl")
37

38
# numeric operations
39
include("hashing.jl")
40
include("rounding.jl")
41
include("div.jl")
42
include("float.jl")
43
include("twiceprecision.jl")
44
include("complex.jl")
45
include("rational.jl")
46
include("multinverses.jl")
47
using .MultiplicativeInverses
48
include("abstractarraymath.jl")
49
include("arraymath.jl")
50
include("slicearray.jl")
51

52
# SIMD loops
53
sizeof(s::String) = Core.sizeof(s)  # needed by gensym as called from simdloop
1,486,809✔
54
include("simdloop.jl")
55
using .SimdLoop
56

57
# map-reduce operators
58
include("reduce.jl")
59

60
## core structures
61
include("reshapedarray.jl")
62
include("reinterpretarray.jl")
63

64
include("multimedia.jl")
65
using .Multimedia
66

67
# Some type
68
include("some.jl")
69

70
include("dict.jl")
71
include("set.jl")
72

73
# Strings
74
include("char.jl")
75
function array_new_memory(mem::Memory{UInt8}, newlen::Int)
76
    # add an optimization to array_new_memory for StringVector
UNCOV
77
    if (@assume_effects :total @ccall jl_genericmemory_owner(mem::Any,)::Any) === mem
×
78
        # TODO: when implemented, this should use a memory growing call
79
        return typeof(mem)(undef, newlen)
×
80
    else
81
        # If data is in a String, keep it that way.
82
        # When implemented, this could use jl_gc_expand_string(oldstr, newlen) as an optimization
UNCOV
83
        str = _string_n(newlen)
×
UNCOV
84
        return (@assume_effects :total !:consistent @ccall jl_string_to_genericmemory(str::Any,)::Memory{UInt8})
×
85
    end
86
end
87
include("strings/basic.jl")
88
include("strings/string.jl")
89
include("strings/substring.jl")
90
include("strings/cstring.jl")
91

92
include("osutils.jl")
93

94
# Core I/O
95
include("io.jl")
96
include("iobuffer.jl")
97

98
# Concurrency (part 1)
99
include("linked_list.jl")
100
include("condition.jl")
101
include("threads.jl")
102
include("lock.jl")
103

104
# strings & printing
105
include("intfuncs.jl")
106
include("strings/strings.jl")
107
include("regex.jl")
108
include("parse.jl")
109
include("shell.jl")
110
include("show.jl")
111
include("arrayshow.jl")
112
include("methodshow.jl")
113

114
# multidimensional arrays
115
include("cartesian.jl")
116
using .Cartesian
117
include("multidimensional.jl")
118

119
include("broadcast.jl")
120
using .Broadcast
121
using .Broadcast: broadcasted, broadcasted_kwsyntax, materialize, materialize!,
122
                  broadcast_preserving_zero_d, andand, oror
123

124
# missing values
125
include("missing.jl")
126

127
# version
128
include("version.jl")
129

130
# system & environment
131
include("sysinfo.jl")
132
include("libc.jl")
133
using .Libc: getpid, gethostname, time, memcpy, memset, memmove, memcmp
134

135
const USING_STOCK_GC = occursin("stock", GC.gc_active_impl())
136

137
# These used to be in build_h.jl and are retained for backwards compatibility.
138
# NOTE: keep in sync with `libblastrampoline_jll.libblastrampoline`.
139
const libblas_name = "libblastrampoline" * (Sys.iswindows() ? "-5" : "")
140
const liblapack_name = libblas_name
141

142
# Concurrency (part 2)
143
# Note that `atomics.jl` here should be deprecated
144
Core.eval(Threads, :(include("atomics.jl")))
145
include("channels.jl")
146
include("partr.jl")
147
include("task.jl")
148
include("threads_overloads.jl")
149
include("weakkeydict.jl")
150

151
# ScopedValues
152
include("scopedvalues.jl")
153

154
# metaprogramming
155
include("meta.jl")
156

157
# Logging
158
include("logging/logging.jl")
159
using .CoreLogging
160

161
include("env.jl")
162

163
# functions defined in Random
164
function rand end
165
function randn end
166

167
# I/O
168
include("libuv.jl")
169
include("asyncevent.jl")
170
include("iostream.jl")
171
include("stream.jl")
172
include("filesystem.jl")
173
using .Filesystem
174
include("cmd.jl")
175
include("process.jl")
176
include("terminfo.jl")
177
include("secretbuffer.jl")
178

179
# core math functions
180
include("floatfuncs.jl")
181
include("math.jl")
182
using .Math
183
const (√)=sqrt
184
const (∛)=cbrt
185
const (∜)=fourthroot
186

187
# now switch to a simple, race-y TLS, relative include for the rest of Base
188
delete_method(which(include, (Module, String)))
189
let SOURCE_PATH = ""
190
    global function include(mod::Module, path::String)
×
191
        prev = SOURCE_PATH::String
×
192
        path = normpath(joinpath(dirname(prev), path))
×
193
        Core.println(path)
×
194
        ccall(:jl_uv_flush, Nothing, (Ptr{Nothing},), Core.io_pointer(Core.stdout))
×
195
        push!(_included_files, (mod, abspath(path)))
×
196
        SOURCE_PATH = path
×
197
        result = Core.include(mod, path)
×
198
        SOURCE_PATH = prev
×
199
        return result
×
200
    end
201
end
202

203
# reduction along dims
204
include("reducedim.jl")  # macros in this file rely on string.jl
205
include("accumulate.jl")
206

207
include("permuteddimsarray.jl")
208
using .PermutedDimsArrays
209

210
# Combinatorics
211
include("sort.jl")
212
using .Sort
213

214
# BinaryPlatforms, used by Artifacts.  Needs `Sort`.
215
include("binaryplatforms.jl")
216

217
# Fast math
218
include("fastmath.jl")
219
using .FastMath
220

221
function deepcopy_internal end
222

223
# enums
224
include("Enums.jl")
225
using .Enums
226

227
# BigInts
228
include("gmp.jl")
229
using .GMP
230

231
# float printing: requires BigInt
232
include("ryu/Ryu.jl")
233
using .Ryu
234

235
# BigFloats
236
include("mpfr.jl")
237
using .MPFR
238

239
include("combinatorics.jl")
240

241
# irrational mathematical constants
242
include("irrationals.jl")
243
include("mathconstants.jl")
244
using .MathConstants: ℯ, π, pi
245

246
# Stack frames and traces
247
include("stacktraces.jl")
248
using .StackTraces
249

250
# experimental API's
251
include("experimental.jl")
252

253
# utilities
254
include("deepcopy.jl")
255
include("download.jl")
256
include("summarysize.jl")
257
include("errorshow.jl")
258
include("util.jl")
259

260
include("initdefs.jl")
261
Filesystem.__postinit__()
262

263
# worker threads
264
include("threadcall.jl")
265

266
# code loading
267
include("uuid.jl")
268
include("pkgid.jl")
269
include("toml_parser.jl")
270
include("linking.jl")
271
include("staticdata.jl")
272
include("loading.jl")
273

274
# misc useful functions & macros
275
include("timing.jl")
276
include("client.jl")
277
include("asyncmap.jl")
278

279
# deprecated functions
280
include("deprecated.jl")
281
#
282
# Some additional basic documentation
283
include("docs/basedocs.jl")
284

285
# Documentation -- should always be included last in sysimg.
286
include("docs/Docs.jl")
287
using .Docs
288
Docs.loaddocs(CoreDocs.DOCS)
289
@eval CoreDocs DOCS = DocLinkedList()
290

291
include("precompilation.jl")
292

293
# finally, now make `include` point to the full version
294
for m in methods(include)
295
    delete_method(m)
296
end
297
for m in methods(IncludeInto(Base))
298
    delete_method(m)
299
end
300

301
# This method is here only to be overwritten during the test suite to test
302
# various sysimg related invalidation scenarios.
303
a_method_to_overwrite_in_test() = inferencebarrier(1)
×
304

305
# These functions are duplicated in client.jl/include(::String) for
306
# nicer stacktraces. Modifications here have to be backported there
UNCOV
307
@noinline include(mod::Module, _path::AbstractString) = _include(identity, mod, _path)
×
308
@noinline include(mapexpr::Function, mod::Module, _path::AbstractString) = _include(mapexpr, mod, _path)
×
309
(this::IncludeInto)(fname::AbstractString) = include(identity, this.m, fname)
×
310
(this::IncludeInto)(mapexpr::Function, fname::AbstractString) = include(mapexpr, this.m, fname)
×
311

312
# Compatibility with when Compiler was in Core
313
@eval Core const Compiler = Main.Base.Compiler
314
@eval Compiler const fl_parse = Core.Main.Base.fl_parse
315

316
# External libraries vendored into Base
317
Core.println("JuliaSyntax/src/JuliaSyntax.jl")
318
include(@__MODULE__, string(BUILDROOT, "JuliaSyntax/src/JuliaSyntax.jl")) # include($BUILDROOT/base/JuliaSyntax/JuliaSyntax.jl)
319

320
end_base_include = time_ns()
321

322
const _sysimage_modules = PkgId[]
323
in_sysimage(pkgid::PkgId) = pkgid in _sysimage_modules
22,827✔
324

325
if is_primary_base_module
326

327
# Profiling helper
328
# triggers printing the report and (optionally) saving a heap snapshot after a SIGINFO/SIGUSR1 profile request
329
# Needs to be in Base because Profile is no longer loaded on boot
330
function profile_printing_listener(cond::Base.AsyncCondition)
1✔
331
    profile = nothing
1✔
332
    try
1✔
333
        while _trywait(cond)
1✔
334
            profile = @something(profile, require_stdlib(PkgId(UUID("9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"), "Profile")))::Module
×
335
            invokelatest(profile.peek_report[])
×
336
            if Base.get_bool_env("JULIA_PROFILE_PEEK_HEAP_SNAPSHOT", false) === true
×
337
                println(stderr, "Saving heap snapshot...")
×
338
                fname = invokelatest(profile.take_heap_snapshot)
×
339
                println(stderr, "Heap snapshot saved to `$(fname)`")
×
340
            end
341
        end
1✔
342
    catch ex
343
        if !isa(ex, InterruptException)
×
344
            @error "Profile printing listener crashed" exception=ex,catch_backtrace()
×
345
        end
346
    end
347
    nothing
1✔
348
end
349

350
function start_profile_listener()
1✔
351
    cond = Base.AsyncCondition()
1✔
352
    Base.uv_unref(cond.handle)
1✔
353
    t = errormonitor(Threads.@spawn(profile_printing_listener(cond)))
2✔
354
    atexit() do
1✔
355
        # destroy this callback when exiting
356
        ccall(:jl_set_peek_cond, Cvoid, (Ptr{Cvoid},), C_NULL)
1✔
357
        # this will prompt any ongoing or pending event to flush also
358
        close(cond)
1✔
359
        # error-propagation is not needed, since the errormonitor will handle printing that better
360
        t === current_task() || _wait(t)
1✔
361
    end
362
    finalizer(cond) do c
1✔
363
        # if something goes south, still make sure we aren't keeping a reference in C to this
364
        ccall(:jl_set_peek_cond, Cvoid, (Ptr{Cvoid},), C_NULL)
365
    end
366
    ccall(:jl_set_peek_cond, Cvoid, (Ptr{Cvoid},), cond.handle)
1✔
367
end
368

369
function __init__()
1✔
370
    # Base library init
371
    global _atexit_hooks_finished = false
1✔
372
    Filesystem.__postinit__()
1✔
373
    reinit_stdio()
1✔
374
    Multimedia.reinit_displays() # since Multimedia.displays uses stdout as fallback
1✔
375
    # initialize loading
376
    init_depot_path()
1✔
377
    init_load_path()
1✔
378
    init_active_project()
1✔
379
    append!(empty!(_sysimage_modules), keys(loaded_modules))
1✔
380
    empty!(loaded_precompiles) # If we load a packageimage when building the image this might not be empty
1✔
381
    for mod in loaded_modules_order
1✔
382
        push!(get!(Vector{Module}, loaded_precompiles, PkgId(mod)), mod)
12✔
383
    end
12✔
384
    if haskey(ENV, "JULIA_MAX_NUM_PRECOMPILE_FILES")
1✔
385
        MAX_NUM_PRECOMPILE_FILES[] = parse(Int, ENV["JULIA_MAX_NUM_PRECOMPILE_FILES"])
×
386
    end
387
    # Profiling helper
388
    @static if !Sys.iswindows()
389
        # triggering a profile via signals is not implemented on windows
390
        start_profile_listener()
1✔
391
    end
392
    _require_world_age[] = get_world_counter()
1✔
393
    # Prevent spawned Julia process from getting stuck waiting on Tracy to connect.
394
    delete!(ENV, "JULIA_WAIT_FOR_TRACY")
1✔
395
    if get_bool_env("JULIA_USE_FLISP_PARSER", false) === false
1✔
396
        JuliaSyntax.enable_in_core!()
1✔
397
    end
398

399
    CoreLogging.global_logger(CoreLogging.ConsoleLogger())
1✔
400
    nothing
1✔
401
end
402

403
# enable threads support
404
@eval PCRE PCRE_COMPILE_LOCK = Threads.SpinLock()
405

406
# Record dependency information for files belonging to the Compiler, so that
407
# we know whether the .ji can just give the Base copy or not.
408
# TODO: We may want to do this earlier to avoid TOCTOU issues.
409
const _compiler_require_dependencies = Any[]
410
@Core.latestworld
411
for i = 1:length(_included_files)
412
    isassigned(_included_files, i) || continue
413
    (mod, file) = _included_files[i]
414
    if mod === Compiler || parentmodule(mod) === Compiler || endswith(file, "/Compiler.jl")
415
        _include_dependency!(_compiler_require_dependencies, true, mod, file, true, false)
416
    end
417
end
418
# Make relative to DATAROOTDIR to allow relocation
419
let basedir = joinpath(Sys.BINDIR, DATAROOTDIR)
420
for i = 1:length(_compiler_require_dependencies)
421
    tup = _compiler_require_dependencies[i]
422
    _compiler_require_dependencies[i] = (tup[1], relpath(tup[2], basedir), tup[3:end]...)
423
end
424
end
425
@assert length(_compiler_require_dependencies) >= 15
426

427
end
428

429
# Ensure this file is also tracked
430
@assert !isassigned(_included_files, 1)
431
_included_files[1] = (parentmodule(Base), abspath(@__FILE__))
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc