Skip to content

Commit

Permalink
pack more bits in DataType
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Jun 5, 2021
1 parent de6f62a commit f487e0c
Show file tree
Hide file tree
Showing 22 changed files with 111 additions and 133 deletions.
4 changes: 2 additions & 2 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
end
elseif e.head === :new
t = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))[1]
if isconcretetype(t) && !t.name.mutable
if isconcretetype(t) && !ismutabletype(t)
args = Vector{Any}(undef, length(e.args)-1)
ats = Vector{Any}(undef, length(e.args)-1)
anyconst = false
Expand Down Expand Up @@ -1465,7 +1465,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
end
elseif e.head === :splatnew
t = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))[1]
if length(e.args) == 2 && isconcretetype(t) && !t.name.mutable
if length(e.args) == 2 && isconcretetype(t) && !ismutabletype(t)
at = abstract_eval_value(interp, e.args[2], vtypes, sv)
n = fieldcount(t)
if isa(at, Const) && isa(at.val, Tuple) && n == length(at.val) &&
Expand Down
10 changes: 5 additions & 5 deletions base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ function lift_leaves(compact::IncrementalCompact, @nospecialize(stmt),
if isa(typ, UnionAll)
typ = unwrap_unionall(typ)
end
(isa(typ, DataType) && (!typ.name.abstract)) || return nothing
@assert !typ.name.mutable
(isa(typ, DataType) && !isabstracttype(typ)) || return nothing
@assert !ismutabletype(typ)
if length(def.args) < 1 + field
if field > fieldcount(typ)
return nothing
Expand Down Expand Up @@ -635,7 +635,7 @@ function getfield_elim_pass!(ir::IRCode)
if isa(typ, UnionAll)
typ = unwrap_unionall(typ)
end
if typ isa DataType && !typ.name.mutable
if typ isa DataType && !ismutabletype(typ)
process_immutable_preserve(new_preserves, compact, def)
old_preserves[pidx] = nothing
continue
Expand Down Expand Up @@ -677,7 +677,7 @@ function getfield_elim_pass!(ir::IRCode)

def, typeconstraint = stmt.args[2], struct_typ

if struct_typ.name.mutable
if ismutabletype(struct_typ)
isa(def, SSAValue) || continue
let intermediaries = IdSet()
callback = function(@nospecialize(pi), ssa::AnySSAValue)
Expand Down Expand Up @@ -790,7 +790,7 @@ function getfield_elim_pass!(ir::IRCode)
end
# Could still end up here if we tried to setfield! and immutable, which would
# error at runtime, but is not illegal to have in the IR.
typ.name.mutable || continue
ismutabletype(typ) || continue
# Partition defuses by field
fielddefuse = SSADefUse[SSADefUse() for _ = 1:fieldcount(typ)]
ok = true
Expand Down
26 changes: 12 additions & 14 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ const TYPENAME_NAME_FIELDINDEX = fieldindex(Core.TypeName, :name)
const TYPENAME_MODULE_FIELDINDEX = fieldindex(Core.TypeName, :module)
const TYPENAME_NAMES_FIELDINDEX = fieldindex(Core.TypeName, :names)
const TYPENAME_WRAPPER_FIELDINDEX = fieldindex(Core.TypeName, :wrapper)
const TYPENAME_MUTABLE_FIELDINDEX = fieldindex(Core.TypeName, :mutable)
const TYPENAME_ABSTRACT_FIELDINDEX = fieldindex(Core.TypeName, :abstract)
const TYPENAME_HASH_FIELDINDEX = fieldindex(Core.TypeName, :hash)
const TYPENAME_FLAGS_FIELDINDEX = fieldindex(Core.TypeName, :flags)

##########
# tfuncs #
Expand Down Expand Up @@ -89,7 +88,7 @@ function instanceof_tfunc(@nospecialize(t))
# a real instance must be within the declared bounds of the type,
# so we can intersect with the original wrapper.
tr = typeintersect(tr, t′′.name.wrapper)
isconcrete = !t′′.name.abstract
isconcrete = !isabstracttype(t′′)
if tr === Union{}
# runtime unreachable (our inference Type{T} where S is
# uninhabited with any runtime T that exists)
Expand Down Expand Up @@ -273,7 +272,7 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym))
return Bool
end
a1 = unwrap_unionall(a1)
if isa(a1, DataType) && !a1.name.abstract
if isa(a1, DataType) && !isabstracttype(a1)
if a1 === Module
Symbol <: widenconst(sym) || return Bottom
if isa(sym, Const) && isa(sym.val, Symbol) && isa(arg1, Const) && isdefined(arg1.val, sym.val)
Expand Down Expand Up @@ -406,7 +405,7 @@ function nfields_tfunc(@nospecialize(x))
isa(x, Conditional) && return Const(0)
x = unwrap_unionall(widenconst(x))
isconstType(x) && return Const(nfields(x.parameters[1]))
if isa(x, DataType) && !x.name.abstract
if isa(x, DataType) && !isabstracttype(x)
if !(x.name === Tuple.name && isvatuple(x)) &&
!(x.name === _NAMEDTUPLE_NAME && !isconcretetype(x))
return Const(isdefined(x, :types) ? length(x.types) : length(x.name.names))
Expand Down Expand Up @@ -535,7 +534,7 @@ function typeof_tfunc(@nospecialize(t))
return typeof_tfunc(t.ub)
elseif isa(t, UnionAll)
u = unwrap_unionall(t)
if isa(u, DataType) && !u.name.abstract
if isa(u, DataType) && !isabstracttype(u)
if u.name === Tuple.name
uu = typeof_concrete_vararg(u)
if uu !== nothing
Expand Down Expand Up @@ -653,7 +652,7 @@ function fieldcount_noerror(@nospecialize t)
end
abstr = true
else
abstr = t.name.abstract || (t.name === Tuple.name && isvatuple(t))
abstr = isabstracttype(t) || (t.name === Tuple.name && isvatuple(t))
end
if abstr
return nothing
Expand Down Expand Up @@ -732,7 +731,7 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), boundscheck::
getfield_nothrow(rewrap(s.b, s00), name, boundscheck)
elseif isa(s, DataType)
# Can't say anything about abstract types
s.name.abstract && return false
isabstracttype(s) && return false
s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering == :not_atomic
# If all fields are always initialized, and bounds check is disabled, we can assume
# we don't throw
Expand Down Expand Up @@ -791,9 +790,8 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
if (fld == TYPENAME_NAME_FIELDINDEX ||
fld == TYPENAME_MODULE_FIELDINDEX ||
fld == TYPENAME_WRAPPER_FIELDINDEX ||
fld == TYPENAME_MUTABLE_FIELDINDEX ||
fld == TYPENAME_ABSTRACT_FIELDINDEX ||
fld == TYPENAME_HASH_FIELDINDEX ||
fld == TYPENAME_FLAGS_FIELDINDEX ||
(fld == TYPENAME_NAMES_FIELDINDEX && isdefined(sv, fld)))
return Const(getfield(sv, fld))
end
Expand All @@ -818,7 +816,7 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
end
s = widenconst(s)
end
if isType(s) || !isa(s, DataType) || s.name.abstract
if isType(s) || !isa(s, DataType) || isabstracttype(s)
return Any
end
s = s::DataType
Expand All @@ -833,7 +831,7 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
end
# If no value has this type, then this statement should be unreachable.
# Bail quickly now.
s.has_concrete_subtype || return Union{}
has_concrete_subtype(s) || return Union{}
if s.name === _NAMEDTUPLE_NAME && !isconcretetype(s)
if isa(name, Const) && isa(name.val, Symbol)
if isa(s.parameters[1], Tuple)
Expand Down Expand Up @@ -959,7 +957,7 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
return exact ? (a || b) : (a && b)
end
u isa DataType || return false
u.name.abstract && return false
isabstracttype(u) && return false
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
# TODO: better approximate inference
return false
Expand Down Expand Up @@ -1021,7 +1019,7 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
_fieldtype_tfunc(rewrap(u.b, s), exact, name))
end
u isa DataType || return Any
if u.name.abstract
if isabstracttype(u)
# Abstract types have no fields
exact && return Bottom
# Type{...} without free typevars has no subtypes, so it is actually
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/typelimits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe
let tPi = unwrap_unionall(tPi),
cPi = unwrap_unionall(cPi)
if isa(tPi, DataType) && isa(cPi, DataType) &&
!tPi.name.abstract && !cPi.name.abstract &&
!isabstracttype(tPi) && !isabstracttype(cPi) &&
sym_isless(cPi.name.name, tPi.name.name)
# allow collect on (anonymous) Generators to nest, provided that their functions are appropriately ordered
# TODO: is there a better way?
Expand Down
4 changes: 3 additions & 1 deletion base/compiler/typeutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ end

has_const_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x)

has_concrete_subtype(d::DataType) = d.flags & 0x20 == 0x20

# Subtyping currently intentionally answers certain queries incorrectly for kind types. For
# some of these queries, this check can be used to somewhat protect against making incorrect
# decisions based on incorrect subtyping. Note that this check, itself, is broken for
Expand All @@ -59,7 +61,7 @@ end
# Compute the minimum number of initialized fields for a particular datatype
# (therefore also a lower bound on the number of fields)
function datatype_min_ninitialized(t::DataType)
t.name.abstract && return 0
isabstracttype(t) && return 0
if t.name === NamedTuple_typename
names, types = t.parameters[1], t.parameters[2]
if names isa Tuple
Expand Down
2 changes: 1 addition & 1 deletion base/deepcopy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ end
function deepcopy_internal(@nospecialize(x), stackdict::IdDict)
T = typeof(x)::DataType
nf = nfields(x)
if T.name.mutable
if ismutable(x)
if haskey(stackdict, x)
return stackdict[x]
end
Expand Down
2 changes: 1 addition & 1 deletion base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ function showerror(io::IO, ex::MethodError)
if f === Base.convert && length(arg_types_param) == 2 && !is_arg_types
f_is_function = true
show_convert_error(io, ex, arg_types_param)
elseif isempty(methods(f)) && isa(f, DataType) && f.name.abstract
elseif isempty(methods(f)) && isa(f, DataType) && isabstracttype(f)
print(io, "no constructors have been defined for ", f)
elseif isempty(methods(f)) && !isa(f, Function) && !isa(f, Type)
print(io, "objects of type ", ft, " are not callable")
Expand Down
2 changes: 1 addition & 1 deletion base/pointer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ See also [`unsafe_pointer_to_objref`](@ref).
"""
function pointer_from_objref(@nospecialize(x))
@_inline_meta
typeof(x).name.mutable || error("pointer_from_objref cannot be used on immutable objects")
ismutable(x) || error("pointer_from_objref cannot be used on immutable objects")
ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
end

Expand Down
22 changes: 11 additions & 11 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ function fieldname(t::DataType, i::Integer)
end
throw_need_pos_int(i) = throw(ArgumentError("Field numbers must be positive integers. $i is invalid."))

t.name.abstract && throw_not_def_field()
isabstracttype(t) && throw_not_def_field()
names = _fieldnames(t)
n_fields = length(names)::Int
i > n_fields && throw_field_access(t, i, n_fields)
Expand Down Expand Up @@ -471,7 +471,7 @@ true
!!! compat "Julia 1.5"
This function requires at least Julia 1.5.
"""
ismutable(@nospecialize(x)) = (@_pure_meta; typeof(x).name.mutable)
ismutable(@nospecialize(x)) = (@_pure_meta; typeof(x).name.flags & 0x2 == 0x2)


"""
Expand All @@ -486,7 +486,7 @@ Determine whether type `T` was declared as a mutable type
function ismutabletype(@nospecialize(t::Type))
t = unwrap_unionall(t)
# TODO: what to do for `Union`?
return isa(t, DataType) && t.name.mutable
return isa(t, DataType) && t.name.flags & 0x2 == 0x2
end


Expand All @@ -502,7 +502,7 @@ function isstructtype(@nospecialize(t::Type))
# TODO: what to do for `Union`?
isa(t, DataType) || return false
hasfield = !isdefined(t, :types) || !isempty(t.types)
return hasfield || (t.size == 0 && !t.name.abstract)
return hasfield || (t.size == 0 && !isabstracttype(t))
end

"""
Expand All @@ -517,7 +517,7 @@ function isprimitivetype(@nospecialize(t::Type))
# TODO: what to do for `Union`?
isa(t, DataType) || return false
hasfield = !isdefined(t, :types) || !isempty(t.types)
return !hasfield && t.size != 0 && !t.name.abstract
return !hasfield && t.size != 0 && !isabstracttype(t)
end

"""
Expand All @@ -543,14 +543,14 @@ julia> isbitstype(Complex)
false
```
"""
isbitstype(@nospecialize(t::Type)) = (@_pure_meta; isa(t, DataType) && t.isbitstype)
isbitstype(@nospecialize(t::Type)) = (@_pure_meta; isa(t, DataType) && (t.flags & 0x8) == 0x8)

"""
isbits(x)
Return `true` if `x` is an instance of an [`isbitstype`](@ref) type.
"""
isbits(@nospecialize x) = (@_pure_meta; typeof(x).isbitstype)
isbits(@nospecialize x) = (@_pure_meta; typeof(x).flags & 0x8 == 0x8)

"""
isdispatchtuple(T)
Expand All @@ -559,7 +559,7 @@ Determine whether type `T` is a tuple "leaf type",
meaning it could appear as a type signature in dispatch
and has no subtypes (or supertypes) which could appear in a call.
"""
isdispatchtuple(@nospecialize(t)) = (@_pure_meta; isa(t, DataType) && t.isdispatchtuple)
isdispatchtuple(@nospecialize(t)) = (@_pure_meta; isa(t, DataType) && (t.flags & 0x4) == 0x4)

iskindtype(@nospecialize t) = (t === DataType || t === UnionAll || t === Union || t === typeof(Bottom))
isconcretedispatch(@nospecialize t) = isconcretetype(t) && !iskindtype(t)
Expand Down Expand Up @@ -602,7 +602,7 @@ julia> isconcretetype(Union{Int,String})
false
```
"""
isconcretetype(@nospecialize(t)) = (@_pure_meta; isa(t, DataType) && t.isconcretetype)
isconcretetype(@nospecialize(t)) = (@_pure_meta; isa(t, DataType) && (t.flags & 0x2) == 0x2)

"""
isabstracttype(T)
Expand All @@ -623,7 +623,7 @@ function isabstracttype(@nospecialize(t))
@_pure_meta
t = unwrap_unionall(t)
# TODO: what to do for `Union`?
return isa(t, DataType) && t.name.abstract
return isa(t, DataType) && (t.name.flags & 0x1) == 0x1
end

"""
Expand Down Expand Up @@ -758,7 +758,7 @@ function fieldcount(@nospecialize t)
end
abstr = true
else
abstr = t.name.abstract || (t.name === Tuple.name && isvatuple(t))
abstr = isabstracttype(t) || (t.name === Tuple.name && isvatuple(t))
end
if abstr
throw(ArgumentError("type does not have a definite number of fields"))
Expand Down
2 changes: 1 addition & 1 deletion base/refpointer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ convert(::Type{Ref{T}}, x::AbstractArray{T}) where {T} = RefArray(x, 1)
function unsafe_convert(P::Union{Type{Ptr{T}},Type{Ptr{Cvoid}}}, b::RefArray{T})::P where T
if allocatedinline(T)
p = pointer(b.x, b.i)
elseif isconcretetype(T) && T.name.mutable
elseif isconcretetype(T) && ismutabletype(T)
p = pointer_from_objref(b.x[b.i])
else
# see comment on equivalent branch for RefValue
Expand Down
2 changes: 1 addition & 1 deletion base/refvalue.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ isassigned(x::RefValue) = isdefined(x, :x)
function unsafe_convert(P::Union{Type{Ptr{T}},Type{Ptr{Cvoid}}}, b::RefValue{T})::P where T
if allocatedinline(T)
p = pointer_from_objref(b)
elseif isconcretetype(T) && T.name.mutable
elseif isconcretetype(T) && ismutabletype(T)
p = pointer_from_objref(b.x)
else
# If the slot is not leaf type, it could be either immutable or not.
Expand Down
2 changes: 1 addition & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2615,7 +2615,7 @@ function dump(io::IOContext, x::DataType, n::Int, indent)
if x !== Any
print(io, " <: ", supertype(x))
end
if n > 0 && !(x <: Tuple) && !x.name.abstract
if n > 0 && !(x <: Tuple) && !isabstracttype(x)
tvar_io::IOContext = io
for tparam in x.parameters
# approximately recapture the list of tvar parameterization
Expand Down
18 changes: 4 additions & 14 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,24 +987,13 @@ static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt)
Value *Idx = ConstantInt::get(T_size, offsetof(jl_datatype_t, name));
Value *Nam = tbaa_decorate(tbaa_const,
ctx.builder.CreateAlignedLoad(T_pint8, ctx.builder.CreateInBoundsGEP(T_pint8, Ptr, Idx), Align(sizeof(int8_t*))));
Value *Idx2 = ConstantInt::get(T_size, offsetof(jl_typename_t, name));
Value *Idx2 = ConstantInt::get(T_size, offsetof(jl_typename_t, n_uninitialized) + sizeof(((jl_typename_t*)nullptr)->n_uninitialized));
Value *mutabl = tbaa_decorate(tbaa_const,
ctx.builder.CreateAlignedLoad(T_int8, ctx.builder.CreateInBoundsGEP(T_int8, Nam, Idx2), Align(1)));
mutabl = ctx.builder.CreateLShr(mutabl, 1);
return ctx.builder.CreateTrunc(mutabl, T_int1);
}

/* this is valid code, it's simply unused
static Value *emit_datatype_abstract(jl_codectx_t &ctx, Value *dt)
{
Value *Ptr = emit_bitcast(ctx, decay_derived(ctx, dt), T_pint8);
Value *Idx = ConstantInt::get(T_size, offsetof(jl_datatype_t, abstract));
Value *abstract = tbaa_decorate(tbaa_const,
ctx.builder.CreateAlignedLoad(T_int8, ctx.builder.CreateInBoundsGEP(T_int8, Ptr, Idx), Align(1)));
return ctx.builder.CreateTrunc(abstract, T_int1);
}
*/

static Value *emit_datatype_isprimitivetype(jl_codectx_t &ctx, Value *dt)
{
Value *immut = ctx.builder.CreateNot(emit_datatype_mutabl(ctx, dt));
Expand Down Expand Up @@ -1297,8 +1286,9 @@ static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *t
static Value *emit_isconcrete(jl_codectx_t &ctx, Value *typ)
{
Value *isconcrete;
isconcrete = ctx.builder.CreateConstInBoundsGEP1_32(T_int8, emit_bitcast(ctx, decay_derived(ctx, typ), T_pint8), offsetof(jl_datatype_t, isconcretetype));
isconcrete = ctx.builder.CreateConstInBoundsGEP1_32(T_int8, emit_bitcast(ctx, decay_derived(ctx, typ), T_pint8), offsetof(jl_datatype_t, hash) + sizeof(((jl_datatype_t*)nullptr)->hash));
isconcrete = tbaa_decorate(tbaa_const, ctx.builder.CreateAlignedLoad(T_int8, isconcrete, Align(1)));
isconcrete = ctx.builder.CreateLShr(isconcrete, 1);
isconcrete = ctx.builder.CreateTrunc(isconcrete, T_int1);
return isconcrete;
}
Expand Down
Loading

0 comments on commit f487e0c

Please sign in to comment.