8282# and hence our re-use of the `callargs` field of Frame would introduce
8383# bugs. Since these nodes use a very limited repertoire of calls, we can special-case
8484# this quite easily.
85- function lookup_or_eval(@nospecialize(recurse) , frame:: Frame , @nospecialize(node))
85+ function lookup_or_eval(interp :: Interpreter , frame:: Frame , @nospecialize(node))
8686 if isa(node, SSAValue)
8787 return lookup_var(frame, node)
8888 elseif isa(node, SlotNumber)
@@ -96,7 +96,7 @@ function lookup_or_eval(@nospecialize(recurse), frame::Frame, @nospecialize(node
9696 elseif isa(node, Expr)
9797 ex = Expr(node. head)
9898 for arg in node. args
99- push!(ex. args, lookup_or_eval(recurse , frame, arg))
99+ push!(ex. args, lookup_or_eval(interp , frame, arg))
100100 end
101101 if ex. head === :call
102102 f = ex. args[1 ]
@@ -130,7 +130,7 @@ function lookup_or_eval(@nospecialize(recurse), frame::Frame, @nospecialize(node
130130 elseif isa(node, Type)
131131 return node
132132 end
133- return eval_rhs(recurse , frame, node)
133+ return eval_rhs(interp , frame, node)
134134end
135135
136136function resolvefc(frame:: Frame , @nospecialize(expr))
@@ -153,14 +153,14 @@ function resolvefc(frame::Frame, @nospecialize(expr))
153153 @invokelatest error(" unexpected ccall to " , expr)
154154end
155155
156- function collect_args(@nospecialize(recurse) , frame:: Frame , call_expr:: Expr ; isfc:: Bool = false )
156+ function collect_args(interp :: Interpreter , frame:: Frame , call_expr:: Expr ; isfc:: Bool = false )
157157 args = frame. framedata. callargs
158158 resize!(args, length(call_expr. args))
159159 mod = moduleof(frame)
160160 args[1 ] = isfc ? resolvefc(frame, call_expr. args[1 ]) : @lookup(mod, frame, call_expr. args[1 ])
161161 for i = 2 : length(args)
162162 if isexpr(call_expr. args[i], :call)
163- args[i] = lookup_or_eval(recurse , frame, call_expr. args[i])
163+ args[i] = lookup_or_eval(interp , frame, call_expr. args[i])
164164 else
165165 args[i] = @lookup(mod, frame, call_expr. args[i])
166166 end
@@ -169,13 +169,13 @@ function collect_args(@nospecialize(recurse), frame::Frame, call_expr::Expr; isf
169169end
170170
171171"""
172- ret = evaluate_foreigncall(recurse , frame::Frame, call_expr)
172+ ret = evaluate_foreigncall(interp , frame::Frame, call_expr)
173173
174174Evaluate a `:foreigncall` (from a `ccall`) statement `callexpr` in the context of `frame`.
175175"""
176- function evaluate_foreigncall(@nospecialize(recurse) , frame:: Frame , call_expr:: Expr )
176+ function evaluate_foreigncall(interp :: Interpreter , frame:: Frame , call_expr:: Expr )
177177 head = call_expr. head
178- args = collect_args(recurse , frame, call_expr; isfc = head === :foreigncall)
178+ args = collect_args(interp , frame, call_expr; isfc = head === :foreigncall)
179179 for i = 2 : length(args)
180180 arg = args[i]
181181 args[i] = isa(arg, Symbol) ? QuoteNode(arg) : arg
@@ -205,11 +205,11 @@ function evaluate_foreigncall(@nospecialize(recurse), frame::Frame, call_expr::E
205205end
206206
207207# We have to intercept ccalls / llvmcalls before we try it as a builtin
208- function bypass_builtins(@nospecialize(recurse) , frame:: Frame , call_expr:: Expr , pc:: Int )
208+ function bypass_builtins(interp :: Interpreter , frame:: Frame , call_expr:: Expr , pc:: Int )
209209 if isassigned(frame. framecode. methodtables, pc)
210210 tme = frame. framecode. methodtables[pc]
211211 if isa(tme, Compiled)
212- fargs = collect_args(recurse , frame, call_expr)
212+ fargs = collect_args(interp , frame, call_expr)
213213 f = to_function(fargs[1 ])
214214 fmod = parentmodule(f):: Module
215215 if fmod === JuliaInterpreter. CompiledCalls || fmod === Core. Compiler
@@ -238,25 +238,25 @@ function native_call(fargs::Vector{Any}, frame::Frame)
238238 return @invokelatest f(fargs... )
239239end
240240
241- function evaluate_call_compiled!( :: Compiled , frame:: Frame , call_expr:: Expr ; enter_generated:: Bool = false )
241+ function evaluate_call!(interp :: Compiled , frame:: Frame , call_expr:: Expr , enter_generated:: Bool = false )
242242 # @assert !enter_generated
243243 pc = frame. pc
244- ret = bypass_builtins(Compiled() , frame, call_expr, pc)
244+ ret = bypass_builtins(interp , frame, call_expr, pc)
245245 isa(ret, Some{Any}) && return ret. value
246246 ret = maybe_evaluate_builtin(frame, call_expr, false )
247247 isa(ret, Some{Any}) && return ret. value
248- fargs = collect_args(Compiled() , frame, call_expr)
248+ fargs = collect_args(interp , frame, call_expr)
249249 return native_call(fargs, frame)
250250end
251251
252- function evaluate_call_recurse!(@nospecialize(recurse) , frame:: Frame , call_expr:: Expr ; enter_generated:: Bool = false )
252+ function evaluate_call!(interp :: Interpreter , frame:: Frame , call_expr:: Expr , enter_generated:: Bool = false )
253253 pc = frame. pc
254- ret = bypass_builtins(recurse , frame, call_expr, pc)
254+ ret = bypass_builtins(interp , frame, call_expr, pc)
255255 isa(ret, Some{Any}) && return ret. value
256256 ret = maybe_evaluate_builtin(frame, call_expr, true )
257257 isa(ret, Some{Any}) && return ret. value
258258 call_expr = ret
259- fargs = collect_args(recurse , frame, call_expr)
259+ fargs = collect_args(interp , frame, call_expr)
260260 if fargs[1 ] === Core. eval
261261 return Core. eval(fargs[2 ], fargs[3 ]) # not a builtin, but worth treating specially
262262 elseif fargs[1 ] === Base. rethrow
@@ -286,30 +286,24 @@ function evaluate_call_recurse!(@nospecialize(recurse), frame::Frame, call_expr:
286286 npc = newframe. pc
287287 shouldbreak(newframe, npc) && return BreakpointRef(newframe. framecode, npc)
288288 # if the following errors, handle_err will pop the stack and recycle newframe
289- if recurse === finish_and_return!
290- # Optimize this case to avoid dynamic dispatch
291- ret = finish_and_return!(finish_and_return!, newframe, false )
292- else
293- ret = recurse(recurse, newframe, false )
294- end
289+ ret = finish_and_return!(interp, newframe, false )
295290 isa(ret, BreakpointRef) && return ret
296291 frame. callee = nothing
297292 return_from(newframe)
298293 return ret
299294end
300295
301296"""
302- ret = evaluate_call!(Compiled() , frame::Frame, call_expr)
303- ret = evaluate_call!(recurse, frame::Frame, call_expr)
297+ ret = evaluate_call!(interp::Interpreter , frame::Frame, call_expr::Expr, enter_generated::Bool=false )
298+ ret = evaluate_call!(frame::Frame, call_expr::Expr, enter_generated::Bool=false )
304299
305300Evaluate a `:call` expression `call_expr` in the context of `frame`.
306301The first causes it to be executed using Julia's normal dispatch (compiled code),
307302whereas the second recurses in via the interpreter.
308- `recurse ` has a default value of [`JuliaInterpreter.finish_and_return! `](@ref).
303+ `interp ` has a default value of [`RecursiveInterpreter `](@ref).
309304"""
310- evaluate_call!(:: Compiled , frame:: Frame , call_expr:: Expr ; kwargs... ) = evaluate_call_compiled!(Compiled(), frame, call_expr; kwargs... )
311- evaluate_call!(@nospecialize(recurse), frame:: Frame , call_expr:: Expr ; kwargs... ) = evaluate_call_recurse!(recurse, frame, call_expr; kwargs... )
312- evaluate_call!(frame:: Frame , call_expr:: Expr ; kwargs... ) = evaluate_call!(finish_and_return!, frame, call_expr; kwargs... )
305+ evaluate_call!(frame:: Frame , call_expr:: Expr , enter_generated:: Bool = false ) =
306+ evaluate_call!(RecursiveInterpreter(), frame, call_expr, enter_generated)
313307
314308# The following come up only when evaluating toplevel code
315309function evaluate_methoddef(frame:: Frame , node:: Expr )
@@ -366,7 +360,7 @@ function maybe_assign!(frame::Frame, @nospecialize(stmt), @nospecialize(val))
366360end
367361maybe_assign!(frame:: Frame , @nospecialize(val)) = maybe_assign!(frame, pc_expr(frame), val)
368362
369- function eval_rhs(@nospecialize(recurse) , frame:: Frame , node:: Expr )
363+ function eval_rhs(interp :: Interpreter , frame:: Frame , node:: Expr )
370364 head = node. head
371365 if head === :new
372366 mod = moduleof(frame)
@@ -385,11 +379,9 @@ function eval_rhs(@nospecialize(recurse), frame::Frame, node::Expr)
385379 elseif head === :isdefined
386380 return check_isdefined(frame, node. args[1 ])
387381 elseif head === :call
388- # here it's crucial to avoid dynamic dispatch
389- isa(recurse, Compiled) && return evaluate_call_compiled!(recurse, frame, node)
390- return evaluate_call_recurse!(recurse, frame, node)
382+ return evaluate_call!(interp, frame, node)
391383 elseif head === :foreigncall || head === :cfunction
392- return evaluate_foreigncall(recurse , frame, node)
384+ return evaluate_foreigncall(interp , frame, node)
393385 elseif head === :copyast
394386 val = (node. args[1 ]:: QuoteNode ). value
395387 return isa(val, Expr) ? copy(val) : val
453445# in `step_expr!`
454446const _location = Dict{Tuple{Method,Int},Int}()
455447
456- function step_expr!(@nospecialize(recurse) , frame:: Frame , @nospecialize(node), istoplevel:: Bool )
448+ function step_expr!(interp :: Interpreter , frame:: Frame , @nospecialize(node), istoplevel:: Bool )
457449 pc, code, data = frame. pc, frame. framecode, frame. framedata
458450 # if !is_leaf(frame)
459451 # show_stackloc(frame)
@@ -473,7 +465,7 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
473465 if node. head === :(= )
474466 lhs, rhs = node. args
475467 if isa(rhs, Expr)
476- rhs = eval_rhs(recurse , frame, rhs)
468+ rhs = eval_rhs(interp , frame, rhs)
477469 else
478470 rhs = istoplevel ? @lookup(moduleof(frame), frame, rhs) : @lookup(frame, rhs)
479471 end
@@ -519,12 +511,12 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
519511 end
520512 elseif node. head === :thunk
521513 newframe = Frame(moduleof(frame), node. args[1 ]:: CodeInfo )
522- if isa(recurse , Compiled)
523- finish!(recurse , newframe, true )
514+ if isa(interp , Compiled)
515+ finish!(interp , newframe, true )
524516 else
525517 newframe. caller = frame
526518 frame. callee = newframe
527- finish!(recurse , newframe, true )
519+ finish!(interp , newframe, true )
528520 frame. callee = nothing
529521 end
530522 return_from(newframe)
@@ -541,7 +533,7 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
541533 end
542534 newframe = ($ Frame)(mod, ex)
543535 while true
544- ($ through_methoddef_or_done!)($ recurse , newframe) === nothing && break
536+ ($ through_methoddef_or_done!)($ interp , newframe) === nothing && break
545537 end
546538 $ return_from(newframe)
547539 end )))
@@ -552,12 +544,12 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
552544 elseif node. head === :latestworld
553545 frame. world = Base. get_world_counter()
554546 else
555- rhs = eval_rhs(recurse , frame, node)
547+ rhs = eval_rhs(interp , frame, node)
556548 end
557549 elseif node. head === :thunk || node. head === :toplevel
558550 error(" this frame needs to be run at top level" )
559551 else
560- rhs = eval_rhs(recurse , frame, node)
552+ rhs = eval_rhs(interp , frame, node)
561553 end
562554 elseif isa(node, GotoNode)
563555 @assert is_leaf(frame)
@@ -588,7 +580,7 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
588580 rhs = @lookup(frame, node)
589581 end
590582 catch err
591- return handle_err(recurse , frame, err)
583+ return handle_err(interp , frame, err)
592584 end
593585 @isdefined(rhs) && isa(rhs, BreakpointRef) && return rhs
594586 if isassign(frame, pc)
@@ -603,25 +595,24 @@ function step_expr!(@nospecialize(recurse), frame::Frame, @nospecialize(node), i
603595end
604596
605597"""
606- pc = step_expr!(recurse , frame, istoplevel=false)
598+ pc = step_expr!(interp::Interpreter , frame, istoplevel=false)
607599 pc = step_expr!(frame, istoplevel=false)
608600
609601Execute the next statement in `frame`. `pc` is the new program counter, or `nothing`
610602if execution terminates, or a [`BreakpointRef`](@ref) if execution hits a breakpoint.
611603
612- `recurse ` controls call evaluation; `recurse = Compiled()` evaluates :call expressions
613- by normal dispatch. The default value `recurse = finish_and_return! ` will use recursive
604+ `interp ` controls call evaluation; `interp = Compiled()` evaluates :call expressions
605+ by normal dispatch. The default value `interp = RecursiveInterpreter() ` will use recursive
614606interpretation.
615607
616608If you are evaluating `frame` at module scope you should pass `istoplevel=true`.
617609"""
618- step_expr!(@nospecialize(recurse), frame:: Frame , istoplevel:: Bool = false ) =
619- step_expr!(recurse, frame, pc_expr(frame), istoplevel)
620- step_expr!(frame:: Frame , istoplevel:: Bool = false ) =
621- step_expr!(finish_and_return!, frame, istoplevel)
610+ step_expr!(interp:: Interpreter , frame:: Frame , istoplevel:: Bool = false ) =
611+ step_expr!(interp, frame, pc_expr(frame), istoplevel)
612+ step_expr!(frame:: Frame , istoplevel:: Bool = false ) = step_expr!(RecursiveInterpreter(), frame, istoplevel)
622613
623614"""
624- loc = handle_err(recurse , frame, err)
615+ loc = handle_err(interp , frame, err)
625616
626617Deal with an error `err` that arose while evaluating `frame`. There are one of three
627618behaviors:
@@ -632,7 +623,7 @@ behaviors:
632623 `loc` is a `BreakpointRef`;
633624- otherwise, `err` gets rethrown.
634625"""
635- function handle_err(@nospecialize(recurse) , frame:: Frame , @nospecialize(err))
626+ function handle_err(:: Interpreter , frame:: Frame , @nospecialize(err))
636627 data = frame. framedata
637628 err_will_be_thrown_to_top_level = isempty(data. exception_frames) && ! data. caller_will_catch_err
638629 if break_on_throw[] || (break_on_error[] && err_will_be_thrown_to_top_level)
@@ -664,15 +655,16 @@ end
664655lookup_return(frame, node:: ReturnNode ) = @lookup(frame, node. val)
665656
666657"""
667- ret = get_return(frame)
658+ ret = get_return(interp, frame)
668659
669660Get the return value of `frame`. Throws an error if `frame.pc` does not point to a `return` expression.
670661`frame` must have already been executed so that the return value has been computed (see,
671662e.g., [`JuliaInterpreter.finish!`](@ref)).
672663"""
673- function get_return(frame)
664+ function get_return(interp :: Interpreter , frame:: Frame )
674665 node = pc_expr(frame)
675666 is_return(node) || @invokelatest error(" expected return statement, got " , node)
676667 return lookup_return(frame, node)
677668end
669+ get_return(frame:: Frame ) = get_return(RecursiveInterpreter(), frame)
678670get_return(t:: Tuple{Module,Expr,Frame} ) = get_return(t[end ])
0 commit comments