Skip to content

Commit

Permalink
Split reflection into compiler-dependent and compiler-independent pie…
Browse files Browse the repository at this point in the history
…ces (#56185)

The `reflection.jl` file provides a large amount of functionality
covering everything from helpers for access to core runtime data
structures to setting up particular inference problems. It is included
by both Base and Core.Compiler, but the functions that use the compiler,
don't really make sense in the latter. In preparation for #56128, and
stop including the compiler-dependent pieces in Core.Compiler.

While we're here, also move a few generically useful reflection
functions out of Core.Compiler, so users that access
them don't have to load the compiler.

Split out from #56128, but doesn't make any semantic changes by itself,
so should be quick/easy to merge.
  • Loading branch information
Keno authored and KristofferC committed Oct 21, 2024
1 parent 4f8bb4d commit 2e75c0a
Show file tree
Hide file tree
Showing 8 changed files with 1,601 additions and 1,600 deletions.
1 change: 1 addition & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ include("essentials.jl")
include("ctypes.jl")
include("gcutils.jl")
include("generator.jl")
include("runtime_internals.jl")
include("reflection.jl")
include("options.jl")

Expand Down
2 changes: 1 addition & 1 deletion base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const NUM_EFFECTS_OVERRIDES = 11 # sync with julia.h
include("essentials.jl")
include("ctypes.jl")
include("generator.jl")
include("reflection.jl")
include("runtime_internals.jl")
include("options.jl")

ntuple(f, ::Val{0}) = ()
Expand Down
2 changes: 0 additions & 2 deletions base/compiler/typeutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,6 @@ function typesubtract(@nospecialize(a), @nospecialize(b), max_union_splitting::I
return a # TODO: improve this bound?
end

hasintersect(@nospecialize(a), @nospecialize(b)) = typeintersect(a, b) !== Bottom

_typename(@nospecialize a) = Union{}
_typename(a::TypeVar) = Core.TypeName
function _typename(a::Union)
Expand Down
84 changes: 0 additions & 84 deletions base/compiler/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,6 @@ anymap(f::Function, a::Array{Any,1}) = Any[ f(a[i]) for i in 1:length(a) ]

_topmod(m::Module) = ccall(:jl_base_relative_to, Any, (Any,), m)::Module

#######
# AST #
#######

# Meta expression head, these generally can't be deleted even when they are
# in a dead branch but can be ignored when analyzing uses/liveness.
is_meta_expr_head(head::Symbol) = head === :boundscheck || head === :meta || head === :loopinfo
is_meta_expr(@nospecialize x) = isa(x, Expr) && is_meta_expr_head(x.head)

function is_self_quoting(@nospecialize(x))
return isa(x,Number) || isa(x,AbstractString) || isa(x,Tuple) || isa(x,Type) ||
isa(x,Char) || x === nothing || isa(x,Function)
end

function quoted(@nospecialize(x))
return is_self_quoting(x) ? x : QuoteNode(x)
end

############
# inlining #
############
Expand Down Expand Up @@ -116,10 +98,6 @@ function is_inlineable_constant(@nospecialize(x))
return count_const_size(x) <= MAX_INLINE_CONST_SIZE
end

is_nospecialized(method::Method) = method.nospecialize 0

is_nospecializeinfer(method::Method) = method.nospecializeinfer && is_nospecialized(method)

###########################
# MethodInstance/CodeInfo #
###########################
Expand Down Expand Up @@ -192,74 +170,12 @@ function get_compileable_sig(method::Method, @nospecialize(atype), sparams::Simp
mt, atype, sparams, method, #=int return_if_compileable=#1)
end

function get_nospecializeinfer_sig(method::Method, @nospecialize(atype), sparams::SimpleVector)
isa(atype, DataType) || return method.sig
mt = ccall(:jl_method_get_table, Any, (Any,), method)
mt === nothing && return method.sig
return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any, Cint),
mt, atype, sparams, method, #=int return_if_compileable=#0)
end

isa_compileable_sig(@nospecialize(atype), sparams::SimpleVector, method::Method) =
!iszero(ccall(:jl_isa_compileable_sig, Int32, (Any, Any, Any), atype, sparams, method))

# eliminate UnionAll vars that might be degenerate due to having identical bounds,
# or a concrete upper bound and appearing covariantly.
function subst_trivial_bounds(@nospecialize(atype))
if !isa(atype, UnionAll)
return atype
end
v = atype.var
if isconcretetype(v.ub) || v.lb === v.ub
subst = try
atype{v.ub}
catch
# Note in rare cases a var bound might not be valid to substitute.
nothing
end
if subst !== nothing
return subst_trivial_bounds(subst)
end
end
return UnionAll(v, subst_trivial_bounds(atype.body))
end

has_typevar(@nospecialize(t), v::TypeVar) = ccall(:jl_has_typevar, Cint, (Any, Any), t, v) != 0

# If removing trivial vars from atype results in an equivalent type, use that
# instead. Otherwise we can get a case like issue #38888, where a signature like
# f(x::S) where S<:Int
# gets cached and matches a concrete dispatch case.
function normalize_typevars(method::Method, @nospecialize(atype), sparams::SimpleVector)
at2 = subst_trivial_bounds(atype)
if at2 !== atype && at2 == atype
atype = at2
sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), at2, method.sig)::SimpleVector
sparams = sp_[2]::SimpleVector
end
return Pair{Any,SimpleVector}(atype, sparams)
end

# get a handle to the unique specialization object representing a particular instantiation of a call
@inline function specialize_method(method::Method, @nospecialize(atype), sparams::SimpleVector; preexisting::Bool=false)
if isa(atype, UnionAll)
atype, sparams = normalize_typevars(method, atype, sparams)
end
if is_nospecializeinfer(method)
atype = get_nospecializeinfer_sig(method, atype, sparams)
end
if preexisting
# check cached specializations
# for an existing result stored there
return ccall(:jl_specializations_lookup, Any, (Any, Any), method, atype)::Union{Nothing,MethodInstance}
end
return ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any), method, atype, sparams)
end

function specialize_method(match::MethodMatch; kwargs...)
return specialize_method(match.method, match.spec_types, match.sparams; kwargs...)
end

"""
is_declared_inline(method::Method) -> Bool
Expand Down
14 changes: 14 additions & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1560,3 +1560,17 @@ function make_atomiconce(success_order, fail_order, ex)
end
error("@atomiconce expression missing field access or indexing")
end

# Meta expression head, these generally can't be deleted even when they are
# in a dead branch but can be ignored when analyzing uses/liveness.
is_meta_expr_head(head::Symbol) = head === :boundscheck || head === :meta || head === :loopinfo
is_meta_expr(@nospecialize x) = isa(x, Expr) && is_meta_expr_head(x.head)

function is_self_quoting(@nospecialize(x))
return isa(x,Number) || isa(x,AbstractString) || isa(x,Tuple) || isa(x,Type) ||
isa(x,Char) || x === nothing || isa(x,Function)
end

function quoted(@nospecialize(x))
return is_self_quoting(x) ? x : QuoteNode(x)
end
Loading

0 comments on commit 2e75c0a

Please sign in to comment.