Skip to content

Conversation

@adienes
Copy link
Owner

@adienes adienes commented Aug 15, 2025

No description provided.

adienes added a commit that referenced this pull request Sep 12, 2025
… of `ReshapedArray` (JuliaLang#43518)

This performance difference was found when working on JuliaLang#42736.
Currently, our `ReshapedArray` use stride based `MultiplicativeInverse`
to speed up index transformation.
For example, for `a::AbstractArray{T,3}` and `b = vec(a)`, the index
transformation is equivalent to:
```julia
offset = i - 1                        # b[i]
d1, r1 = divrem(offset, stride(a, 3)) # stride(a, 3) = size(a, 1) * size(a, 2)
d2, r2 = divrem(r1, stride(a, 2))     # stride(a, 2) = size(a, 1)
CartesianIndex(r2 + 1, d2 +1, d1 + 1) # a has one-based axes
```
(All the `stride` is replaced with a `MultiplicativeInverse` to
accelerate `divrem`)

This PR wants to replace the above machinery with:
```julia
offset = i - 1               
d1, r1 = divrem(offset, size(a, 1))
d2, r2 = divrem(d1, size(a, 2))
CartesianIndex(r1 + 1, r2 +1, d2 + 1)
```
For random access, they should have the same computational cost. But for
sequential access, like `sum(b)`, `size` based transformation seems
faster.
To avoid bottleneck from IO, use `reshape(::CartesianIndices, x...)` to
benchmark:
```julia
f(x) = let r = 0
           for i in eachindex(x)
               @inbounds r |= +(x[i].I...)
           end
           r
       end
a = CartesianIndices((99,100,101));
@Btime f(vec($a));                 #2.766 ms  -->  2.591 ms
@Btime f(reshape($a,990,1010));    #3.412 ms  -->  2.626 ms
@Btime f(reshape($a,33,300,101));  #3.422 ms  -->  2.342 ms
```
I haven't looked into the reason for this performance difference.

Beside acceleration, this also makes it possible to reuse the
`MultiplicativeInverse` in some cases (like JuliaLang#42736).
So I think it might be useful?

---------

Co-authored-by: Andy Dienes <[email protected]>
Co-authored-by: Andy Dienes <[email protected]>
adienes pushed a commit that referenced this pull request Sep 15, 2025
Fixes
https://buildkite.com/julialang/julia-master/builds/46446#0195f712-1844-4e81-8b16-27b953fedcd3/899-1778

```
  | Error in testset Profile:
  | Test Failed at /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/stdlib/v1.13/Profile/test/runtests.jl:231
  | Expression: occursin("@Compiler" * slash, str)
  | Evaluated: occursin("@Compiler/", "Overhead ╎ [+additional indent] Count File:Line  Function\n=========================================================\n   ╎9   @juliasrc/task.c:1249  start_task\n   ╎ 9   @juliasrc/julia.h:2353  jl_apply\n   ╎  9   @juliasrc/gf.c:3693  ijl_apply_generic\n   ╎   9   @juliasrc/gf.c:3493  _jl_invoke\n   ╎    9   [unknown stackframe]\n   ╎     9   @Distributed/src/process_messages.jl:287  (::Distributed.var\"#handle_msg##2#handle_msg##3\"{Distributed.CallMsg{:call_fetch}, Distributed.MsgHeader, Sockets.TCPSocket})()\n   ╎    ╎ 9   @Distributed/src/process_messages.jl:70  run_work_thunk(thunk::Distributed.var\"#handle_msg##4#handle_msg##5\"{Distributed.CallMsg{:call_fetch}}, print_error::Bool)\n   ╎    ╎  9   @Distributed/src/process_messages.jl:287  (::Distributed.var\"#handle_msg##4#handle_msg##5\"{Distributed.CallMsg{:call_fetch}})()\n   ╎    ╎   9   @juliasrc/builtins.c:841  jl_f__apply_iterate\n   ╎    ╎    9   @juliasrc/julia.h:2353  jl_apply\n   ╎    ╎     9   @juliasrc/gf.c:3693  ijl_apply_generic\n   ╎    ╎    ╎ 9   @juliasrc/gf.c:3493  _jl_invoke\n   ╎    ╎    ╎  9   @Base/Base_compiler.jl:223  kwcall(::@NamedTuple{seed::UInt128}, ::typeof(invokelatest), ::Function, ::String, ::Vararg{String})\n   ╎    ╎    ╎   9   @juliasrc/builtins.c:841  jl_f__apply_iterate\n   ╎    ╎    ╎    9   @juliasrc/julia.h:2353  jl_apply\n   ╎    ╎    ╎     9   @juliasrc/gf.c:3693  ijl_apply_generic\n   ╎    ╎    ╎    ╎ 9   @juliasrc/gf.c:3493  _jl_invoke\n   ╎    ╎    ╎    ╎  9   @juliasrc/builtins.c:853  jl_f_invokelatest\n   ╎    ╎    ╎    ╎   9   @juliasrc/julia.h:2353  jl_apply\n   ╎    ╎    ╎    ╎    9   @juliasrc/gf.c:3693  ijl_apply_generic\n   ╎    ╎    ╎    ╎     9   @juliasrc/gf.c:3493  _jl_invoke\n   ╎    ╎    ╎    ╎    ╎ 9   [unknown stackframe]\n   ╎    ╎    ╎    ╎    ╎  9   /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/test/testdefs.jl:7  kwcall(::@NamedTuple{seed::UInt128}, ::typeof(runtests), name::String, path::String)\n   ╎    ╎    ╎    ╎    ╎   9   /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/test/testdefs.jl:7  runtests\n   ╎    ╎    ╎    ╎    ╎    9   /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/test/testdefs.jl:13  runtests(name::String, path::String, isolate::Bool; seed::UInt128)\n   ╎    ╎    ╎    ╎    ╎     9   @Base/env.jl:265  withenv(f::var\"#4#5\"{UInt128, String, String, Bool, Bool}, keyvals::Pair{String, Bool})\n   ╎    ╎    ╎    ╎    ╎    ╎ 9   /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/test/testdefs.jl:27  (::var\"#4#5\"{UInt128, String, String, Bool, Bool})()\n   ╎    ╎    ╎    ╎    ╎    ╎  9   @Base/timing.jl:621  macro expansion\n   ╎    ╎    ╎    ╎    ╎    ╎   9   /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/test/testdefs.jl:29  macro expansion\n   ╎    ╎    ╎    ╎    ╎    ╎    9   @Test/src/Test.jl:1835  macro expansion\n   ╎    ╎    ╎    ╎    ╎    ╎     9   /cache/build/tester-amdci5-10/julialang/julia-master/julia-7c9af464cc/share/julia/test/testdefs.jl:37  macro expansion\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 9   @Base/Base.jl:303  include(mod::Module, _path::String)\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎  9   @Base/loading.jl:2925  _include(mapexpr::Function, mod::Module, _path::String)\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎   9   @juliasrc/gf.c:3693  ijl_apply_generic\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    9   @juliasrc/gf.c:3493  _jl_invoke\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎     9   @Base/loading.jl:2865  include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 9   @Base/boot.jl:489  eval(m::Module, e::Any)\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  9   @juliasrc/toplevel.c:1095  ijl_toplevel_eval_in\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   9   @juliasrc/toplevel.c:1050  ijl_toplevel_eval\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    9   @juliasrc/toplevel.c:978  jl_toplevel_eval_flex\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     9   @juliasrc/toplevel.c:1038  jl_toplevel_eval_flex\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 9   @juliasrc/interpreter.c:897  jl_interpret_toplevel_thunk\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  9   @juliasrc/interpreter.c:557  eval_body\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   9   @juliasrc/interpreter.c:557  eval_body\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    9   @juliasrc/interpreter.c:557  eval_body\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     9   @juliasrc/interpreter.c:692  eval_body\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 9   @juliasrc/interpreter.c:193  eval_stmt_value\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  9   @juliasrc/interpreter.c:242  eval_value\n   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   9   @juliasrc/interpreter.c:124  do_call\n   ╎    ╎    ╎    ╎
...
```
adienes pushed a commit that referenced this pull request Sep 15, 2025
Use an atomic fetch and add to fix a data race in `Module()` identified
by tsan:

```
./usr/bin/julia -t4,0 --gcthreads=1 -e 'Threads.@threads for i=1:100 Module() end'
==================
WARNING: ThreadSanitizer: data race (pid=5575)
  Write of size 4 at 0xffff9bf9bd28 by thread T9:
    #0 jl_new_module__ /home/user/c/julia/src/module.c:487:22 (libjulia-internal.so.1.13+0x897d4)
    #1 jl_new_module_ /home/user/c/julia/src/module.c:527:22 (libjulia-internal.so.1.13+0x897d4)
    #2 jl_f_new_module /home/user/c/julia/src/module.c:649:22 (libjulia-internal.so.1.13+0x8a968)
    #3 <null> <null> (0xffff76a21164)
    #4 <null> <null> (0xffff76a1f074)
    #5 <null> <null> (0xffff76a1f0c4)
    #6 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5ea04)
    #7 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5ea04)
    #8 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9e4c4)
    #9 start_task /home/user/c/julia/src/task.c:1249:19 (libjulia-internal.so.1.13+0x9e4c4)

  Previous write of size 4 at 0xffff9bf9bd28 by thread T10:
    #0 jl_new_module__ /home/user/c/julia/src/module.c:487:22 (libjulia-internal.so.1.13+0x897d4)
    #1 jl_new_module_ /home/user/c/julia/src/module.c:527:22 (libjulia-internal.so.1.13+0x897d4)
    #2 jl_f_new_module /home/user/c/julia/src/module.c:649:22 (libjulia-internal.so.1.13+0x8a968)
    #3 <null> <null> (0xffff76a21164)
    #4 <null> <null> (0xffff76a1f074)
    #5 <null> <null> (0xffff76a1f0c4)
    #6 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5ea04)
    #7 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5ea04)
    #8 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9e4c4)
    #9 start_task /home/user/c/julia/src/task.c:1249:19 (libjulia-internal.so.1.13+0x9e4c4)

  Location is global 'jl_new_module__.mcounter' of size 4 at 0xffff9bf9bd28 (libjulia-internal.so.1.13+0x3dbd28)
```
adienes pushed a commit that referenced this pull request Sep 15, 2025
…aLang#58893)

When invoking any "functor-like", such as a closure:
```julia
bar(x) = @noinline ((y)->x+y)(x)
```
our IR printing was not showing the arg0 invoked, even when it is
required to determine which MethodInstance this is invoking.

Before:
```julia
julia> @code_typed optimize=true bar(1)
CodeInfo(
1 ─ %1 = %new(var"#bar##2#bar##3"{Int64}, x)::var"#bar##2#bar##3"{Int64}
│   %2 =    invoke %1(x::Int64)::Int64
└──      return %2
) => Int64
```

After:
```julia
julia> @code_typed optimize=true bar(1)
CodeInfo(
1 ─ %1 = %new(var"#bar##2#bar##3"{Int64}, x)::var"#bar##2#bar##3"{Int64}
│   %2 =    invoke (%1::var"#bar##2#bar##3"{Int64})(x::Int64)::Int64
└──      return %2
) => Int64
```
adienes pushed a commit that referenced this pull request Sep 15, 2025
Simplify `workqueue_for`. While not strictly necessary, the acquire load
in `getindex(once::OncePerThread{T,F}, tid::Integer)` makes
ThreadSanitizer happy. With the existing implementation, we get false
positives whenever a thread other than the one that originally allocated
the array reads it:

```
==================
WARNING: ThreadSanitizer: data race (pid=6819)
  Atomic read of size 8 at 0xffff86bec058 by main thread:
    #0 getproperty Base_compiler.jl:57 (sys.so+0x113b478)
    #1 julia_pushNOT._1925 task.jl:868 (sys.so+0x113b478)
    #2 julia_enq_work_1896 task.jl:969 (sys.so+0x5cd218)
    #3 schedule task.jl:983 (sys.so+0x892294)
    #4 macro expansion threadingconstructs.jl:522 (sys.so+0x892294)
    #5 julia_start_profile_listener_60681 Base.jl:355 (sys.so+0x892294)
    #6 julia___init___60641 Base.jl:392 (sys.so+0x1178dc)
    #7 jfptr___init___60642 <null> (sys.so+0x118134)
    #8 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5e9a4)
    #9 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5e9a4)
    JuliaLang#10 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0xbba74)
    JuliaLang#11 jl_module_run_initializer /home/user/c/julia/src/toplevel.c:68:13 (libjulia-internal.so.1.13+0xbba74)
    JuliaLang#12 _finish_jl_init_ /home/user/c/julia/src/init.c:632:13 (libjulia-internal.so.1.13+0x9c0fc)
    JuliaLang#13 ijl_init_ /home/user/c/julia/src/init.c:783:5 (libjulia-internal.so.1.13+0x9bcf4)
    JuliaLang#14 jl_repl_entrypoint /home/user/c/julia/src/jlapi.c:1125:5 (libjulia-internal.so.1.13+0xf7ec8)
    JuliaLang#15 jl_load_repl /home/user/c/julia/cli/loader_lib.c:601:12 (libjulia.so.1.13+0x11934)
    JuliaLang#16 main /home/user/c/julia/cli/loader_exe.c:58:15 (julia+0x10dc20)

  Previous write of size 8 at 0xffff86bec058 by thread T2:
    #0 IntrusiveLinkedListSynchronized task.jl:863 (sys.so+0x78d220)
    #1 macro expansion task.jl:932 (sys.so+0x78d220)
    #2 macro expansion lock.jl:376 (sys.so+0x78d220)
    #3 julia_workqueue_for_1933 task.jl:924 (sys.so+0x78d220)
    #4 julia_wait_2048 task.jl:1204 (sys.so+0x6255ac)
    #5 julia_task_done_hook_49205 task.jl:839 (sys.so+0x128fdc0)
    #6 jfptr_task_done_hook_49206 <null> (sys.so+0x902218)
    #7 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5e9a4)
    #8 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5e9a4)
    #9 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9c79c)
    JuliaLang#10 jl_finish_task /home/user/c/julia/src/task.c:345:13 (libjulia-internal.so.1.13+0x9c79c)
    JuliaLang#11 jl_threadfun /home/user/c/julia/src/scheduler.c:122:5 (libjulia-internal.so.1.13+0xe7db8)

  Thread T2 (tid=6824, running) created by main thread at:
    #0 pthread_create <null> (julia+0x85f88)
    #1 uv_thread_create_ex /workspace/srcdir/libuv/src/unix/thread.c:172 (libjulia-internal.so.1.13+0x1a8d70)
    #2 _finish_jl_init_ /home/user/c/julia/src/init.c:618:5 (libjulia-internal.so.1.13+0x9c010)
    #3 ijl_init_ /home/user/c/julia/src/init.c:783:5 (libjulia-internal.so.1.13+0x9bcf4)
    #4 jl_repl_entrypoint /home/user/c/julia/src/jlapi.c:1125:5 (libjulia-internal.so.1.13+0xf7ec8)
    #5 jl_load_repl /home/user/c/julia/cli/loader_lib.c:601:12 (libjulia.so.1.13+0x11934)
    #6 main /home/user/c/julia/cli/loader_exe.c:58:15 (julia+0x10dc20)

SUMMARY: ThreadSanitizer: data race Base_compiler.jl:57 in getproperty
==================
```
adienes pushed a commit that referenced this pull request Oct 4, 2025
…JuliaLang#58279)

# Overview
In the spirit of JuliaLang#58187 and JuliaLang#57965, this PR lowers more surface syntax
to calls,
eliminating the lowered `:global` and `:globaldecl` operations in favour
of a
single `Core.declare_global` builtin.

`Core.declare_global` has the signature:
```
declare_global(module::Module, name::Symbol, strong::Bool=false, [ty::Type])
```

- When `strong = false`, it has the effect of `global name` at the top
level
(see the description for
[`PARTITION_KIND_DECLARED`](https://github.com/JuliaLang/julia/blob/d46b665067bd9fc352c89c9d0abb591eaa4f7695/src/julia.h#L706-L710)).
- With `strong = true`:
- No `ty` provided: if no global exists, creates a strong global with
type
`Any`. Has no effect if one already exists. This form is generated by
    global assignments with no type declaration.
- `ty` provided: always creates a new global with the given type,
failing if
    one already exists with a different declared type.

## Definition effects
One of the purposes of this change is to remove the definitions effects
for
`:global` and `:globaldecl`:

https://github.com/JuliaLang/julia/blob/d46b665067bd9fc352c89c9d0abb591eaa4f7695/src/method.c#L95-L105

The eventual goal is to make all the definition effects for a method
explicit
after lowering, simplifying interpreters for lowered IR.

## Minor lowering changes
### `global` permitted in more places
Adds a new ephemeral syntax head, `unused-only`, to wrap expressions
whose
result should not be used. It generates the `misplaced "global"
declaration`
error, and is slightly more forgiving than the old restriction. This was
necessary to permit `global` to be lowered in all contexts.  Old:

```
julia> global example

julia> begin
           global example
       end
ERROR: syntax: misplaced "global" declaration
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

New:
```
julia> global example

julia> begin
           global example
       end
```

### `global` always lowered
This change maintains support for some expressions that cannot be
produced by
the parser (similar to `Expr(:const, :foo)`):

https://github.com/JuliaLang/julia/blob/d46b665067bd9fc352c89c9d0abb591eaa4f7695/test/precompile.jl#L2036

This used to work by bypassing lowering but is now lowered to the
appropriate
`declare_global` call.

## Generated functions
After lowering the body AST returned by a `@generated` function, the
definition
effects are still performed.  Instead of relying on a check in
`jl_declare_global` to fail during this process, `GeneratedFunctionStub`
now
wraps the AST in a new Expr head, `Expr(:toplevel_pure, ...)`,
indicating
lowering should not produce toplevel side effects.

Currently, this is used only to omit calls to `declare_global` for
generated
functions, but it could also be used to improve the catch-all error
message when
lowering returns a thunk (telling the user if it failed because of a
closure,
generator, etc), or even to support some closures by making them opaque.

The error message for declaring a global as a side effect of a
`@generated`
function AST has changed, because it now fails when the assignment to an
undeclared global is performed.  Old:
```
julia> @generated function foo(x)
           :(global bar = x)
       end
foo (generic function with 1 method)

julia> foo(1)
ERROR: new strong globals cannot be created in a generated function. Declare them outside using `global x::Any`.
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

New:
```
julia> @generated function foo(x)
           :(global bar = x)
       end
foo (generic function with 1 method)

julia> foo(1)
ERROR: Global Main.bar does not exist and cannot be assigned.
Note: Julia 1.9 and 1.10 inadvertently omitted this error check (JuliaLang#56933).
Hint: Declare it using `global bar` inside `Main` before attempting assignment.
Stacktrace:
 [1] macro expansion
   @ ./REPL[1]:1 [inlined]
 [2] foo(x::Int64)
   @ Main ./REPL[1]:1
 [3] top-level scope
   @ REPL[2]:1
```


## Examples of the new lowering
Toplevel weak global:
```
julia> Meta.@lower global example
:($(Expr(:thunk, CodeInfo(
1 ─       builtin Core.declare_global(Main, :example, false)
│       $(Expr(:latestworld))
└──     return nothing
))))
```

Toplevel strong global declaration with type:
```
julia> Meta.@lower example::Int
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = Main.example
│   %2 = Main.Int
│   %3 =   builtin Core.typeassert(%1, %2)
└──      return %3
))))
```

Toplevel strong global assignment:
```
julia> Meta.@lower example = 1
:($(Expr(:thunk, CodeInfo(
1 ─         builtin Core.declare_global(Main, :example, true)
│         $(Expr(:latestworld))
│   %3  =   builtin Core.get_binding_type(Main, :example)
│         #s1 = 1
│   %5  = #s1
│   %6  =   builtin %5 isa %3
└──       goto #3 if not %6
2 ─       goto #4
3 ─ %9  = #s1
└──       #s1 = Base.convert(%3, %9)
4 ┄ %11 = #s1
│           dynamic Base.setglobal!(Main, :example, %11)
└──       return 1
))))
```

Toplevel strong global assignment with type:
```
julia> Meta.@lower example::Int = 1
:($(Expr(:thunk, CodeInfo(
1 ─ %1  = Main.Int
│           builtin Core.declare_global(Main, :example, true, %1)
│         $(Expr(:latestworld))
│   %4  =   builtin Core.get_binding_type(Main, :example)
│         #s1 = 1
│   %6  = #s1
│   %7  =   builtin %6 isa %4
└──       goto #3 if not %7
2 ─       goto #4
3 ─ %10 = #s1
└──       #s1 = Base.convert(%4, %10)
4 ┄ %12 = #s1
│           dynamic Base.setglobal!(Main, :example, %12)
└──       return 1
))))
```

Global assignment inside function (call to `declare_global` hoisted to
top
level):
```
julia> Meta.@lower function f1(x)
           global example = x
       end
:($(Expr(:thunk, CodeInfo(
1 ─       $(Expr(:method, :(Main.f1)))
│         $(Expr(:latestworld))
│         $(Expr(:latestworld))
│           builtin Core.declare_global(Main, :example, false)
│         $(Expr(:latestworld))
│           builtin Core.declare_global(Main, :example, true)
│         $(Expr(:latestworld))
│   %8  = Main.f1
│   %9  =   dynamic Core.Typeof(%8)
│   %10 =   builtin Core.svec(%9, Core.Any)
│   %11 =   builtin Core.svec()
│   %12 =   builtin Core.svec(%10, %11, $(QuoteNode(:(#= REPL[7]:1 =#))))
│         $(Expr(:method, :(Main.f1), :(%12), CodeInfo(
    @ REPL[7]:2 within `unknown scope`
1 ─ %1  = x
│   %2  =   builtin Core.get_binding_type(Main, :example)
│         @_3 = %1
│   %4  = @_3
│   %5  =   builtin %4 isa %2
└──       goto #3 if not %5
2 ─       goto #4
3 ─ %8  = @_3
└──       @_3 = Base.convert(%2, %8)
4 ┄ %10 = @_3
│           dynamic Base.setglobal!(Main, :example, %10)
└──       return %1
)))
│         $(Expr(:latestworld))
│   %15 = Main.f1
└──       return %15
))))
```

---------

Co-authored-by: Jameson Nash <[email protected]>
adienes pushed a commit that referenced this pull request Oct 10, 2025
Addresses mystery #3 in JuliaLang#57381 (and extends the test from that issue).

(cherry picked from commit cff8bd6)
adienes pushed a commit that referenced this pull request Oct 10, 2025
)

Deferring this part of defining the ctor code allows it to do some
value-based optimizations, without the awkwardness previously of needing
to do conditional lowering of all of the possible versions that might be
useful just from syntax transforms. This feels very like a generated
function: how it expands just the function body, except it is flipped so
that then we wrap the result in a single Method instead of being created
from a Method!

Avoids lowering inaccuracies where a variable appears but is not used.
These warnings are now prevented:
```julia
julia> struct Foo{T}
           x::(T; Any)
       end
WARNING: method definition for Foo at REPL[1]:2 declares type variable T but does not use it.

julia> struct Foo{T}
   x::Union{Any, T}
end
WARNING: method definition for Foo at REPL[1]:2 declares type variable T but does not use it.
```

Avoids hitting JuliaLang#31542. This
lowering mistake is now avoided:
```julia
julia> struct Foo{T}
           x::(Val{T} where T)
       end
ERROR: syntax: invalid variable expression in "where" around REPL[1]:2
```

As a minor optimization, this avoids generating a `convert` call when
the user declares explicit `::Any` declarations, the same as if the user
didn't annotate the field type:
```julia
julia> struct Foo
           x::Any
           y::Int
           z
       end

julia> code_lowered(Foo)[2]
CodeInfo(
    @ REPL[1]:2 within `unknown scope`
1 ─ %1 =   builtin Core.fieldtype(#ctor-self#, 2)
│   %2 = y
│        @_4 = %2
│   %4 =   builtin @_4 isa %1
└──      goto #3 if not %4
2 ─      goto #4
3 ─      @_4 = Base.convert(%1, @_4)
4 ┄ %8 = @_4
│   %9 = %new(#ctor-self#, x, %8, z)
└──      return %9
)
```

The outer/inner names might be a bit historical at this point (predating
where clauses allowing specifying them flexibly inside or outside of the
struct def): they are really exact-type-type&convert-args-from-any /
exact-arg-types&apply-type-from-args if named for precisely what they
do.

(cherry picked from commit f4a9d25)
adienes pushed a commit that referenced this pull request Oct 10, 2025
Use an atomic fetch and add to fix a data race in `Module()` identified
by tsan:

```
./usr/bin/julia -t4,0 --gcthreads=1 -e 'Threads.@threads for i=1:100 Module() end'
==================
WARNING: ThreadSanitizer: data race (pid=5575)
  Write of size 4 at 0xffff9bf9bd28 by thread T9:
    #0 jl_new_module__ /home/user/c/julia/src/module.c:487:22 (libjulia-internal.so.1.13+0x897d4)
    #1 jl_new_module_ /home/user/c/julia/src/module.c:527:22 (libjulia-internal.so.1.13+0x897d4)
    #2 jl_f_new_module /home/user/c/julia/src/module.c:649:22 (libjulia-internal.so.1.13+0x8a968)
    #3 <null> <null> (0xffff76a21164)
    #4 <null> <null> (0xffff76a1f074)
    #5 <null> <null> (0xffff76a1f0c4)
    #6 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5ea04)
    #7 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5ea04)
    #8 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9e4c4)
    #9 start_task /home/user/c/julia/src/task.c:1249:19 (libjulia-internal.so.1.13+0x9e4c4)

  Previous write of size 4 at 0xffff9bf9bd28 by thread T10:
    #0 jl_new_module__ /home/user/c/julia/src/module.c:487:22 (libjulia-internal.so.1.13+0x897d4)
    #1 jl_new_module_ /home/user/c/julia/src/module.c:527:22 (libjulia-internal.so.1.13+0x897d4)
    #2 jl_f_new_module /home/user/c/julia/src/module.c:649:22 (libjulia-internal.so.1.13+0x8a968)
    #3 <null> <null> (0xffff76a21164)
    #4 <null> <null> (0xffff76a1f074)
    #5 <null> <null> (0xffff76a1f0c4)
    #6 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5ea04)
    #7 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5ea04)
    #8 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9e4c4)
    #9 start_task /home/user/c/julia/src/task.c:1249:19 (libjulia-internal.so.1.13+0x9e4c4)

  Location is global 'jl_new_module__.mcounter' of size 4 at 0xffff9bf9bd28 (libjulia-internal.so.1.13+0x3dbd28)
```

(cherry picked from commit 9039555)
@adienes adienes marked this pull request as ready for review October 20, 2025 19:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants