@@ -173,7 +173,7 @@ function bypass_builtins(frame, call_expr, pc)
173
173
return nothing
174
174
end
175
175
176
- function evaluate_call ! (:: Compiled , frame:: Frame , call_expr:: Expr )
176
+ function evaluate_call_compiled ! (:: Compiled , frame:: Frame , call_expr:: Expr )
177
177
pc = frame. pc
178
178
ret = bypass_builtins (frame, call_expr, pc)
179
179
isa (ret, Some{Any}) && return ret. value
@@ -185,7 +185,7 @@ function evaluate_call!(::Compiled, frame::Frame, call_expr::Expr)
185
185
return f (fargs... )
186
186
end
187
187
188
- function evaluate_call ! (@nospecialize (recurse:: Function ), frame:: Frame , call_expr:: Expr )
188
+ function evaluate_call_recurse ! (@nospecialize (recurse), frame:: Frame , call_expr:: Expr )
189
189
pc = frame. pc
190
190
ret = bypass_builtins (frame, call_expr, pc)
191
191
isa (ret, Some{Any}) && return ret. value
@@ -206,15 +206,21 @@ function evaluate_call!(@nospecialize(recurse::Function), frame::Frame, call_exp
206
206
end
207
207
return framecode # this was a Builtin
208
208
end
209
- newframe = prepare_frame (frame, framecode, fargs, lenv)
210
- shouldbreak (newframe) && return BreakpointRef (newframe. framecode, newframe. pc)
211
- ret = recurse (recurse, newframe) # if this errors, handle_err will pop the stack and recycle newframe
209
+ newframe = prepare_frame_caller (frame, framecode, fargs, lenv)
210
+ npc = newframe. pc
211
+ shouldbreak (newframe, npc) && return BreakpointRef (newframe. framecode, npc)
212
+ # if the following errors, handle_err will pop the stack and recycle newframe
213
+ if recurse === finish_and_return!
214
+ # Optimize this case to avoid dynamic dispatch
215
+ ret = finish_and_return! (finish_and_return!, newframe, false )
216
+ else
217
+ ret = recurse (recurse, newframe, false )
218
+ end
212
219
isa (ret, BreakpointRef) && return ret
213
220
frame. callee = nothing
214
221
recycle (newframe)
215
222
return ret
216
223
end
217
- evaluate_call! (frame:: Frame , call_expr:: Expr ) = evaluate_call! (finish_and_return!, frame, call_expr)
218
224
219
225
"""
220
226
ret = evaluate_call!(Compiled(), frame::Frame, call_expr)
@@ -225,7 +231,9 @@ The first causes it to be executed using Julia's normal dispatch (compiled code)
225
231
whereas the second recurses in via the interpreter.
226
232
`recurse` has a default value of [`JuliaInterpreter.finish_and_return!`](@ref).
227
233
"""
228
- evaluate_call!
234
+ evaluate_call! (:: Compiled , frame:: Frame , call_expr:: Expr ) = evaluate_call_compiled! (Compiled (), frame, call_expr)
235
+ evaluate_call! (@nospecialize (recurse), frame:: Frame , call_expr:: Expr ) = evaluate_call_recurse! (recurse, frame, call_expr)
236
+ evaluate_call! (frame:: Frame , call_expr:: Expr ) = evaluate_call! (finish_and_return!, frame, call_expr)
229
237
230
238
# The following come up only when evaluating toplevel code
231
239
function evaluate_methoddef (frame, node)
@@ -317,7 +325,9 @@ function eval_rhs(@nospecialize(recurse), frame, node::Expr)
317
325
elseif head == :isdefined
318
326
return check_isdefined (frame, node. args[1 ])
319
327
elseif head == :call
320
- return evaluate_call! (recurse, frame, node)
328
+ # here it's crucial to avoid dynamic dispatch
329
+ isa (recurse, Compiled) && return evaluate_call_compiled! (recurse, frame, node)
330
+ return evaluate_call_recurse! (recurse, frame, node)
321
331
elseif head == :foreigncall || head == :cfunction
322
332
return evaluate_foreigncall (frame, node)
323
333
elseif head == :copyast
0 commit comments