Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REPL] improve quality of precompile script #55210

Merged
merged 2 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ delete_method(which(Pair{Any,Any}, (Any, Any)))
end

# The REPL stdlib hooks into Base using this Ref
const REPL_MODULE_REF = Ref{Module}()
const REPL_MODULE_REF = Ref{Module}(Base)

include("checked.jl")
using .Checked
Expand Down
137 changes: 78 additions & 59 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -416,78 +416,97 @@ function load_REPL()
end

global active_repl
global active_repl_backend = nothing

function run_fallback_repl(interactive::Bool)
let input = stdin
if isa(input, File) || isa(input, IOStream)
# for files, we can slurp in the whole thing at once
ex = parse_input_line(read(input, String))
if Meta.isexpr(ex, :toplevel)
# if we get back a list of statements, eval them sequentially
# as if we had parsed them sequentially
for stmt in ex.args
eval_user_input(stderr, stmt, true)
end
body = ex.args
else
eval_user_input(stderr, ex, true)
end
else
while !eof(input)
if interactive
print("julia> ")
flush(stdout)
end
try
line = ""
ex = nothing
while !eof(input)
line *= readline(input, keep=true)
ex = parse_input_line(line)
if !(isa(ex, Expr) && ex.head === :incomplete)
break
end
end
eval_user_input(stderr, ex, true)
catch err
isa(err, InterruptException) ? print("\n\n") : rethrow()
end
end
end
end
nothing
end

function run_std_repl(REPL::Module, quiet::Bool, banner::Symbol, history_file::Bool)
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr)
banner == :no || REPL.banner(term, short=banner==:short)
if term.term_type == "dumb"
repl = REPL.BasicREPL(term)
quiet || @warn "Terminal not fully functional"
else
repl = REPL.LineEditREPL(term, get(stdout, :color, false), true)
repl.history_file = history_file
end
# Make sure any displays pushed in .julia/config/startup.jl ends up above the
# REPLDisplay
d = REPL.REPLDisplay(repl)
last_active_repl = @isdefined(active_repl) ? active_repl : nothing
last_active_repl_backend = active_repl_backend
global active_repl = repl
pushdisplay(d)
try
global active_repl = repl
_atreplinit(repl)
REPL.run_repl(repl, backend->(global active_repl_backend = backend))
finally
popdisplay(d)
active_repl = last_active_repl
active_repl_backend = last_active_repl_backend
end
nothing
end

# run the requested sort of evaluation loop on stdio
function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_file::Bool)
fallback_repl = parse(Bool, get(ENV, "JULIA_FALLBACK_REPL", "false"))
if !fallback_repl && interactive
load_InteractiveUtils()
if !isassigned(REPL_MODULE_REF)
REPL = REPL_MODULE_REF[]
if REPL === Base
load_REPL()
end
end
# TODO cleanup REPL_MODULE_REF
if !fallback_repl && interactive && isassigned(REPL_MODULE_REF)
invokelatest(REPL_MODULE_REF[]) do REPL
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr)
banner == :no || REPL.banner(term, short=banner==:short)
if term.term_type == "dumb"
repl = REPL.BasicREPL(term)
quiet || @warn "Terminal not fully functional"
else
repl = REPL.LineEditREPL(term, get(stdout, :color, false), true)
repl.history_file = history_file
end
global active_repl = repl
# Make sure any displays pushed in .julia/config/startup.jl ends up above the
# REPLDisplay
pushdisplay(REPL.REPLDisplay(repl))
_atreplinit(repl)
REPL.run_repl(repl, backend->(global active_repl_backend = backend))
end
REPL = REPL_MODULE_REF[]
if !fallback_repl && interactive && REPL !== Base
invokelatest(run_std_repl, REPL, quiet, banner, history_file)
else
# otherwise provide a simple fallback
if !fallback_repl && interactive && !quiet
@warn "REPL provider not available: using basic fallback" LOAD_PATH=join(Base.LOAD_PATH, Sys.iswindows() ? ';' : ':')
end
let input = stdin
if isa(input, File) || isa(input, IOStream)
# for files, we can slurp in the whole thing at once
ex = parse_input_line(read(input, String))
if Meta.isexpr(ex, :toplevel)
# if we get back a list of statements, eval them sequentially
# as if we had parsed them sequentially
for stmt in ex.args
eval_user_input(stderr, stmt, true)
end
body = ex.args
else
eval_user_input(stderr, ex, true)
end
else
while !eof(input)
if interactive
print("julia> ")
flush(stdout)
end
try
line = ""
ex = nothing
while !eof(input)
line *= readline(input, keep=true)
ex = parse_input_line(line)
if !(isa(ex, Expr) && ex.head === :incomplete)
break
end
end
eval_user_input(stderr, ex, true)
catch err
isa(err, InterruptException) ? print("\n\n") : rethrow()
end
end
end
end
run_fallback_repl(interactive)
end
nothing
end
Expand Down
3 changes: 1 addition & 2 deletions base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,8 @@ function docm(source::LineNumberNode, mod::Module, ex)
@nospecialize ex
if isexpr(ex, :->) && length(ex.args) > 1
return docm(source, mod, ex.args...)
elseif isassigned(Base.REPL_MODULE_REF)
elseif (REPL = Base.REPL_MODULE_REF[]) !== Base
# TODO: this is a shim to continue to allow `@doc` for looking up docstrings
REPL = Base.REPL_MODULE_REF[]
return invokelatest(REPL.lookup_doc, ex)
else
return simple_lookup_doc(ex)
Expand Down
5 changes: 0 additions & 5 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1121,13 +1121,8 @@ function cache_file_entry(pkg::PkgId)
uuid === nothing ? pkg.name : package_slug(uuid)
end

# for use during running the REPL precompilation subprocess script, given we don't
# want it to pick up caches that already exist for other optimization levels
const ignore_compiled_cache = PkgId[]

function find_all_in_cache_path(pkg::PkgId, DEPOT_PATH::typeof(DEPOT_PATH)=DEPOT_PATH)
paths = String[]
pkg in ignore_compiled_cache && return paths
entrypath, entryfile = cache_file_entry(pkg)
for path in DEPOT_PATH
path = joinpath(path, entrypath)
Expand Down
2 changes: 1 addition & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,8 @@ function _show_default(io::IO, @nospecialize(x))
end

function active_module()
isassigned(REPL_MODULE_REF) || return Main
REPL = REPL_MODULE_REF[]
REPL === Base && return Main
return invokelatest(REPL.active_module)::Module
end

Expand Down
4 changes: 2 additions & 2 deletions base/task.jl
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ function task_done_hook(t::Task)
end

if err && !handled && Threads.threadid() == 1
if isa(result, InterruptException) && isdefined(Base, :active_repl_backend) &&
if isa(result, InterruptException) && active_repl_backend !== nothing &&
active_repl_backend.backend_task._state === task_state_runnable && isempty(Workqueue) &&
active_repl_backend.in_eval
throwto(active_repl_backend.backend_task, result) # this terminates the task
Expand All @@ -849,7 +849,7 @@ function task_done_hook(t::Task)
# the exception to the REPL task since the current task is done.
# issue #19467
if Threads.threadid() == 1 &&
isa(e, InterruptException) && isdefined(Base, :active_repl_backend) &&
isa(e, InterruptException) && active_repl_backend !== nothing &&
active_repl_backend.backend_task._state === task_state_runnable && isempty(Workqueue) &&
active_repl_backend.in_eval
throwto(active_repl_backend.backend_task, e)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/REPL/src/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module LineEdit

import ..REPL
using REPL: AbstractREPL, Options
using ..REPL: AbstractREPL, Options

using ..Terminals
import ..Terminals: raw!, width, height, clear_line, beep
Expand Down
9 changes: 5 additions & 4 deletions stdlib/REPL/src/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ include("options.jl")

include("LineEdit.jl")
using .LineEdit
import ..LineEdit:
import .LineEdit:
CompletionProvider,
HistoryProvider,
add_history,
Expand Down Expand Up @@ -752,6 +752,7 @@ struct LatexCompletions <: CompletionProvider end

function active_module() # this method is also called from Base
isdefined(Base, :active_repl) || return Main
Base.active_repl === nothing && return Main
return active_module(Base.active_repl::AbstractREPL)
end
active_module((; mistate)::LineEditREPL) = mistate === nothing ? Main : mistate.active_module
Expand Down Expand Up @@ -1793,7 +1794,7 @@ module Numbered

using ..REPL

__current_ast_transforms() = isdefined(Base, :active_repl_backend) ? Base.active_repl_backend.ast_transforms : REPL.repl_ast_transforms
__current_ast_transforms() = Base.active_repl_backend !== nothing ? Base.active_repl_backend.ast_transforms : REPL.repl_ast_transforms

function repl_eval_counter(hp)
return length(hp.history) - hp.start_idx
Expand Down Expand Up @@ -1855,13 +1856,13 @@ end

function __current_ast_transforms(backend)
if backend === nothing
isdefined(Base, :active_repl_backend) ? Base.active_repl_backend.ast_transforms : REPL.repl_ast_transforms
Base.active_repl_backend !== nothing ? Base.active_repl_backend.ast_transforms : REPL.repl_ast_transforms
else
backend.ast_transforms
end
end

function numbered_prompt!(repl::LineEditREPL=Base.active_repl, backend=nothing)
function numbered_prompt!(repl::LineEditREPL=Base.active_repl::LineEditREPL, backend=nothing)
n = Ref{Int}(0)
set_prompt(repl, n)
set_output_prefix(repl, n)
Expand Down
5 changes: 4 additions & 1 deletion stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,10 @@ function maybe_spawn_cache_PATH()
@lock PATH_cache_lock begin
PATH_cache_task isa Task && !istaskdone(PATH_cache_task) && return
time() < next_cache_update && return
PATH_cache_task = Threads.@spawn REPLCompletions.cache_PATH()
PATH_cache_task = Threads.@spawn begin
REPLCompletions.cache_PATH()
@lock PATH_cache_lock PATH_cache_task = nothing # release memory when done
end
Base.errormonitor(PATH_cache_task)
end
end
Expand Down
2 changes: 1 addition & 1 deletion stdlib/REPL/src/TerminalMenus/TerminalMenus.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module TerminalMenus

using REPL: REPL
using ..REPL: REPL

function default_terminal(; in::IO=stdin, out::IO=stdout, err::IO=stderr)
return REPL.Terminals.TTYTerminal(
Expand Down
2 changes: 0 additions & 2 deletions stdlib/REPL/src/Terminals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,8 @@ cmove_line_up(t::UnixTerminal, n) = (cmove_up(t, n); cmove_col(t, 1))
cmove_line_down(t::UnixTerminal, n) = (cmove_down(t, n); cmove_col(t, 1))
cmove_col(t::UnixTerminal, n) = (write(t.out_stream, '\r'); n > 1 && cmove_right(t, n-1))

const is_precompiling = Ref(false)
if Sys.iswindows()
function raw!(t::TTYTerminal,raw::Bool)
is_precompiling[] && return true
check_open(t.in_stream)
if Base.ispty(t.in_stream)
run((raw ? `stty raw -echo onlcr -ocrnl opost` : `stty sane`),
Expand Down
4 changes: 1 addition & 3 deletions stdlib/REPL/src/docview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ using Base: with_output_color, mapany, isdeprecated, isexported

using Base.Filesystem: _readdirx

import REPL

using InteractiveUtils: subtypes

using Unicode: normalize
Expand Down Expand Up @@ -475,7 +473,7 @@ repl_corrections(s) = repl_corrections(stdout, s)
# inverse of latex_symbols Dict, lazily created as needed
const symbols_latex = Dict{String,String}()
function symbol_latex(s::String)
if isempty(symbols_latex) && isassigned(Base.REPL_MODULE_REF)
if isempty(symbols_latex)
for (k,v) in Iterators.flatten((REPLCompletions.latex_symbols,
REPLCompletions.emoji_symbols))
symbols_latex[v] = k
Expand Down
Loading