codegen: do not rely on method roots if `--strip-ir` is enabled
`aot_optimize_roots` prefers an existing method root over adding a global root,
but a method root only keeps a value alive while `m->roots` survives into the
output image, and `--trim` / `--strip-ir` clear that field during serialization.
Anything rooted that way is left referenced only by native-code gvar slots,
which are not GC roots.
A `let`-bound local captured by global methods hits this: the capture lands in
its capturing methods' `roots`, which suppresses the global root, and trimming
then strips the roots. On Julia 1.12, where image objects are still loaded
unmarked, the write barrier for such an object never arms, so an old-to-young
edge created by mutating it goes unrecorded and the young referent is swept
while still reachable from the image -- a use-after-free reproduced by
FileWatching's `let FDWatchers = Vector{Any}()` in trimmed binaries. #61474
hides the symptom on newer versions by pre-marking image objects, but the value
is still unrooted.
Take the global root whenever the roots we would otherwise rely on are about to
be stripped. This is the same fix as #60945 applied to captures rather than
`const` globals.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>