Skip to content

Commit

Permalink
Merge pull request #16 from JuliaDebug/teh/divert
Browse files Browse the repository at this point in the history
Support diversion of specific methods to Compiled
  • Loading branch information
timholy authored Feb 12, 2019
2 parents 57a9073 + 1e3f57a commit f3a60f7
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 4 deletions.
11 changes: 10 additions & 1 deletion src/JuliaInterpreter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ JuliaStackFrame(frame::JuliaStackFrame, pc::JuliaProgramCounter; kwargs...) =
see [`genframedict`](@ref).
"""
const framedict = Dict{Method,JuliaFrameCode}() # essentially a method table for lowered code

"""
`genframedict[(method,argtypes)]` returns the `JuliaFrameCode` for a `@generated` method `method`,
for the particular argument types `argtypes`.
Expand All @@ -128,6 +129,12 @@ for the generator itself, its framecode would be stored in [`framedict`](@ref).
"""
const genframedict = Dict{Tuple{Method,Type},JuliaFrameCode}() # the same for @generated functions

"""
`meth ∈ compiled_methods` indicates that `meth` should be run using [`Compiled`](@ref)
rather than recursed into via the interpreter.
"""
const compiled_methods = Set{Method}()

const junk = JuliaStackFrame[] # to allow re-use of allocated memory (this is otherwise a bottleneck)

const empty_svec = Core.svec()
Expand All @@ -149,7 +156,6 @@ Base.nameof(frame) = isa(frame.code.scope, Method) ? frame.code.scope.name : nam
is_loc_meta(expr, kind) = isexpr(expr, :meta) && length(expr.args) >= 1 && expr.args[1] === kind



function to_function(x)
if isa(x, GlobalRef)
getfield(x.mod, x.name)
Expand Down Expand Up @@ -282,6 +288,9 @@ function prepare_call(@nospecialize(f), allargs; enter_generated = false)
args = allargs
sig = method.sig
isa(method, TypeMapEntry) && (method = method.func)
if method compiled_methods
return Compiled()
end
# Get static parameters
(ti, lenv::SimpleVector) = ccall(:jl_type_intersection_with_env, Any, (Any, Any),
argtypes, sig)::SimpleVector
Expand Down
6 changes: 5 additions & 1 deletion src/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,18 @@ function evaluate_call!(stack, frame::JuliaStackFrame, call_expr::Expr, pc)
ret = maybe_evaluate_builtin(frame, call_expr)
isa(ret, Some{Any}) && return ret.value
fargs = collect_args(frame, call_expr)
if fargs[1] === Core.eval
if (f = fargs[1]) === Core.eval
return Core.eval(fargs[2], fargs[3]) # not a builtin, but worth treating specially
elseif fargs[1] === Base.rethrow
err = length(fargs) > 1 ? fargs[2] : frame.last_exception[]
throw(err)
end
framecode, lenv = get_call_framecode(fargs, frame.code, pc.next_stmt)
if lenv === nothing
if isa(framecode, Compiled)
popfirst!(fargs) # now it's really just `args`
return f(fargs...)
end
return framecode # this was a Builtin
end
frame.pc[] = pc # to mark position in the frame (e.g., if we hit breakpoint or error)
Expand Down
6 changes: 5 additions & 1 deletion src/localmethtable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ function get_call_framecode(fargs, parentframe::JuliaFrameCode, idx::Int)
if f === Base._return_type
return Base._return_type(fargs[2:end]...), nothing
end
framecode, args, env, argtypes = prepare_call(f, fargs)
ret = prepare_call(f, fargs)
if isa(ret, Compiled)
return ret, nothing
end
framecode, args, env, argtypes = ret
# Store the results of the method lookup in the local method table
tme = ccall(:jl_new_struct_uninit, Any, (Any,), TypeMapEntry)::TypeMapEntry
tme.func = mi = ccall(:jl_new_struct_uninit, Any, (Any,), MethodInstance)::MethodInstance
Expand Down
17 changes: 16 additions & 1 deletion test/juliatests.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using JuliaInterpreter
using Test
using Test, Random

if !isdefined(Main, :read_and_parse)
include("utils.jl")
Expand All @@ -18,6 +18,21 @@ using Test
end

@testset "Julia tests" begin
# To do this efficiently, certain methods must be run in Compiled mode
cm = JuliaInterpreter.compiled_methods
empty!(cm)
push!(cm, which(Test.eval_test, Tuple{Expr, Expr, LineNumberNode}))
push!(cm, which(Test.finish, Tuple{Test.DefaultTestSet}))
push!(cm, which(Test.get_testset, Tuple{}))
push!(cm, which(Test.push_testset, Tuple{Test.AbstractTestSet}))
push!(cm, which(Test.pop_testset, Tuple{}))
push!(cm, which(Random.seed!, Tuple{Union{Integer,Vector{UInt32}}}))
push!(cm, which(copy!, Tuple{Random.MersenneTwister, Random.MersenneTwister}))
push!(cm, which(copy, Tuple{Random.MersenneTwister}))
push!(cm, which(Base.include, Tuple{Module, String}))
push!(cm, which(Base.show_backtrace, Tuple{IO, Vector}))
push!(cm, which(Base.show_backtrace, Tuple{IO, Vector{Any}}))

stack = JuliaStackFrame[]
function runtest(frame)
empty!(stack)
Expand Down

0 comments on commit f3a60f7

Please sign in to comment.