Skip to content

Commit e367911

Browse files
committed
update to JuliaInterpreter 0.10
This commit implements the migration to the new JuliaInterpreter interface proposed in JuliaDebug/JuliaInterpreter.jl#683. It purely performs the migration to the new interface and does not include any refactoring based on it. In practice, `methods_by_execution!` is quite complex, and using the `Interpreter` interface may not allow us to simplify its implementation. That said, this commit seems to achieve a modest latency improvement by changing the argument type declaration from `@nospecialize(recurse)` to `interp::Interpreter` (with easier code specialization).
1 parent 57c856b commit e367911

File tree

6 files changed

+64
-61
lines changed

6 files changed

+64
-61
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ DistributedExt = "Distributed"
2323
[compat]
2424
CodeTracking = "1.2"
2525
Distributed = "1"
26-
JuliaInterpreter = "0.9.46"
27-
LoweredCodeUtils = "3.2"
26+
JuliaInterpreter = "0.10"
27+
LoweredCodeUtils = "3.3"
2828
OrderedCollections = "1"
2929
# Exclude Requires-1.1.0 - see https://github.com/JuliaPackaging/Requires.jl/issues/94
3030
Requires = "~1.0, ^1.1.1"

src/Revise.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ module Revise
3636
using OrderedCollections, CodeTracking, JuliaInterpreter, LoweredCodeUtils
3737

3838
using CodeTracking: PkgFiles, basedir, srcfiles, basepath
39-
using JuliaInterpreter: codelocs, finish_and_return!, get_return, is_doc_expr,
40-
isassign, isidentical, is_quotenode_egal, linetable,
41-
LineTypes, lookup, moduleof, pc_expr, scopeof,
42-
step_expr!, whichtt
39+
using JuliaInterpreter: Compiled, Frame, Interpreter, LineTypes, RecursiveInterpreter
40+
using JuliaInterpreter: codelocs, finish_and_return!, get_return, is_doc_expr, isassign,
41+
isidentical, is_quotenode_egal, linetable, lookup, moduleof,
42+
pc_expr, scopeof, step_expr!
4343
using LoweredCodeUtils: next_or_nothing!, callee_matches
4444

4545
include("packagedef.jl")

src/lowered.jl

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ function assign_this!(frame, value)
1313
frame.framedata.ssavalues[frame.pc] = value
1414
end
1515

16+
# TODO Define abstract type MethodInfo end
17+
1618
# This defines the API needed to store signatures using methods_by_execution!
1719
# This default version is simple and only used for testing purposes.
1820
# The "real" one is CodeTrackingMethodInfo in Revise.jl.
1921
const MethodInfo = IdDict{Type,LineNumberNode}
20-
add_signature!(methodinfo::MethodInfo, @nospecialize(sig), ln) = push!(methodinfo, sig=>ln)
21-
push_expr!(methodinfo::MethodInfo, mod::Module, ex::Expr) = methodinfo
22-
pop_expr!(methodinfo::MethodInfo) = methodinfo
23-
add_dependencies!(methodinfo::MethodInfo, be::CodeEdges, src, isrequired) = methodinfo
24-
add_includes!(methodinfo::MethodInfo, mod::Module, filename) = methodinfo
22+
add_signature!(methodinfo, @nospecialize(sig), ln) = push!(methodinfo, sig=>ln)
23+
push_expr!(methodinfo, mod::Module, ex::Expr) = methodinfo
24+
pop_expr!(methodinfo) = methodinfo
25+
add_dependencies!(methodinfo, be::CodeEdges, src, isrequired) = methodinfo
26+
add_includes!(methodinfo, mod::Module, filename) = methodinfo
2527

2628
function is_some_include(@nospecialize(f))
2729
@assert !isa(f, Core.SSAValue) && !isa(f, JuliaInterpreter.SSAValue)
@@ -187,11 +189,11 @@ function minimal_evaluation!(@nospecialize(predicate), methodinfo, mod::Module,
187189
add_dependencies!(methodinfo, edges, src, isrequired)
188190
return isrequired, evalassign
189191
end
190-
@noinline minimal_evaluation!(@nospecialize(predicate), methodinfo, frame::JuliaInterpreter.Frame, mode::Symbol) =
192+
@noinline minimal_evaluation!(@nospecialize(predicate), methodinfo, frame::Frame, mode::Symbol) =
191193
minimal_evaluation!(predicate, methodinfo, moduleof(frame), frame.framecode.src, mode)
192194

193-
function minimal_evaluation!(methodinfo, frame::JuliaInterpreter.Frame, mode::Symbol)
194-
minimal_evaluation!(methodinfo, frame, mode) do @nospecialize(stmt), code
195+
function minimal_evaluation!(methodinfo, frame::Frame, mode::Symbol)
196+
minimal_evaluation!(methodinfo, frame, mode) do @nospecialize(stmt), code::Vector{Any}
195197
ismeth, haseval, isinclude, isnamespace, istoplevel = categorize_stmt(stmt, code)
196198
isreq = ismeth | isinclude | istoplevel
197199
return mode === :sigs ? (isreq, haseval) : (isreq | isnamespace, haseval)
@@ -206,14 +208,14 @@ function methods_by_execution(mod::Module, ex::Expr; kwargs...)
206208
end
207209

208210
"""
209-
methods_by_execution!(recurse=JuliaInterpreter.Compiled(), methodinfo, docexprs, mod::Module, ex::Expr;
211+
methods_by_execution!([interp::Interpreter=JuliaInterpreter.Compiled(),] methodinfo, docexprs::DocExprs, mod::Module, ex::Expr;
210212
mode=:eval, disablebp=true, skip_include=mode!==:eval, always_rethrow=false)
211213
212214
Evaluate or analyze `ex` in the context of `mod`.
213215
Depending on the setting of `mode` (see the Extended help), it supports full evaluation or just the minimal
214216
evaluation needed to extract method signatures.
215-
`recurse` controls JuliaInterpreter's evaluation of any non-intercepted statement;
216-
likely choices are `JuliaInterpreter.Compiled()` or `JuliaInterpreter.finish_and_return!`.
217+
`interp` controls JuliaInterpreter's evaluation of any non-intercepted statement;
218+
likely choices are `JuliaInterpreter.Compiled()` or `JuliaInterpreter.RecursiveInterpreter()`.
217219
`methodinfo` is a cache for storing information about any method definitions (see [`CodeTrackingMethodInfo`](@ref)).
218220
`docexprs` is a cache for storing documentation expressions; obtain an empty one with `Revise.DocExprs()`.
219221
@@ -249,7 +251,7 @@ The other keyword arguments are more straightforward:
249251
If false, the error is logged with `@error`. `InterruptException`s are always rethrown.
250252
This is primarily useful for debugging.
251253
"""
252-
function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod::Module, ex::Expr;
254+
function methods_by_execution!(interp::Interpreter, methodinfo, docexprs::DocExprs, mod::Module, ex::Expr;
253255
mode::Symbol=:eval, disablebp::Bool=true, always_rethrow::Bool=false, kwargs...)
254256
mode (:sigs, :eval, :evalmeth, :evalassign) || error("unsupported mode ", mode)
255257
lwr = Meta.lower(mod, ex)
@@ -261,8 +263,8 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod
261263
mode === :sigs && return nothing, nothing
262264
return Core.eval(mod, lwr), nothing
263265
end
264-
frame = JuliaInterpreter.Frame(mod, lwr.args[1]::CodeInfo)
265-
mode === :eval || LoweredCodeUtils.rename_framemethods!(recurse, frame)
266+
frame = Frame(mod, lwr.args[1]::CodeInfo)
267+
mode === :eval || LoweredCodeUtils.rename_framemethods!(interp, frame)
266268
# Determine whether we need interpreted mode
267269
isrequired, evalassign = minimal_evaluation!(methodinfo, frame, mode)
268270
# LoweredCodeUtils.print_with_code(stdout, frame.framecode.src, isrequired)
@@ -293,7 +295,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod
293295
foreach(disable, active_bp_refs)
294296
end
295297
ret = try
296-
methods_by_execution!(recurse, methodinfo, docexprs, frame, isrequired; mode=mode, kwargs...)
298+
methods_by_execution!(interp, methodinfo, docexprs, frame, isrequired; mode, kwargs...)
297299
catch err
298300
(always_rethrow || isa(err, InterruptException)) && (disablebp && foreach(enable, active_bp_refs); rethrow(err))
299301
loc = location_string(whereis(frame))
@@ -311,10 +313,11 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod
311313
end
312314
return ret, lwr
313315
end
314-
methods_by_execution!(methodinfo, docexprs, mod::Module, ex::Expr; kwargs...) =
315-
methods_by_execution!(JuliaInterpreter.Compiled(), methodinfo, docexprs, mod, ex; kwargs...)
316+
methods_by_execution!(methodinfo, docexprs::DocExprs, mod::Module, ex::Expr; kwargs...) =
317+
methods_by_execution!(Compiled(), methodinfo, docexprs, mod, ex; kwargs...)
316318

317-
function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, frame::Frame, isrequired::AbstractVector{Bool}; mode::Symbol=:eval, skip_include::Bool=true)
319+
function methods_by_execution!(interp::Interpreter, methodinfo, docexprs::DocExprs, frame::Frame, isrequired::AbstractVector{Bool};
320+
mode::Symbol=:eval, skip_include::Bool=true)
318321
isok(lnn::LineTypes) = !iszero(lnn.line) || lnn.file !== :none # might fail either one, but accept anything
319322

320323
mod = moduleof(frame)
@@ -336,7 +339,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
336339
local value
337340
for ex in stmt.args
338341
ex isa Expr || continue
339-
value = methods_by_execution!(recurse, methodinfo, docexprs, mod, ex; mode=mode, disablebp=false, skip_include=skip_include)
342+
value = methods_by_execution!(interp, methodinfo, docexprs, mod, ex; mode, disablebp=false, skip_include)
340343
end
341344
isassign(frame, pc) && assign_this!(frame, value)
342345
pc = next_or_nothing!(frame)
@@ -348,10 +351,10 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
348351
# # way to find them within the already-defined module.
349352
# # They may be needed to define later signatures.
350353
# # Note that named inner methods don't require special treatment.
351-
# pc = step_expr!(recurse, frame, stmt, true)
354+
# pc = step_expr!(interp, frame, stmt, true)
352355
elseif head === :method
353356
empty!(signatures)
354-
ret = methoddef!(recurse, signatures, frame, stmt, pc; define=mode!==:sigs)
357+
ret = methoddef!(interp, signatures, frame, stmt, pc; define=mode!==:sigs)
355358
if ret === nothing
356359
# This was just `function foo end` or similar.
357360
# However, it might have been followed by a thunk that defined a
@@ -367,22 +370,22 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
367370
end
368371
end
369372
@assert length(stmt.args) == 1
370-
pc = mode !== :sigs ? step_expr!(recurse, frame, stmt, true) :
373+
pc = mode !== :sigs ? step_expr!(interp, frame, stmt, true) :
371374
next_or_nothing!(frame)
372375
else
373376
pc, pc3 = ret
374377
# Get the line number from the body
375378
stmt3 = pc_expr(frame, pc3)::Expr
376379
lnn = nothing
377-
sigcode = lookup(frame, stmt3.args[2])::Core.SimpleVector
380+
sigcode = lookup(interp, frame, stmt3.args[2])::Core.SimpleVector
378381
lnn = sigcode[end]
379382
if !isa(lnn, LineNumberNode)
380383
lnn = nothing
381384
end
382385
if lnn === nothing
383386
bodycode = stmt3.args[end]
384387
if !isa(bodycode, CodeInfo)
385-
bodycode = lookup(frame, bodycode)
388+
bodycode = lookup(interp, frame, bodycode)
386389
end
387390
if isa(bodycode, CodeInfo)
388391
lnn = linetable(bodycode, 1)
@@ -456,13 +459,13 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
456459
# avoid redefining types unless we have to
457460
pc = next_or_nothing!(frame)
458461
else
459-
pc = step_expr!(recurse, frame, stmt, true)
462+
pc = step_expr!(interp, frame, stmt, true)
460463
end
461464
elseif head === :call
462-
f = lookup(frame, stmt.args[1])
465+
f = lookup(interp, frame, stmt.args[1])
463466
if isdefined(Core, :_defaultctors) && f === Core._defaultctors && length(stmt.args) == 3
464-
T = lookup(frame, stmt.args[2])
465-
lnn = lookup(frame, stmt.args[3])
467+
T = lookup(interp, frame, stmt.args[2])
468+
lnn = lookup(interp, frame, stmt.args[3])
466469
if T isa Type && lnn isa LineNumberNode
467470
empty!(signatures)
468471
uT = Base.unwrap_unionall(T)::DataType
@@ -482,12 +485,12 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
482485
if mode===:sigs
483486
pc = next_or_nothing!(frame)
484487
else # also execute this call
485-
pc = step_expr!(recurse, frame, stmt, true)
488+
pc = step_expr!(interp, frame, stmt, true)
486489
end
487490
elseif f === Core.eval
488491
# an @eval or eval block: this may contain method definitions, so intercept it.
489-
evalmod = lookup(frame, stmt.args[2])::Module
490-
evalex = lookup(frame, stmt.args[3])
492+
evalmod = lookup(interp, frame, stmt.args[2])::Module
493+
evalex = lookup(interp, frame, stmt.args[3])
491494
value = nothing
492495
for (newmod, newex) in ExprSplitter(evalmod, evalex)
493496
if is_doc_expr(newex)
@@ -496,7 +499,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
496499
end
497500
newex = unwrap(newex)
498501
push_expr!(methodinfo, newmod, newex)
499-
value = methods_by_execution!(recurse, methodinfo, docexprs, newmod, newex; mode=mode, skip_include=skip_include, disablebp=false)
502+
value = methods_by_execution!(interp, methodinfo, docexprs, newmod, newex; mode, skip_include, disablebp=false)
500503
pop_expr!(methodinfo)
501504
end
502505
assign_this!(frame, value)
@@ -505,29 +508,29 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
505508
# include calls need to be managed carefully from several standpoints, including
506509
# path management and parsing new expressions
507510
if length(stmt.args) == 2
508-
add_includes!(methodinfo, mod, lookup(frame, stmt.args[2]))
511+
add_includes!(methodinfo, mod, lookup(interp, frame, stmt.args[2]))
509512
elseif length(stmt.args) == 3
510-
add_includes!(methodinfo, lookup(frame, stmt.args[2]), lookup(frame, stmt.args[3]))
513+
add_includes!(methodinfo, lookup(interp, frame, stmt.args[2]), lookup(interp, frame, stmt.args[3]))
511514
else
512515
error("Bad call to Core.include")
513516
end
514517
assign_this!(frame, nothing) # FIXME: the file might return something different from `nothing`
515518
pc = next_or_nothing!(frame)
516519
elseif skip_include && f === Base.include
517520
if length(stmt.args) == 2
518-
add_includes!(methodinfo, mod, lookup(frame, stmt.args[2]))
521+
add_includes!(methodinfo, mod, lookup(interp, frame, stmt.args[2]))
519522
else # either include(module, path) or include(mapexpr, path)
520-
mod_or_mapexpr = lookup(frame, stmt.args[2])
523+
mod_or_mapexpr = lookup(interp, frame, stmt.args[2])
521524
if isa(mod_or_mapexpr, Module)
522-
add_includes!(methodinfo, mod_or_mapexpr, lookup(frame, stmt.args[3]))
525+
add_includes!(methodinfo, mod_or_mapexpr, lookup(interp, frame, stmt.args[3]))
523526
else
524527
error("include(mapexpr, path) is not supported") # TODO (issue #634)
525528
end
526529
end
527530
assign_this!(frame, nothing) # FIXME: the file might return something different from `nothing`
528531
pc = next_or_nothing!(frame)
529532
elseif f === Base.Docs.doc! # && mode !== :eval
530-
fargs = JuliaInterpreter.collect_args(recurse, frame, stmt)
533+
fargs = JuliaInterpreter.collect_args(interp, frame, stmt)
531534
popfirst!(fargs)
532535
length(fargs) == 3 && push!(fargs, Union{}) # add the default sig
533536
dmod::Module, b::Base.Docs.Binding, str::Base.Docs.DocStr, sig = fargs
@@ -559,16 +562,16 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
559562
pc = next_or_nothing!(frame)
560563
else
561564
# A :call Expr we don't want to intercept
562-
pc = step_expr!(recurse, frame, stmt, true)
565+
pc = step_expr!(interp, frame, stmt, true)
563566
end
564567
else
565568
# An Expr we don't want to intercept
566569
frame.pc = pc
567-
pc = step_expr!(recurse, frame, stmt, true)
570+
pc = step_expr!(interp, frame, stmt, true)
568571
end
569572
else
570573
# A statement we don't want to intercept
571-
pc = step_expr!(recurse, frame, stmt, true)
574+
pc = step_expr!(interp, frame, stmt, true)
572575
end
573576
pc === nothing && break
574577
end

src/packagedef.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ end
515515
function eval_with_signatures(mod, ex::Expr; mode=:eval, kwargs...)
516516
methodinfo = CodeTrackingMethodInfo(ex)
517517
docexprs = DocExprs()
518-
frame = methods_by_execution!(finish_and_return!, methodinfo, docexprs, mod, ex; mode=mode, kwargs...)[2]
518+
frame = methods_by_execution!(methodinfo, docexprs, mod, ex; mode=mode, kwargs...)[2]
519519
return methodinfo.allsigs, methodinfo.deps, methodinfo.includes, frame
520520
end
521521

0 commit comments

Comments
 (0)