Skip to content
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
4 changes: 2 additions & 2 deletions src/construct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -479,8 +479,8 @@ function queuenext!(iter::ExprSplitter)
if head === :module
# Find or create the module
newname = ex.args[2]::Symbol
if isdefined(mod, newname)
newmod = getfield(mod, newname)
if invokelatest(isdefined, mod, newname)
newmod = invokelatest(getfield, mod, newname)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between invokelatest vs. @invokelatest here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invokelatest will be marginally faster since it doesn't need to re-lookup the getfield binding.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although we're still missing the optimization to make invokelatest on intrinsics fast, so it doesn't really make a difference right now.

newmod isa Module || throw(ErrorException("invalid redefinition of constant $(newname)"))
mod = newmod
else
Expand Down
24 changes: 15 additions & 9 deletions src/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ isassign(frame::Frame) = isassign(frame, frame.pc)
isassign(frame::Frame, pc::Int) = (pc in frame.framecode.used)

lookup_var(frame::Frame, val::SSAValue) = frame.framedata.ssavalues[val.id]
lookup_var(frame::Frame, ref::GlobalRef) = @invokelatest getfield(ref.mod, ref.name)
lookup_var(frame::Frame, ref::GlobalRef) = invokelatest(getfield, ref.mod, ref.name)
function lookup_var(frame::Frame, slot::SlotNumber)
val = frame.framedata.locals[slot.id]
val !== nothing && return val.value
Expand Down Expand Up @@ -31,7 +31,7 @@ macro lookup(args...)
nodetmp = gensym(:node) # used to hoist, e.g., args[4]
if havemod
fallback = quote
isa($nodetmp, Symbol) ? getfield($(esc(mod)), $nodetmp) :
isa($nodetmp, Symbol) ? invokelatest(getfield, $(esc(mod)), $nodetmp) :
$nodetmp
end
else
Expand All @@ -45,7 +45,7 @@ macro lookup(args...)
isa($nodetmp, GlobalRef) ? lookup_var($(esc(frame)), $nodetmp) :
isa($nodetmp, SlotNumber) ? lookup_var($(esc(frame)), $nodetmp) :
isa($nodetmp, QuoteNode) ? $nodetmp.value :
isa($nodetmp, Symbol) ? getfield(moduleof($(esc(frame))), $nodetmp) :
isa($nodetmp, Symbol) ? invokelatest(getfield, moduleof($(esc(frame))), $nodetmp) :
isa($nodetmp, Expr) ? lookup_expr($(esc(frame)), $nodetmp) :
$fallback
end
Expand Down Expand Up @@ -90,7 +90,7 @@ function lookup_or_eval(@nospecialize(recurse), frame::Frame, @nospecialize(node
elseif isa(node, GlobalRef)
return lookup_var(frame, node)
elseif isa(node, Symbol)
return getfield(moduleof(frame), node)
return invokelatest(getfield, moduleof(frame), node)
elseif isa(node, QuoteNode)
return node.value
elseif isa(node, Expr)
Expand All @@ -111,7 +111,7 @@ function lookup_or_eval(@nospecialize(recurse), frame::Frame, @nospecialize(node
elseif f === typeassert && length(ex.args) == 3
return typeassert(ex.args[2], ex.args[3])
elseif f === Base.getproperty && length(ex.args) == 3
return Base.getproperty(ex.args[2], ex.args[3])
return invokelatest(Base.getproperty, ex.args[2], ex.args[3])
elseif f === Core.Compiler.Val && length(ex.args) == 2
return Core.Compiler.Val(ex.args[2])
elseif f === Val && length(ex.args) == 2
Expand Down Expand Up @@ -311,10 +311,16 @@ function evaluate_methoddef(frame::Frame, node::Expr)
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) && @invokelatest isdefined(mod, name) # `isdefined` accesses the binding, making it impossible to create a new one
f = @invokelatest getfield(mod, name)
if isbindingresolved_deprecated
f = Core.eval(mod, Expr(:function, name))
else
f = Core.eval(mod, Expr(:function, name)) # create a new function
# TODO: This logic isn't fully correct, but it's been used for a long
# time, so let's leave it for now.
if Base.isbindingresolved(mod, name) && @invokelatest isdefined(mod, name) # `isdefined` accesses the binding, making it impossible to create a new one
f = @invokelatest getfield(mod, name)
else
f = Core.eval(mod, Expr(:function, name)) # create a new function
end
end
end
length(node.args) == 1 && return f
Expand Down Expand Up @@ -563,7 +569,7 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
# FIXME: undefine the slot?
elseif istoplevel && isa(node, LineNumberNode)
elseif istoplevel && isa(node, Symbol)
rhs = getfield(moduleof(frame), node)
rhs = invokelatest(getfield, moduleof(frame), node)
elseif @static (isdefined(Core.IR, :EnterNode) && true) && isa(node, Core.IR.EnterNode)
rhs = node.catch_dest
push!(data.exception_frames, rhs)
Expand Down
2 changes: 1 addition & 1 deletion src/localmethtable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function get_call_framecode(fargs::Vector{Any}, parentframe::FrameCode, idx::Int
# We haven't yet encountered this argtype combination and need to look it up by dispatch
fargs[1] = f = to_function(fargs[1])
ret = prepare_call(f, fargs; enter_generated=enter_generated)
ret === nothing && return f(fargs[2:end]...), nothing
ret === nothing && return invokelatest(f, fargs[2:end]...), nothing
is_compiled = isa(ret[1], Compiled)
local framecode
if is_compiled
Expand Down
6 changes: 4 additions & 2 deletions src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ function smallest_ref(stmts, arg, idmin)
return idmin
end

const isbindingresolved_deprecated = which(Base.isbindingresolved, Tuple{Module, Symbol}).file == Symbol("deprecated.jl")
function lookup_global_ref(a::GlobalRef)
if (Base.isbindingresolved(a.mod, a.name) &&
isbindingresolved_deprecated && return a
if Base.isbindingresolved(a.mod, a.name) &&
(@invokelatest isdefined(a.mod, a.name)) &&
(@invokelatest isconst(a.mod, a.name)))
(@invokelatest isconst(a.mod, a.name))
return QuoteNode(@invokelatest getfield(a.mod, a.name))
end
return a
Expand Down
2 changes: 1 addition & 1 deletion src/packagedef.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Base.Meta
import Base: +, -, convert, isless, get_world_counter, mapany, ntupleany
import Base: +, -, convert, isless, get_world_counter, mapany, ntupleany, invokelatest
using Core: CodeInfo, SimpleVector, LineInfoNode, GotoNode, GotoIfNot, ReturnNode,
GeneratedFunctionStub, MethodInstance, NewvarNode, TypeName

Expand Down
2 changes: 1 addition & 1 deletion src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ end
_Typeof(x) = isa(x, Type) ? Type{x} : typeof(x)

function to_function(@nospecialize(x))
isa(x, GlobalRef) ? getfield(x.mod, x.name) : x
isa(x, GlobalRef) ? invokelatest(getfield, x.mod, x.name) : x
end

"""
Expand Down
Loading