-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
use our own struct for the local method table instead of TypeMapEntry #313
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,13 @@ function breakpointchar(bps::BreakpointState) | |
return bps.condition === falsecondition ? ' ' : 'd' # no breakpoint : disabled | ||
end | ||
|
||
abstract type AbstractFrameInstance end | ||
mutable struct DispatchableMethod | ||
next::Union{Nothing,DispatchableMethod} # linked-list representation | ||
frameinstance::Union{Compiled, AbstractFrameInstance} # really a Union{Compiled, FrameInstance} but we have a cyclic dependency | ||
sig::Type # for speed of matching, this is a *concrete* signature. `sig <: frameinstance.framecode.scope.sig` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you're doing this, can you implement the tim@diva:~/.julia/dev/JuliaInterpreter$ git diff
diff --git a/src/construct.jl b/src/construct.jl
index 9b70786..796c4ab 100644
--- a/src/construct.jl
+++ b/src/construct.jl
@@ -236,6 +236,7 @@ function prepare_call(@nospecialize(f), allargs; enter_generated = false)
end
argtypesv = Any[_Typeof(a) for a in allargs]
argtypes = Tuple{argtypesv...}
+ println("Calling which (super-slow)")
method = whichtt(argtypes)
if method === nothing
# Call it to generate the exact error and the following test code using JuliaInterpreter
bar(::Int) = 1
bar(::Float64) = 2
push!(JuliaInterpreter.compiled_methods, @which bar(1.0))
function foo(A)
s = 0
for a in A
@bp
s += bar(a)
end
return s
end
A = Real[1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0]
frame = JuliaInterpreter.enter_call(foo, A)
for i = 1:length(A)
println("iteration ", i)
debug_command(frame, :c)
for i = 1:3
debug_command(frame, :se) # step forward to the call to bar
end
# display(frame.framecode.methodtables)
end I think you'll see what I'm worried about. (Note that the In the longer run we want to store the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correction: there's already this, so we don't have to modify Julia at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added caching for Compiled calls as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. function jl_generic(args)
args[1] + args[2]
end
function jl_invoke(args, mi)
ccall(:jl_invoke, Any, (Any, Ptr{Any}, Cuint, Any), +, args, 2, mi)
end
args = Any[1, 2]
@btime jl_generic($args)
# 25 ns
mi = Core.Compiler.specialize_method(@which(1 + 1), Tuple{typeof(+), Int, Int}, Core.svec())
@btime jl_invoke($args, $mi)
# 11 ns There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not quite sure I get what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, had a typo, |
||
end | ||
|
||
""" | ||
`FrameCode` holds static information about a method or toplevel code. | ||
One `FrameCode` can be shared by many calling `Frame`s. | ||
|
@@ -68,7 +75,7 @@ Important fields: | |
struct FrameCode | ||
scope::Union{Method,Module} | ||
src::CodeInfo | ||
methodtables::Vector{Union{Compiled,TypeMapEntry}} # line-by-line method tables for generic-function :call Exprs | ||
methodtables::Vector{Union{Compiled,DispatchableMethod}} # line-by-line method tables for generic-function :call Exprs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see how this prevents There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It prevents it because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason I still want to have |
||
breakpoints::Vector{BreakpointState} | ||
used::BitSet | ||
generator::Bool # true if this is for the expression-generator of a @generated function | ||
|
@@ -80,7 +87,7 @@ function FrameCode(scope, src::CodeInfo; generator=false, optimize=true) | |
src, methodtables = optimize!(copy_codeinfo(src), scope) | ||
else | ||
src = replace_coretypes!(copy_codeinfo(src)) | ||
methodtables = Vector{Union{Compiled,TypeMapEntry}}(undef, length(src.code)) | ||
methodtables = Vector{Union{Compiled,DispatchableMethod}}(undef, length(src.code)) | ||
end | ||
breakpoints = Vector{BreakpointState}(undef, length(src.code)) | ||
for (i, pc_expr) in enumerate(src.code) | ||
|
@@ -118,7 +125,7 @@ Fields: | |
- `framecode`: the [`FrameCode`](@ref) for the method. | ||
- `sparam_vals`: the static parameter values for the method. | ||
""" | ||
struct FrameInstance | ||
struct FrameInstance <: AbstractFrameInstance | ||
framecode::FrameCode | ||
sparam_vals::SimpleVector | ||
enter_generated::Bool | ||
|
@@ -331,7 +338,7 @@ struct BreakpointSignature <: AbstractBreakpoint | |
enabled::Ref{Bool} | ||
instances::Vector{BreakpointRef} | ||
end | ||
same_location(bp2::BreakpointSignature, bp::BreakpointSignature) = | ||
same_location(bp2::BreakpointSignature, bp::BreakpointSignature) = | ||
bp2.f == bp.f && bp2.sig == bp.sig && bp2.line == bp.line | ||
function Base.show(io::IO, bp::BreakpointSignature) | ||
print(io, bp.f) | ||
|
@@ -369,7 +376,7 @@ struct BreakpointFileLocation <: AbstractBreakpoint | |
enabled::Ref{Bool} | ||
instances::Vector{BreakpointRef} | ||
end | ||
same_location(bp2::BreakpointFileLocation, bp::BreakpointFileLocation) = | ||
same_location(bp2::BreakpointFileLocation, bp::BreakpointFileLocation) = | ||
bp2.path == bp.path && bp2.abspath == bp.abspath && bp2.line == bp.line | ||
function Base.show(io::IO, bp::BreakpointFileLocation) | ||
print(io, bp.path, ':', bp.line) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could hurt. Union-splitting may not work, unless the compiler is smart enough to know there is only one concrete subtype.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but we type assert immediately when we use it anyway but I will time some stuff and see if I can do it some other way.
Where the stuff in
TypeMapEntry
inferrable?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked a bit, there is a single place where we look at this field and all uses either just calls
isa
on it, or type asserts before it is used so there should be no dynamic behavior.