diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 9f4ca7ac7a4f7..db68fe721642c 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -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 @@ -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) && diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 0293cecfe38d7..ce20a61a4e983 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -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 @@ -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 @@ -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) @@ -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 diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 03f257360056a..56fe9d1591848 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -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 # @@ -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) @@ -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) @@ -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)) @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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 diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index 372989e114022..3145517630958 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -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? diff --git a/base/compiler/typeutils.jl b/base/compiler/typeutils.jl index 39b7ad0f16a4e..ae4913e4aec18 100644 --- a/base/compiler/typeutils.jl +++ b/base/compiler/typeutils.jl @@ -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 @@ -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 diff --git a/base/deepcopy.jl b/base/deepcopy.jl index abe8a07fc9a3e..7ea5a041fc632 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -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 diff --git a/base/errorshow.jl b/base/errorshow.jl index 1d2745f63b297..1e03996e410ea 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -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") diff --git a/base/pointer.jl b/base/pointer.jl index d5b4972cc7875..b315e589ffd9a 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -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 diff --git a/base/reflection.jl b/base/reflection.jl index 8f3353f4bdd50..876d1cda78da9 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -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) @@ -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) """ @@ -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 @@ -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 """ @@ -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 """ @@ -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) @@ -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) @@ -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) @@ -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 """ @@ -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")) diff --git a/base/refpointer.jl b/base/refpointer.jl index 725b2d05f95ee..cd179c87b30d5 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -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 diff --git a/base/refvalue.jl b/base/refvalue.jl index 69d9a31061724..7cbb651d41aee 100644 --- a/base/refvalue.jl +++ b/base/refvalue.jl @@ -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. diff --git a/base/show.jl b/base/show.jl index fcc3d32526f3a..474f2ff25faa2 100644 --- a/base/show.jl +++ b/base/show.jl @@ -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 diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 37d2f78421b82..bb9b3d63f91fb 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -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)); @@ -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; } diff --git a/src/jltypes.c b/src/jltypes.c index da55d8e89c9bf..af2e4f8f3a081 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -1948,63 +1948,58 @@ void jl_init_types(void) JL_GC_DISABLED // initialize them. lots of cycles. // NOTE: types are not actually mutable, but we want to ensure they are heap-allocated with stable addresses jl_datatype_type->name = jl_new_typename_in(jl_symbol("DataType"), core, 0, 1); - jl_datatype_type->name->n_uninitialized = 15 - 3; jl_datatype_type->name->wrapper = (jl_value_t*)jl_datatype_type; jl_datatype_type->super = (jl_datatype_t*)jl_type_type; jl_datatype_type->parameters = jl_emptysvec; - jl_datatype_type->name->names = jl_perm_symsvec(15, - "name", - "super", - "parameters", - "types", - "instance", - "layout", - "size", - "hash", - "hasfreetypevars", - "isconcretetype", - "isdispatchtuple", - "isbitstype", - "zeroinit", - "has_concrete_subtype", - "cached_by_hash"); - jl_datatype_type->types = jl_svec(15, - jl_typename_type, - jl_datatype_type, - jl_simplevector_type, - jl_simplevector_type, - jl_any_type, // instance - jl_any_type, jl_any_type, jl_any_type, jl_any_type, // properties - jl_any_type, jl_any_type, jl_any_type, jl_any_type, - jl_any_type, jl_any_type); + jl_datatype_type->name->n_uninitialized = 9 - 3; + jl_datatype_type->name->names = jl_perm_symsvec(9, + "name", + "super", + "parameters", + "types", + "instance", + "layout", + "size", + "hash", + "flags"); // "hasfreetypevars", "isconcretetype", "isdispatchtuple", "isbitstype", "zeroinit", "has_concrete_subtype", "cached_by_hash" + jl_datatype_type->types = jl_svec(9, + jl_typename_type, + jl_datatype_type, + jl_simplevector_type, + jl_simplevector_type, + jl_any_type, // instance + jl_any_type /*jl_voidpointer_type*/, + jl_any_type /*jl_int32_type*/, + jl_any_type /*jl_int32_type*/, + jl_any_type /*jl_uint8_type*/); jl_precompute_memoized_dt(jl_datatype_type, 1); jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core, 0, 1); - jl_typename_type->name->n_uninitialized = 14 - 2; jl_typename_type->name->wrapper = (jl_value_t*)jl_typename_type; jl_typename_type->name->mt = jl_nonfunction_mt; jl_typename_type->super = jl_any_type; jl_typename_type->parameters = jl_emptysvec; - jl_typename_type->name->names = jl_perm_symsvec(14, "name", "module", + jl_typename_type->name->n_uninitialized = 12 - 2; + jl_typename_type->name->names = jl_perm_symsvec(12, "name", "module", "names", "atomicfields", "wrapper", "cache", "linearcache", + "mt", "partial", "hash", "n_uninitialized", - "abstract", "mutable", "mayinlinealloc", - "mt", "partial"); - jl_typename_type->types = jl_svec(14, jl_symbol_type, jl_any_type /*jl_module_type*/, + "flags"); // "abstract", "mutable", "mayinlinealloc", + jl_typename_type->types = jl_svec(12, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_simplevector_type, jl_any_type/*jl_voidpointer_type*/, jl_type_type, jl_simplevector_type, jl_simplevector_type, + jl_methtable_type, jl_any_type, jl_any_type /*jl_long_type*/, jl_any_type /*jl_int32_type*/, - jl_any_type /*jl_bool_type*/, jl_any_type /*jl_bool_type*/, jl_any_type /*jl_bool_type*/, - jl_methtable_type, jl_any_type); + jl_any_type /*jl_uint8_type*/); jl_precompute_memoized_dt(jl_typename_type, 1); jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core, 0, 1); - jl_methtable_type->name->n_uninitialized = 12 - 5; jl_methtable_type->name->wrapper = (jl_value_t*)jl_methtable_type; jl_methtable_type->name->mt = jl_nonfunction_mt; jl_methtable_type->super = jl_any_type; jl_methtable_type->parameters = jl_emptysvec; + jl_methtable_type->name->n_uninitialized = 12 - 5; jl_methtable_type->name->names = jl_perm_symsvec(12, "name", "defs", "leafcache", "cache", "max_args", "kwsorter", "module", @@ -2592,21 +2587,13 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_datatype_type->types, 5, jl_voidpointer_type); jl_svecset(jl_datatype_type->types, 6, jl_int32_type); jl_svecset(jl_datatype_type->types, 7, jl_int32_type); - jl_svecset(jl_datatype_type->types, 8, jl_bool_type); - jl_svecset(jl_datatype_type->types, 9, jl_bool_type); - jl_svecset(jl_datatype_type->types, 10, jl_bool_type); - jl_svecset(jl_datatype_type->types, 11, jl_bool_type); - jl_svecset(jl_datatype_type->types, 12, jl_bool_type); - jl_svecset(jl_datatype_type->types, 13, jl_bool_type); - jl_svecset(jl_datatype_type->types, 14, jl_bool_type); + jl_svecset(jl_datatype_type->types, 8, jl_uint8_type); jl_svecset(jl_typename_type->types, 1, jl_module_type); jl_svecset(jl_typename_type->types, 3, jl_voidpointer_type); jl_svecset(jl_typename_type->types, 4, jl_type_type); - jl_svecset(jl_typename_type->types, 7, jl_long_type); - jl_svecset(jl_typename_type->types, 8, jl_int32_type); - jl_svecset(jl_typename_type->types, 9, jl_bool_type); - jl_svecset(jl_typename_type->types, 10, jl_bool_type); - jl_svecset(jl_typename_type->types, 11, jl_bool_type); + jl_svecset(jl_typename_type->types, 9, jl_long_type); + jl_svecset(jl_typename_type->types, 10, jl_int32_type); + jl_svecset(jl_typename_type->types, 11, jl_uint8_type); jl_svecset(jl_methtable_type->types, 4, jl_long_type); jl_svecset(jl_methtable_type->types, 6, jl_module_type); jl_svecset(jl_methtable_type->types, 7, jl_array_any_type); diff --git a/src/julia.h b/src/julia.h index 1dbe2f746479a..da8d668306314 100644 --- a/src/julia.h +++ b/src/julia.h @@ -437,13 +437,14 @@ typedef struct { jl_value_t *wrapper; jl_svec_t *cache; // sorted array jl_svec_t *linearcache; // unsorted array - intptr_t hash; - int32_t n_uninitialized; - uint8_t abstract; - uint8_t mutabl; - uint8_t mayinlinealloc; struct _jl_methtable_t *mt; jl_array_t *partial; // incomplete instantiations of this type + intptr_t hash; + int32_t n_uninitialized; + // type properties + uint8_t abstract:1; + uint8_t mutabl:1; + uint8_t mayinlinealloc:1; } jl_typename_t; typedef struct { @@ -499,15 +500,15 @@ typedef struct _jl_datatype_t { jl_value_t *instance; // for singletons const jl_datatype_layout_t *layout; int32_t size; // TODO: move to _jl_datatype_layout_t - uint32_t hash; // memoized properties - uint8_t hasfreetypevars; // majority part of isconcrete computation - uint8_t isconcretetype; // whether this type can have instances - uint8_t isdispatchtuple; // aka isleaftupletype - uint8_t isbitstype; // relevant query for C-api and type-parameters - uint8_t zeroinit; // if one or more fields requires zero-initialization - uint8_t has_concrete_subtype; // If clear, no value will have this datatype - uint8_t cached_by_hash; // stored in hash-based set cache (instead of linear cache) + uint32_t hash; + uint8_t hasfreetypevars:1; // majority part of isconcrete computation + uint8_t isconcretetype:1; // whether this type can have instances + uint8_t isdispatchtuple:1; // aka isleaftupletype + uint8_t isbitstype:1; // relevant query for C-api and type-parameters + uint8_t zeroinit:1; // if one or more fields requires zero-initialization + uint8_t has_concrete_subtype:1; // If clear, no value will have this datatype + uint8_t cached_by_hash:1; // stored in hash-based set cache (instead of linear cache) } jl_datatype_t; typedef struct _jl_vararg_t { diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index 2ff223beff4b2..b6eb73bcd5faa 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -272,14 +272,14 @@ function summarize(io::IO, TT::Type, binding::Binding) if T isa DataType println(io, "```") print(io, - T.name.abstract ? "abstract type " : - T.name.mutable ? "mutable struct " : + Base.isabstracttype(T) ? "abstract type " : + Base.ismutabletype(T) ? "mutable struct " : Base.isstructtype(T) ? "struct " : "primitive type ") supert = supertype(T) println(io, T) println(io, "```") - if !T.name.abstract && T.name !== Tuple.name && !isempty(fieldnames(T)) + if !Base.isabstracttype(T) && T.name !== Tuple.name && !isempty(fieldnames(T)) println(io, "# Fields") println(io, "```") pad = maximum(length(string(f)) for f in fieldnames(T)) diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index f08ec1b8adfe4..0ed5b2df113ce 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -507,8 +507,8 @@ function serialize_typename(s::AbstractSerializer, t::Core.TypeName) serialize(s, primary.parameters) serialize(s, primary.types) serialize(s, isdefined(primary, :instance)) - serialize(s, t.abstract) - serialize(s, t.mutable) + serialize(s, t.flags & 0x1 == 0x1) # .abstract + serialize(s, t.flags & 0x2 == 0x2) # .mutable serialize(s, Int32(length(primary.types) - t.n_uninitialized)) if isdefined(t, :mt) && t.mt !== Symbol.name.mt serialize(s, t.mt.name) @@ -660,7 +660,7 @@ function serialize_any(s::AbstractSerializer, @nospecialize(x)) serialize_type(s, t) write(s.io, x) else - if t.name.mutable + if ismutable(x) serialize_cycle(s, x) && return serialize_type(s, t, true) else @@ -937,7 +937,7 @@ function handle_deserialize(s::AbstractSerializer, b::Int32) return deserialize_dict(s, t) end t = desertag(b)::DataType - if t.name.mutable && length(t.types) > 0 # manual specialization of fieldcount + if ismutabletype(t) && length(t.types) > 0 # manual specialization of fieldcount slot = s.counter; s.counter += 1 push!(s.pending_refs, slot) end @@ -1423,7 +1423,7 @@ function deserialize(s::AbstractSerializer, t::DataType) if nf == 0 && t.size > 0 # bits type return read(s.io, t) - elseif t.name.mutable + elseif ismutabletype(t) x = ccall(:jl_new_struct_uninit, Any, (Any,), t) deserialize_cycle(s, x) for i in 1:nf diff --git a/test/ccall.jl b/test/ccall.jl index ae29b40784eb6..02d005108459e 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -906,7 +906,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), global function $fname(s::$t) verbose && println("B: ", s) @test s == $v - if $(t).name.mutable + if ismutable(s) @test !(s === $a) end global c = s @@ -934,7 +934,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), end verbose && println("C: ",b) @test b == $v - if $(t).name.mutable + if ismutable($v) @test !(b === c) @test !(b === a) end @@ -943,7 +943,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), end verbose && println("C: ",b) @test b == $v - if $(t).name.mutable + if ismutable($v) @test !(b === c) @test !(b === a) end @@ -953,7 +953,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), verbose && println("C: ",b) @test b == $v @test b === c - if $(t).name.mutable + if ismutable($v) @test !(b === a) end let cf = @cfunction($fname, Any, (Ref{$t},)) @@ -962,7 +962,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), verbose && println("C: ",b) @test b == $v @test b === c - if $(t).name.mutable + if ismutable($v) @test !(b === a) end let cf = @cfunction($fname, Any, (Ref{Any},)) @@ -970,7 +970,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), end @test b == $v @test b === c - if $(t).name.mutable + if ismutable($v) @test !(b === a) end let cf = @cfunction($fname, Ref{AbstractString}, (Ref{Any},)) diff --git a/test/compiler/contextual.jl b/test/compiler/contextual.jl index bce782d73df87..6b22c47f522be 100644 --- a/test/compiler/contextual.jl +++ b/test/compiler/contextual.jl @@ -116,7 +116,7 @@ f() = 2 @test overdub(Ctx(), gcd, 10, 20) === gcd(10, 20) # Test that pure propagates for Cassette -Base.@pure isbitstype(T) = T.isbitstype +Base.@pure isbitstype(T) = Base.isbitstype(T) f31012(T) = Val(isbitstype(T)) @test @inferred(overdub(Ctx(), f31012, Int64)) == Val(true) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index be8a88b6dc21e..76fd93bb75763 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1551,9 +1551,9 @@ f_pure_add() = (1 + 1 == 2) ? true : "FAIL" @test @inferred f_pure_add() # inference of `T.mutable` -@test Core.Compiler.getfield_tfunc(Const(Int.name), Const(:mutable)) == Const(false) -@test Core.Compiler.getfield_tfunc(Const(Vector{Int}.name), Const(:mutable)) == Const(true) -@test Core.Compiler.getfield_tfunc(Core.TypeName, Const(:mutable)) == Bool +@test Core.Compiler.getfield_tfunc(Const(Int.name), Const(:flags)) == Const(0x4) +@test Core.Compiler.getfield_tfunc(Const(Vector{Int}.name), Const(:flags)) == Const(0x2) +@test Core.Compiler.getfield_tfunc(Core.TypeName, Const(:flags)) == UInt8 # getfield on abstract named tuples. issue #32698 import Core.Compiler.getfield_tfunc diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index ea0761320e700..1ffd012acb755 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -163,7 +163,7 @@ function fully_eliminated(f, args, retval) end # check that ismutabletype(type) can be fully eliminated -f_mutable_nothrow(s::String) = Val{typeof(s).name.mutable} +f_mutable_nothrow(s::String) = Val{typeof(s).name.flags} @test fully_eliminated(f_mutable_nothrow, (String,)) # check that ifelse can be fully eliminated diff --git a/test/core.jl b/test/core.jl index 725d83cb096a4..e0be3b109cb44 100644 --- a/test/core.jl +++ b/test/core.jl @@ -7530,7 +7530,7 @@ end struct S38224 i::Union{Int,Missing} end -@test S38224.zeroinit +@test S38224.flags & 0x10 == 0x10 # .zeroinit for _ in 1:5 let a = Vector{S38224}(undef, 1000000) @test all(x->ismissing(x.i), a)