From d36abf21b818d8d7e8c63e428bd96f398412656f Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Fri, 14 Jun 2024 17:37:42 +0900 Subject: [PATCH] minimum adjustments to make JuliaInterpreter work with v1.12 For now, I've made the minimal changes needed to use JuliaInterpreter (and Revise) with v1.12. CI is still broken, so additional changes are needed. Additionally, while making these changes, I found that the implementation of `JuliaInterpreter.optimize!` is quite illegal. This is an issue that should be resolved eventually, so I've left comments in optimize.jl regarding the known problems. --- src/interpret.jl | 13 ++++++------- src/optimize.jl | 24 ++++++++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/interpret.jl b/src/interpret.jl index eb413c1f..26afb80c 100644 --- a/src/interpret.jl +++ b/src/interpret.jl @@ -313,15 +313,14 @@ evaluate_call!(frame::Frame, call_expr::Expr; kwargs...) = evaluate_call!(finish # The following come up only when evaluating toplevel code function evaluate_methoddef(frame, node) f = node.args[1] - if isa(f, Symbol) - mod = moduleof(frame) - if Base.isbindingresolved(mod, f) && isdefined(mod, f) # `isdefined` accesses the binding, making it impossible to create a new one - f = getfield(mod, f) + if f isa Symbol || f isa GlobalRef + mod = f isa Symbol ? moduleof(frame) : f.mod + name = f isa Symbol ? f : f.name + if Base.isbindingresolved(mod, name) && isdefined(mod, name) # `isdefined` accesses the binding, making it impossible to create a new one + f = getfield(mod, name) else - f = Core.eval(moduleof(frame), Expr(:function, f)) # create a new function + f = Core.eval(mod, Expr(:function, name)) # create a new function end - elseif isa(f, GlobalRef) - f = getfield(f.mod, f.name) end length(node.args) == 1 && return f sig = @lookup(frame, node.args[2])::SimpleVector diff --git a/src/optimize.jl b/src/optimize.jl index 95331d2b..2ae98714 100644 --- a/src/optimize.jl +++ b/src/optimize.jl @@ -6,7 +6,7 @@ function lookup_stmt(stmts::Vector{Any}, @nospecialize arg) arg = stmts[arg.id] end if isa(arg, QuoteNode) - arg = arg.value + return arg.value end return arg end @@ -24,16 +24,16 @@ function smallest_ref(stmts, arg, idmin) end function lookup_global_ref(a::GlobalRef) - if isdefined(a.mod, a.name) && isconst(a.mod, a.name) - r = getfield(a.mod, a.name) - return QuoteNode(r) - else - return a + if Base.isbindingresolved(a.mod, a.name) && isdefined(a.mod, a.name) + return QuoteNode(getfield(a.mod, a.name)) end + return a end function lookup_global_refs!(ex::Expr) - (ex.head === :isdefined || ex.head === :thunk || ex.head === :toplevel) && return nothing + if isexpr(ex, (:isdefined, :thunk, :toplevel, :method, :global, :const)) + return nothing + end for (i, a) in enumerate(ex.args) ex.head === :(=) && i == 1 && continue # Don't look up globalrefs on the LHS of an assignment (issue #98) if isa(a, GlobalRef) @@ -57,7 +57,14 @@ function lookup_getproperties(code::Vector{Any}, @nospecialize a) return lookup_global_ref(GlobalRef(arg2, arg3)) end -# TODO This isn't optimization really, but necessary to bypass llvmcall and foreigncall +# HACK This isn't optimization really, but necessary to bypass llvmcall and foreigncall +# TODO This "optimization" should be refactored into a "minimum compilation" necessary to +# execute `llvmcall` and `foreigncall` and pure optimizations on the lowered code representation. +# In particular, the optimization that replaces `GlobalRef` with `QuoteNode` is invalid and +# should be removed: This is because it is not possible to know when and where the binding +# will be resolved without executing the code. +# Since the current `build_compiled_[llvmcall|foreigncall]!` relies on this replacement, +# they also need to be reimplemented. """ optimize!(code::CodeInfo, mod::Module) @@ -73,6 +80,7 @@ function optimize!(code::CodeInfo, scope) evalmod = mod == Core.Compiler ? Core.Compiler : CompiledCalls sparams = scope isa Method ? sparam_syms(scope) : Symbol[] replace_coretypes!(code) + # TODO: because of builtins.jl, for CodeInfos like # %1 = Core.apply_type # %2 = (%1)(args...)