diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 9b7434c0a5a45..fc2217110409b 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -1410,7 +1410,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.mutable + if isconcretetype(t) && !t.name.mutable args = Vector{Any}(undef, length(e.args)-1) ats = Vector{Any}(undef, length(e.args)-1) anyconst = false @@ -1447,7 +1447,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.mutable + if length(e.args) == 2 && isconcretetype(t) && !t.name.mutable 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 f27c71c2bcd6c..114b8c6033615 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.abstract)) || return nothing - @assert !typ.mutable + (isa(typ, DataType) && (!typ.name.abstract)) || return nothing + @assert !typ.name.mutable if length(def.args) < 1 + field if field > fieldcount(typ) return nothing @@ -625,7 +625,7 @@ function getfield_elim_pass!(ir::IRCode) if isa(typ, UnionAll) typ = unwrap_unionall(typ) end - if typ isa DataType && !typ.mutable + if typ isa DataType && !typ.name.mutable process_immutable_preserve(new_preserves, compact, def) old_preserves[pidx] = nothing continue @@ -662,7 +662,7 @@ function getfield_elim_pass!(ir::IRCode) def, typeconstraint = stmt.args[2], struct_typ - if struct_typ.mutable + if struct_typ.name.mutable isa(def, SSAValue) || continue let intermediaries = IdSet() callback = function(@nospecialize(pi), ssa::AnySSAValue) @@ -775,7 +775,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.mutable || continue + typ.name.mutable || 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 214087781a44f..25631d9594c98 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -28,15 +28,17 @@ const DATATYPE_NAME_FIELDINDEX = fieldindex(DataType, :name) const DATATYPE_PARAMETERS_FIELDINDEX = fieldindex(DataType, :parameters) const DATATYPE_TYPES_FIELDINDEX = fieldindex(DataType, :types) const DATATYPE_SUPER_FIELDINDEX = fieldindex(DataType, :super) -const DATATYPE_MUTABLE_FIELDINDEX = fieldindex(DataType, :mutable) const DATATYPE_INSTANCE_FIELDINDEX = fieldindex(DataType, :instance) -const DATATYPE_ABSTRACT_FIELDINDEX = fieldindex(DataType, :abstract) const DATATYPE_NAMES_FIELDINDEX = fieldindex(DataType, :names) +const DATATYPE_HASH_FIELDINDEX = fieldindex(DataType, :hash) 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) ########## # tfuncs # @@ -88,7 +90,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′′.abstract + isconcrete = !t′′.name.abstract if tr === Union{} # runtime unreachable (our inference Type{T} where S is # uninhabited with any runtime T that exists) @@ -271,7 +273,7 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym)) return Bool end a1 = unwrap_unionall(a1) - if isa(a1, DataType) && !a1.abstract + if isa(a1, DataType) && !a1.name.abstract if a1 === Module Symbol <: widenconst(sym) || return Bottom if isa(sym, Const) && isa(sym.val, Symbol) && isa(arg1, Const) && isdefined(arg1.val, sym.val) @@ -404,7 +406,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.abstract + if isa(x, DataType) && !x.name.abstract 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)) @@ -529,7 +531,7 @@ function typeof_tfunc(@nospecialize(t)) return typeof_tfunc(t.ub) elseif isa(t, UnionAll) u = unwrap_unionall(t) - if isa(u, DataType) && !u.abstract + if isa(u, DataType) && !u.name.abstract if u.name === Tuple.name uu = typeof_concrete_vararg(u) if uu !== nothing @@ -612,10 +614,9 @@ is_dt_const_field(fld::Int) = ( fld == DATATYPE_PARAMETERS_FIELDINDEX || fld == DATATYPE_TYPES_FIELDINDEX || fld == DATATYPE_SUPER_FIELDINDEX || - fld == DATATYPE_MUTABLE_FIELDINDEX || fld == DATATYPE_INSTANCE_FIELDINDEX || fld == DATATYPE_NAMES_FIELDINDEX || - fld == DATATYPE_ABSTRACT_FIELDINDEX + fld == DATATYPE_HASH_FIELDINDEX ) function const_datatype_getfield_tfunc(@nospecialize(sv), fld::Int) if fld == DATATYPE_INSTANCE_FIELDINDEX @@ -649,7 +650,7 @@ function fieldcount_noerror(@nospecialize t) end abstr = true else - abstr = t.abstract || (t.name === Tuple.name && isvatuple(t)) + abstr = t.name.abstract || (t.name === Tuple.name && isvatuple(t)) end if abstr return nothing @@ -717,7 +718,7 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), @nospecialize getfield_nothrow(rewrap(s.b, s00), name, inbounds) elseif isa(s, DataType) # Can't say anything about abstract types - s.abstract && return false + s.name.abstract && return false # If all fields are always initialized, and bounds check is disabled, we can assume # we don't throw if bounds_check_disabled && !isvatuple(s) && s.name !== NamedTuple.body.body.name && fieldcount(s) == s.ninitialized @@ -775,6 +776,9 @@ 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_NAMES_FIELDINDEX && isdefined(sv, fld))) return Const(getfield(sv, fld)) end @@ -799,7 +803,7 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) end s = widenconst(s) end - if isType(s) || !isa(s, DataType) || s.abstract + if isType(s) || !isa(s, DataType) || s.name.abstract return Any end s = s::DataType @@ -925,7 +929,7 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const) return exact ? (a || b) : (a && b) end u isa DataType || return false - u.abstract && return false + u.name.abstract && return false if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u) # TODO: better approximate inference return false @@ -986,7 +990,7 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name)) _fieldtype_tfunc(rewrap(u.b, s), exact, name)) end u isa DataType || return Union{Type, TypeVar} - if u.abstract + if u.name.abstract # 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 2eb2d6f542377..372989e114022 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.abstract && !cPi.abstract && + !tPi.name.abstract && !cPi.name.abstract && 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/deepcopy.jl b/base/deepcopy.jl index 36c9c399def54..75ec753a4cd84 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.mutable + if T.name.mutable if haskey(stackdict, x) return stackdict[x] end diff --git a/base/errorshow.jl b/base/errorshow.jl index ceca8b268e42b..d812dbb413d60 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.abstract + elseif isempty(methods(f)) && isa(f, DataType) && f.name.abstract 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 0813d0a0c9735..1739c89f46a0d 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).mutable || error("pointer_from_objref cannot be used on immutable objects") + typeof(x).name.mutable || 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 f1ecab42ef9b7..000319782ff02 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.abstract && throw_not_def_field() + t.name.abstract && 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).mutable) +ismutable(@nospecialize(x)) = (@_pure_meta; typeof(x).name.mutable) """ @@ -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.mutable + return isa(t, DataType) && t.name.mutable 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.abstract) + return hasfield || (t.size == 0 && !t.name.abstract) 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.abstract + return !hasfield && t.size != 0 && !t.name.abstract end """ @@ -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.abstract + return isa(t, DataType) && t.name.abstract end """ @@ -757,7 +757,7 @@ function fieldcount(@nospecialize t) end abstr = true else - abstr = t.abstract || (t.name === Tuple.name && isvatuple(t)) + abstr = t.name.abstract || (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 67cec0925ff58..725b2d05f95ee 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.mutable + elseif isconcretetype(T) && T.name.mutable 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 cf5f4e6b74d6f..69d9a31061724 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.mutable + elseif isconcretetype(T) && T.name.mutable 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 595af52a5fc1c..ca92c349db809 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2616,7 +2616,7 @@ function dump(io::IOContext, x::DataType, n::Int, indent) if x !== Any print(io, " <: ", supertype(x)) end - if n > 0 && !(x <: Tuple) && !x.abstract + if n > 0 && !(x <: Tuple) && !x.name.abstract tvar_io::IOContext = io for tparam in x.parameters # approximately recapture the list of tvar parameterization diff --git a/src/abi_aarch64.cpp b/src/abi_aarch64.cpp index 4d55d3d69a8de..3a0a5c25dc859 100644 --- a/src/abi_aarch64.cpp +++ b/src/abi_aarch64.cpp @@ -16,7 +16,7 @@ struct ABI_AArch64Layout : AbiLayout { Type *get_llvm_vectype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - // `!dt->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields > 0` + // `!dt->name->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields > 0` if (dt->layout == NULL || jl_is_layout_opaque(dt->layout)) return nullptr; size_t nfields = dt->layout->nfields; @@ -62,7 +62,7 @@ Type *get_llvm_vectype(jl_datatype_t *dt) const Type *get_llvm_fptype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - // `!dt->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields == 0` + // `!dt->name->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields == 0` Type *lltype; // Check size first since it's cheaper. switch (jl_datatype_size(dt)) { @@ -88,7 +88,7 @@ Type *get_llvm_fptype(jl_datatype_t *dt) const Type *get_llvm_fp_or_vectype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - if (dt->mutabl || dt->layout->npointers || dt->layout->haspadding) + if (dt->name->mutabl || dt->layout->npointers || dt->layout->haspadding) return nullptr; return dt->layout->nfields ? get_llvm_vectype(dt) : get_llvm_fptype(dt); } diff --git a/src/abi_arm.cpp b/src/abi_arm.cpp index 1a5d3d0651368..b0ae29a623abb 100644 --- a/src/abi_arm.cpp +++ b/src/abi_arm.cpp @@ -33,7 +33,7 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab) override Type *get_llvm_fptype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - if (dt->mutabl || jl_datatype_nfields(dt) != 0) + if (dt->name->mutabl || jl_datatype_nfields(dt) != 0) return NULL; Type *lltype; // Check size first since it's cheaper. diff --git a/src/builtins.c b/src/builtins.c index c6abe4b8e602d..75e3f87151672 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -183,7 +183,7 @@ static int egal_types(jl_value_t *a, jl_value_t *b, jl_typeenv_t *env, int tvar_ } if (dt == jl_symbol_type) return 0; - assert(!dt->mutabl); + assert(!dt->name->mutabl); return jl_egal__bits(a, b, dt); } @@ -324,7 +324,7 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN } if (tv == jl_symbol_type) return ((jl_sym_t*)v)->hash; - assert(!tv->mutabl); + assert(!tv->name->mutabl); return immut_id_(tv, v, tv->hash); } @@ -358,7 +358,7 @@ static uintptr_t immut_id_(jl_datatype_t *dt, jl_value_t *v, uintptr_t h) JL_NOT uint8_t sel = ((uint8_t*)vo)[jl_field_size(dt, f) - 1]; fieldtype = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)fieldtype, sel); } - assert(jl_is_datatype(fieldtype) && !fieldtype->abstract && !fieldtype->mutabl); + assert(jl_is_datatype(fieldtype) && !fieldtype->name->abstract && !fieldtype->name->mutabl); int32_t first_ptr = fieldtype->layout->first_ptr; if (first_ptr >= 0 && ((jl_value_t**)vo)[first_ptr] == NULL) { // If the field is a inline immutable that can be can be undef @@ -391,7 +391,7 @@ static uintptr_t NOINLINE jl_object_id__cold(jl_datatype_t *dt, jl_value_t *v) J return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677); #endif } - if (dt->mutabl) + if (dt->name->mutabl) return inthash((uintptr_t)v); return immut_id_(dt, v, dt->hash); } @@ -451,7 +451,7 @@ JL_CALLABLE(jl_f_sizeof) if (jl_is_datatype(x)) { jl_datatype_t *dx = (jl_datatype_t*)x; if (dx->layout == NULL) { - if (dx->abstract) + if (dx->name->abstract) jl_errorf("Abstract type %s does not have a definite size.", jl_symbol_name(dx->name->name)); else jl_errorf("Argument is an incomplete %s type and does not have a definite size.", jl_symbol_name(dx->name->name)); @@ -473,7 +473,7 @@ JL_CALLABLE(jl_f_sizeof) return jl_box_long((1+jl_svec_len(x))*sizeof(void*)); jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(x); assert(jl_is_datatype(dt)); - assert(!dt->abstract); + assert(!dt->name->abstract); return jl_box_long(jl_datatype_size(dt)); } @@ -840,7 +840,7 @@ JL_CALLABLE(jl_f_setfield) assert(jl_is_datatype(st)); if (st == jl_module_type) jl_error("cannot assign variables in other modules"); - if (!st->mutabl) + if (!st->name->mutabl) jl_errorf("setfield! immutable struct of type %s cannot be changed", jl_symbol_name(st->name->name)); size_t idx; if (jl_is_long(args[1])) { @@ -1337,6 +1337,32 @@ static int equiv_field_types(jl_value_t *old, jl_value_t *ft) return 1; } +static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layout) JL_NOTSAFEPOINT +{ + if (jl_is_uniontype(p)) + return references_name(((jl_uniontype_t*)p)->a, name, affects_layout) || + references_name(((jl_uniontype_t*)p)->b, name, affects_layout); + if (jl_is_unionall(p)) + return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name, 0) || + references_name(((jl_unionall_t*)p)->body, name, affects_layout); + if (jl_is_typevar(p)) + return references_name(((jl_tvar_t*)p)->ub, name, 0) || + references_name(((jl_tvar_t*)p)->lb, name, 0); + if (jl_is_datatype(p)) { + jl_datatype_t *dp = (jl_datatype_t*)p; + if (affects_layout && dp->name == name) + return 1; + affects_layout = dp->types == NULL || jl_svec_len(dp->types) != 0; + size_t i, l = jl_nparams(p); + for (i = 0; i < l; i++) { + if (references_name(jl_tparam(p, i), name, affects_layout)) + return 1; + } + } + return 0; +} + + JL_CALLABLE(jl_f__typebody) { JL_NARGS(_typebody!, 1, 2); @@ -1361,6 +1387,14 @@ JL_CALLABLE(jl_f__typebody) else { dt->types = (jl_svec_t*)ft; jl_gc_wb(dt, ft); + size_t i, nf = jl_svec_len(ft); + for (i = 0; i < nf; i++) { + jl_value_t *fld = jl_svecref(ft, i); + if (references_name(fld, dt->name, 1)) { + dt->name->references_self = 1; + break; + } + } } } @@ -1386,8 +1420,6 @@ static int equiv_type(jl_value_t *ta, jl_value_t *tb) jl_datatype_t *dtb = (jl_datatype_t*)jl_unwrap_unionall(tb); if (!(jl_typeof(dta) == jl_typeof(dtb) && dta->name->name == dtb->name->name && - dta->abstract == dtb->abstract && - dta->mutabl == dtb->mutabl && (jl_svec_len(jl_field_names(dta)) != 0 || dta->size == dtb->size) && dta->ninitialized == dtb->ninitialized && jl_egal((jl_value_t*)jl_field_names(dta), (jl_value_t*)jl_field_names(dtb)) && diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 652b0a8791aae..c3f14299a133e 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -982,10 +982,13 @@ static Value *emit_sizeof(jl_codectx_t &ctx, const jl_cgval_t &p) static Value *emit_datatype_mutabl(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, mutabl)); + Value *Ptr = emit_bitcast(ctx, decay_derived(ctx, dt), T_ppint8); + 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 *mutabl = tbaa_decorate(tbaa_const, - ctx.builder.CreateAlignedLoad(T_int8, ctx.builder.CreateInBoundsGEP(T_int8, Ptr, Idx), Align(1))); + ctx.builder.CreateAlignedLoad(T_int8, ctx.builder.CreateInBoundsGEP(T_int8, Nam, Idx2), Align(1))); return ctx.builder.CreateTrunc(mutabl, T_int1); } @@ -1111,7 +1114,7 @@ static bool _can_optimize_isa(jl_value_t *type, int &counter) if (jl_is_concrete_type(type)) return true; jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(type); - if (jl_is_datatype(dt) && !dt->abstract && jl_subtype(dt->name->wrapper, type)) + if (jl_is_datatype(dt) && !dt->name->abstract && jl_subtype(dt->name->wrapper, type)) return true; return false; } @@ -1227,7 +1230,7 @@ static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, track_pjlvalue(ctx, literal_pointer_val(ctx, intersected_type))), false); } jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(intersected_type); - if (jl_is_datatype(dt) && !dt->abstract && jl_subtype(dt->name->wrapper, type)) { + if (jl_is_datatype(dt) && !dt->name->abstract && jl_subtype(dt->name->wrapper, type)) { // intersection is a supertype of all instances of its constructor, // so the isa test reduces to a comparison of the typename by pointer return std::make_pair( @@ -1713,7 +1716,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, assert(jl_is_concrete_type(jft)); idx = idx0(); Value *ptr = maybe_decay_tracked(ctx, data_pointer(ctx, strct)); - if (!stt->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type || + if (!stt->name->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type || ((jl_datatype_t*)jft)->layout->npointers))) { // just compute the pointer and let user load it when necessary Type *fty = julia_type_to_llvm(ctx, jft); @@ -1806,7 +1809,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st // ConstantAsMetadata::get(ConstantInt::get(T_int8, 0)), // ConstantAsMetadata::get(ConstantInt::get(T_int8, union_max)) })); Value *tindex = ctx.builder.CreateNUWAdd(ConstantInt::get(T_int8, 1), tindex0); - if (jt->mutabl) { + if (jt->name->mutabl) { // move value to an immutable stack slot (excluding tindex) Type *ET = IntegerType::get(jl_LLVMContext, 8 * al); AllocaInst *lv = emit_static_alloca(ctx, ET); @@ -1817,7 +1820,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st return mark_julia_slot(addr, jfty, tindex, tbaa); } assert(jl_is_concrete_type(jfty)); - if (!jt->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type || + if (!jt->name->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type || ((jl_datatype_t*)jfty)->layout->npointers))) { // just compute the pointer and let user load it when necessary return mark_julia_slot(addr, jfty, NULL, tbaa); @@ -2432,7 +2435,7 @@ static Value *_boxed_special(jl_codectx_t &ctx, const jl_cgval_t &vinfo, Type *t v = ctx.builder.CreateExtractValue(v, makeArrayRef(&zero, 1)); box = call_with_attrs(ctx, box_ssavalue_func, v); } - else if (!jb->abstract && jl_datatype_nbits(jb) == 0) { + else if (!jb->name->abstract && jl_datatype_nbits(jb) == 0) { // singleton assert(jb->instance != NULL); return track_pjlvalue(ctx, literal_pointer_val(ctx, jb->instance)); @@ -2836,7 +2839,7 @@ static void emit_setfield(jl_codectx_t &ctx, jl_datatype_t *sty, const jl_cgval_t &strct, size_t idx0, const jl_cgval_t &rhs, bool checked, bool wb) { - if (sty->mutabl || !checked) { + if (sty->name->mutabl || !checked) { assert(strct.ispointer()); size_t byte_offset = jl_field_offset(sty, idx0); Value *addr = data_pointer(ctx, strct); @@ -2892,7 +2895,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg assert(jl_is_concrete_type(ty)); jl_datatype_t *sty = (jl_datatype_t*)ty; size_t nf = jl_datatype_nfields(sty); - if (nf > 0 || sty->mutabl) { + if (nf > 0 || sty->name->mutabl) { if (deserves_stack(ty)) { Type *lt = julia_type_to_llvm(ctx, ty); unsigned na = nargs < nf ? nargs : nf; diff --git a/src/codegen.cpp b/src/codegen.cpp index bc60798220d52..5e489ee88543a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1362,7 +1362,7 @@ static inline jl_cgval_t update_julia_type(jl_codectx_t &ctx, const jl_cgval_t & if (jl_is_concrete_type(utyp)) alwaysboxed = !jl_is_pointerfree(utyp); else - alwaysboxed = !((jl_datatype_t*)utyp)->abstract && ((jl_datatype_t*)utyp)->mutabl; + alwaysboxed = !((jl_datatype_t*)utyp)->name->abstract && ((jl_datatype_t*)utyp)->name->mutabl; if (alwaysboxed) { // discovered that this union-split type must actually be isboxed if (v.Vboxed) { @@ -3149,7 +3149,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, else if (f == jl_builtin_sizeof && nargs == 1) { const jl_cgval_t &obj = argv[1]; jl_datatype_t *sty = (jl_datatype_t*)jl_unwrap_unionall(obj.typ); - assert(jl_string_type->mutabl); + assert(jl_string_type->name->mutabl); if (sty == jl_string_type || sty == jl_simplevector_type) { if (obj.constant) { size_t sz; diff --git a/src/datatype.c b/src/datatype.c index 86ad3170a701e..8c9bae6f09f2f 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -60,7 +60,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo return mt; } -JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *module) +JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *module, int abstract, int mutabl) { jl_ptls_t ptls = jl_get_ptls_states(); jl_typename_t *tn = @@ -73,6 +73,9 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu tn->linearcache = jl_emptysvec; tn->names = NULL; tn->hash = bitmix(bitmix(module ? module->build_id : 0, name->hash), 0xa1ada1da); + tn->abstract = abstract; + tn->mutabl = mutabl; + tn->references_self = 0; tn->mt = NULL; tn->partial = NULL; return tn; @@ -220,8 +223,8 @@ unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t) STATIC_INLINE int jl_is_datatype_make_singleton(jl_datatype_t *d) { - return (!d->abstract && jl_datatype_size(d) == 0 && d != jl_symbol_type && d->name != jl_array_typename && - d->isconcretetype && !d->mutabl); + return (!d->name->abstract && jl_datatype_size(d) == 0 && d != jl_symbol_type && d->name != jl_array_typename && + d->isconcretetype && !d->name->mutabl); } STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) @@ -314,31 +317,6 @@ int jl_pointer_egal(jl_value_t *t) return 0; } -static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layout) JL_NOTSAFEPOINT -{ - if (jl_is_uniontype(p)) - return references_name(((jl_uniontype_t*)p)->a, name, affects_layout) || - references_name(((jl_uniontype_t*)p)->b, name, affects_layout); - if (jl_is_unionall(p)) - return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name, 0) || - references_name(((jl_unionall_t*)p)->body, name, affects_layout); - if (jl_is_typevar(p)) - return references_name(((jl_tvar_t*)p)->ub, name, 0) || - references_name(((jl_tvar_t*)p)->lb, name, 0); - if (jl_is_datatype(p)) { - jl_datatype_t *dp = (jl_datatype_t*)p; - if (affects_layout && dp->name == name) - return 1; - affects_layout = dp->types == NULL || jl_svec_len(dp->types) != 0; - size_t i, l = jl_nparams(p); - for (i = 0; i < l; i++) { - if (references_name(jl_tparam(p, i), name, affects_layout)) - return 1; - } - } - return 0; -} - static void throw_ovf(int should_malloc, void *desc, jl_datatype_t* st, int offset) { if (should_malloc) @@ -359,8 +337,7 @@ void jl_compute_field_offsets(jl_datatype_t *st) if (w->types == NULL) // we got called too early--we'll be back return; size_t i, nfields = jl_svec_len(st->types); - int isinlinealloc = st->isconcretetype && !st->mutabl; - int isbitstype = isinlinealloc; + int isinlinealloc = st->isconcretetype && !st->name->mutabl && !st->name->references_self; assert(st->ninitialized <= nfields); if (st == w && st->layout) { // this check allows us to force re-computation of the layout for some types during init @@ -419,22 +396,10 @@ void jl_compute_field_offsets(jl_datatype_t *st) } } - // compute whether this type may ever be inlined - // based solely on whether its definition is self-referential - if (isinlinealloc) { - size_t i, nf = jl_svec_len(w->types); - for (i = 0; i < nf; i++) { - jl_value_t *fld = jl_svecref(w->types, i); - if (references_name(fld, w->name, 1)) { - isinlinealloc = 0; - isbitstype = 0; - break; - } - } - for (i = 0; isbitstype && i < nfields; i++) { - jl_value_t *fld = jl_field_type(st, i); - isbitstype = jl_isbits(fld); - } + int isbitstype = isinlinealloc; + for (i = 0; isbitstype && i < nfields; i++) { + jl_value_t *fld = jl_field_type(st, i); + isbitstype = jl_isbits(fld); } // if we didn't reuse the layout above, compute it now @@ -592,8 +557,6 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( jl_gc_wb(t, t->parameters); t->types = ftypes; if (ftypes != NULL) jl_gc_wb(t, t->types); - t->abstract = abstract; - t->mutabl = mutabl; t->ninitialized = ninitialized; t->size = 0; @@ -601,9 +564,11 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( if (jl_is_typename(name)) { // This code-path is used by the Serialization module to by-pass normal expectations tn = (jl_typename_t*)name; + tn->abstract = abstract; + tn->mutabl = mutabl; } else { - tn = jl_new_typename_in((jl_sym_t*)name, module); + tn = jl_new_typename_in((jl_sym_t*)name, module, abstract, mutabl); if (super == jl_function_type || super == jl_builtin_type || is_anonfn_typename(jl_symbol_name(name))) { // Callable objects (including compiler-generated closures) get independent method tables // as an optimization diff --git a/src/dump.c b/src/dump.c index 2a6c8318c2095..fc34417123025 100644 --- a/src/dump.c +++ b/src/dump.c @@ -270,7 +270,7 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt) JL_ write_int32(s->s, dt->size); int has_instance = (dt->instance != NULL); int has_layout = (dt->layout != NULL); - write_uint8(s->s, dt->abstract | (dt->mutabl << 1) | (has_layout << 2) | (has_instance << 3)); + write_uint8(s->s, dt->name->abstract | (has_layout << 1) | (has_instance << 2)); write_uint8(s->s, dt->hasfreetypevars | (dt->isconcretetype << 1) | (dt->isdispatchtuple << 2) @@ -279,7 +279,7 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt) JL_ | (dt->isinlinealloc << 5) | (dt->has_concrete_subtype << 6) | (dt->cached_by_hash << 7)); - if (!dt->abstract) { + if (!dt->name->abstract) { write_uint16(s->s, dt->ninitialized); } write_int32(s->s, dt->hash); @@ -815,6 +815,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li jl_serialize_value(s, tn->wrapper); jl_serialize_value(s, tn->mt); ios_write(s->s, (char*)&tn->hash, sizeof(tn->hash)); + write_uint8(s->s, tn->abstract | (tn->mutabl << 1) | (tn->references_self << 2)); } return; } @@ -833,7 +834,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li ios_write(s->s, last, prevptr - last); jl_value_t *e = *(jl_value_t**)prevptr; JL_GC_PROMISE_ROOTED(e); - if (t->mutabl && e && jl_field_isptr(t, i - 1) && jl_is_cpointer(e) && + if (t->name->mutabl && e && jl_field_isptr(t, i - 1) && jl_is_cpointer(e) && jl_unbox_voidpointer(e) != (void*)-1 && jl_unbox_voidpointer(e) != NULL) // reset Ptr fields to C_NULL (but keep MAP_FAILED / INVALID_HANDLE) jl_serialize_cnull(s, jl_typeof(e)); @@ -849,7 +850,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } if (i == nf) break; - if (t->mutabl && jl_is_cpointer_type(jl_field_type(t, i)) && *(void**)ptr != (void*)-1) { + if (t->name->mutabl && jl_is_cpointer_type(jl_field_type(t, i)) && *(void**)ptr != (void*)-1) { if (ptr > last) ios_write(s->s, last, ptr - last); char *n = NULL; @@ -1263,10 +1264,9 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v uint8_t flags = read_uint8(s->s); uint8_t memflags = read_uint8(s->s); dt->size = size; - dt->abstract = flags & 1; - dt->mutabl = (flags >> 1) & 1; - int has_layout = (flags >> 2) & 1; - int has_instance = (flags >> 3) & 1; + int abstract = flags & 1; + int has_layout = (flags >> 1) & 1; + int has_instance = (flags >> 2) & 1; dt->hasfreetypevars = memflags & 1; dt->isconcretetype = (memflags >> 1) & 1; dt->isdispatchtuple = (memflags >> 2) & 1; @@ -1275,10 +1275,10 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v dt->isinlinealloc = (memflags >> 5) & 1; dt->has_concrete_subtype = (memflags >> 6) & 1; dt->cached_by_hash = (memflags >> 7) & 1; - if (!dt->abstract) - dt->ninitialized = read_uint16(s->s); - else + if (abstract) dt->ninitialized = 0; + else + dt->ninitialized = read_uint16(s->s); dt->hash = read_int32(s->s); if (has_layout) { @@ -1728,6 +1728,10 @@ static jl_value_t *jl_deserialize_value_any(jl_serializer_state *s, uint8_t tag, tn->mt = (jl_methtable_t*)jl_deserialize_value(s, (jl_value_t**)&tn->mt); jl_gc_wb(tn, tn->mt); ios_read(s->s, (char*)&tn->hash, sizeof(tn->hash)); + int8_t flags = read_int8(s->s); + tn->abstract = flags & 1; + tn->mutabl = (flags>>1) & 1; + tn->references_self = (flags>>2) & 1; } else { jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(jl_get_global(m, sym)); diff --git a/src/jltypes.c b/src/jltypes.c index 2ba69caf1991e..f759173f2051c 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -62,9 +62,8 @@ static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT if (expect == 0 || env == NULL) return expect; size_t i; - for (i=0; i < jl_nparams(v); i++) { - if (has_free_typevars(jl_tparam(v,i), env)) { - assert(expect); + for (i = 0; i < jl_nparams(v); i++) { + if (has_free_typevars(jl_tparam(v, i), env)) { return 1; } } @@ -1082,7 +1081,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) { int istuple = (dt->name == jl_tuple_typename); dt->hasfreetypevars = 0; - dt->isconcretetype = !dt->abstract; + dt->isconcretetype = !dt->name->abstract; dt->isdispatchtuple = istuple; size_t i, l = jl_nparams(dt); for (i = 0; i < l; i++) { @@ -1398,8 +1397,6 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->types = jl_emptysvec; } } - ndt->mutabl = dt->mutabl; - ndt->abstract = dt->abstract; ndt->size = 0; jl_precompute_memoized_dt(ndt, cacheable); if (istuple) @@ -1437,7 +1434,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value } else if (!isnamedtuple && !istuple) { assert(ftypes != jl_emptysvec || jl_field_names(ndt) == jl_emptysvec); - assert(ftypes == jl_emptysvec || !ndt->abstract); + assert(ftypes == jl_emptysvec || !ndt->name->abstract); if (ftypes == jl_emptysvec) { ndt->types = ftypes; } @@ -1453,7 +1450,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value // now publish the finished result if (cacheable) { - if (!jl_is_primitivetype(dt) && ndt->types != NULL && !ndt->abstract) { + if (!jl_is_primitivetype(dt) && ndt->types != NULL && !ndt->name->abstract) { jl_compute_field_offsets(ndt); } jl_cache_type_(ndt); @@ -1884,11 +1881,12 @@ void jl_init_types(void) JL_GC_DISABLED jl_type_typename->mt = jl_type_type_mt; // initialize them. lots of cycles. - jl_datatype_type->name = jl_new_typename_in(jl_symbol("DataType"), core); + // 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->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(20, + jl_datatype_type->name->names = jl_perm_symsvec(18, "name", "super", "parameters", @@ -1899,8 +1897,6 @@ void jl_init_types(void) JL_GC_DISABLED "size", "ninitialized", "hash", - "abstract", - "mutable", "hasfreetypevars", "isconcretetype", "isdispatchtuple", @@ -1909,7 +1905,7 @@ void jl_init_types(void) JL_GC_DISABLED "isinlinealloc", "has_concrete_subtype", "cached_by_hash"); - jl_datatype_type->types = jl_svec(20, + jl_datatype_type->types = jl_svec(18, jl_typename_type, jl_datatype_type, jl_simplevector_type, @@ -1917,32 +1913,28 @@ void jl_init_types(void) JL_GC_DISABLED 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_any_type, jl_any_type, - jl_any_type, jl_any_type); - jl_datatype_type->abstract = 0; - // NOTE: types are not actually mutable, but we want to ensure they are heap-allocated with stable addresses - jl_datatype_type->mutabl = 1; + jl_any_type, jl_any_type, jl_any_type, jl_any_type); jl_datatype_type->ninitialized = 3; jl_precompute_memoized_dt(jl_datatype_type, 1); - jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core); + jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core, 0, 1); 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(9, "name", "module", + jl_typename_type->name->names = jl_perm_symsvec(12, "name", "module", "names", "wrapper", "cache", "linearcache", - "hash", "mt", "partial"); - jl_typename_type->types = jl_svec(9, jl_symbol_type, jl_any_type, jl_simplevector_type, + "hash", "abstract", "mutable", "references_self", + "mt", "partial"); + jl_typename_type->types = jl_svec(12, jl_symbol_type, jl_any_type, jl_simplevector_type, jl_type_type, jl_simplevector_type, jl_simplevector_type, - jl_any_type, jl_methtable_type, jl_any_type); - jl_typename_type->abstract = 0; - jl_typename_type->mutabl = 1; + jl_any_type, jl_any_type, jl_any_type, jl_any_type, + jl_methtable_type, jl_any_type); jl_typename_type->ninitialized = 2; jl_precompute_memoized_dt(jl_typename_type, 1); - jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core); + jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core, 0, 1); 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; @@ -1956,12 +1948,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_any_type/*module*/, jl_any_type/*any vector*/, jl_any_type/*long*/, jl_any_type/*int32*/, jl_any_type/*uint8*/, jl_any_type/*uint8*/); - jl_methtable_type->abstract = 0; - jl_methtable_type->mutabl = 1; jl_methtable_type->ninitialized = 5; jl_precompute_memoized_dt(jl_methtable_type, 1); - jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core); + jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core, 0, 1); jl_symbol_type->name->wrapper = (jl_value_t*)jl_symbol_type; jl_symbol_type->name->mt = jl_nonfunction_mt; jl_symbol_type->super = jl_any_type; @@ -1969,20 +1959,16 @@ void jl_init_types(void) JL_GC_DISABLED jl_symbol_type->name->names = jl_emptysvec; jl_symbol_type->types = jl_emptysvec; jl_symbol_type->size = 0; - jl_symbol_type->abstract = 0; - jl_symbol_type->mutabl = 1; jl_symbol_type->ninitialized = 0; jl_precompute_memoized_dt(jl_symbol_type, 1); - jl_simplevector_type->name = jl_new_typename_in(jl_symbol("SimpleVector"), core); + jl_simplevector_type->name = jl_new_typename_in(jl_symbol("SimpleVector"), core, 0, 1); jl_simplevector_type->name->wrapper = (jl_value_t*)jl_simplevector_type; jl_simplevector_type->name->mt = jl_nonfunction_mt; jl_simplevector_type->super = jl_any_type; jl_simplevector_type->parameters = jl_emptysvec; jl_simplevector_type->name->names = jl_emptysvec; jl_simplevector_type->types = jl_emptysvec; - jl_simplevector_type->abstract = 0; - jl_simplevector_type->mutabl = 1; jl_simplevector_type->ninitialized = 0; jl_precompute_memoized_dt(jl_simplevector_type, 1); @@ -2518,11 +2504,12 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_datatype_type->types, 15, jl_bool_type); jl_svecset(jl_datatype_type->types, 16, jl_bool_type); jl_svecset(jl_datatype_type->types, 17, jl_bool_type); - jl_svecset(jl_datatype_type->types, 18, jl_bool_type); - jl_svecset(jl_datatype_type->types, 19, jl_bool_type); jl_svecset(jl_typename_type->types, 1, jl_module_type); - jl_svecset(jl_typename_type->types, 6, jl_long_type); jl_svecset(jl_typename_type->types, 3, jl_type_type); + jl_svecset(jl_typename_type->types, 6, jl_long_type); + jl_svecset(jl_typename_type->types, 7, jl_bool_type); + jl_svecset(jl_typename_type->types, 8, jl_bool_type); + jl_svecset(jl_typename_type->types, 9, jl_bool_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 8ec461e77126b..cd3780b9eb453 100644 --- a/src/julia.h +++ b/src/julia.h @@ -429,6 +429,9 @@ typedef struct { jl_svec_t *cache; // sorted array jl_svec_t *linearcache; // unsorted array intptr_t hash; + uint8_t abstract; + uint8_t mutabl; + uint8_t references_self; struct _jl_methtable_t *mt; jl_array_t *partial; // incomplete instantiations of this type } jl_typename_t; @@ -489,8 +492,6 @@ typedef struct _jl_datatype_t { int32_t size; // TODO: move to _jl_datatype_layout_t int32_t ninitialized; uint32_t hash; - uint8_t abstract; - uint8_t mutabl; // memoized properties uint8_t hasfreetypevars; // majority part of isconcrete computation uint8_t isconcretetype; // whether this type can have instances @@ -1136,10 +1137,10 @@ static inline int jl_is_layout_opaque(const jl_datatype_layout_t *l) JL_NOTSAFEP #define jl_is_svec(v) jl_typeis(v,jl_simplevector_type) #define jl_is_simplevector(v) jl_is_svec(v) #define jl_is_datatype(v) jl_typeis(v,jl_datatype_type) -#define jl_is_mutable(t) (((jl_datatype_t*)t)->mutabl) -#define jl_is_mutable_datatype(t) (jl_is_datatype(t) && (((jl_datatype_t*)t)->mutabl)) -#define jl_is_immutable(t) (!((jl_datatype_t*)t)->mutabl) -#define jl_is_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->mutabl)) +#define jl_is_mutable(t) (((jl_datatype_t*)t)->name->mutabl) +#define jl_is_mutable_datatype(t) (jl_is_datatype(t) && (((jl_datatype_t*)t)->name->mutabl)) +#define jl_is_immutable(t) (!((jl_datatype_t*)t)->name->mutabl) +#define jl_is_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->name->mutabl)) #define jl_is_uniontype(v) jl_typeis(v,jl_uniontype_type) #define jl_is_typevar(v) jl_typeis(v,jl_tvar_type) #define jl_is_unionall(v) jl_typeis(v,jl_unionall_type) @@ -1208,7 +1209,7 @@ STATIC_INLINE int jl_is_primitivetype(void *v) JL_NOTSAFEPOINT STATIC_INLINE int jl_is_structtype(void *v) JL_NOTSAFEPOINT { return (jl_is_datatype(v) && - !((jl_datatype_t*)(v))->abstract && + !((jl_datatype_t*)(v))->name->abstract && !jl_is_primitivetype(v)); } @@ -1224,7 +1225,7 @@ STATIC_INLINE int jl_is_datatype_singleton(jl_datatype_t *d) JL_NOTSAFEPOINT STATIC_INLINE int jl_is_abstracttype(void *v) JL_NOTSAFEPOINT { - return (jl_is_datatype(v) && ((jl_datatype_t*)(v))->abstract); + return (jl_is_datatype(v) && ((jl_datatype_t*)(v))->name->abstract); } STATIC_INLINE int jl_is_array_type(void *t) JL_NOTSAFEPOINT @@ -1315,7 +1316,7 @@ STATIC_INLINE int jl_egal_(jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAY jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(a); if (dt != (jl_datatype_t*)jl_typeof(b)) return 0; - if (dt->mutabl) { + if (dt->name->mutabl) { if (dt == jl_simplevector_type || dt == jl_string_type || dt == jl_datatype_type) return jl_egal__special(a, b, dt); return 0; @@ -1355,7 +1356,7 @@ STATIC_INLINE int jl_is_concrete_type(jl_value_t *v) JL_NOTSAFEPOINT JL_DLLEXPORT int jl_isa_compileable_sig(jl_tupletype_t *type, jl_method_t *definition); // type constructors -JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule); +JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule, int abstract, int mutabl); JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub); JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p); JL_DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n); diff --git a/src/rtutils.c b/src/rtutils.c index 99fce51128345..98dc68dfa02f3 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -354,7 +354,7 @@ JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a) JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t idx0, jl_value_t *rhs) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); - if (!st->mutabl) + if (!st->name->mutabl) jl_errorf("setfield! immutable struct of type %s cannot be changed", jl_symbol_name(st->name->name)); if (idx0 >= jl_datatype_nfields(st)) jl_bounds_error_int(v, idx0 + 1); diff --git a/src/staticdata.c b/src/staticdata.c index 44b6f33d05e7a..1fc1797f35fdd 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -901,7 +901,7 @@ static void jl_write_values(jl_serializer_state *s) write_padding(s->s, offset - tot); tot = offset; size_t fsz = jl_field_size(t, i); - if (t->mutabl && jl_is_cpointer_type(jl_field_type(t, i))) { + if (t->name->mutabl && jl_is_cpointer_type(jl_field_type(t, i))) { // reset Ptr fields to C_NULL assert(!jl_field_isptr(t, i)); write_pointer(s->s); diff --git a/src/subtype.c b/src/subtype.c index 90f5438cfd1b6..0d87532e73c39 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -646,7 +646,7 @@ static int is_leaf_bound(jl_value_t *v) JL_NOTSAFEPOINT if (v == jl_bottom_type) return 1; if (jl_is_datatype(v)) { - if (((jl_datatype_t*)v)->abstract) { + if (((jl_datatype_t*)v)->name->abstract) { if (jl_is_type_type(v)) return 1;//!jl_has_free_typevars(jl_tparam0(v)); return 0; diff --git a/src/typemap.c b/src/typemap.c index 8714e4699d855..b546aadee77ac 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -65,7 +65,7 @@ static int jl_type_extract_name_precise(jl_value_t *t1, int invariant) } else if (jl_is_datatype(t1)) { jl_datatype_t *dt = (jl_datatype_t*)t1; - if ((invariant || !dt->abstract) && !jl_is_kind(t1)) + if ((invariant || !dt->name->abstract) && !jl_is_kind(t1)) return 1; return 0; } diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index db87e9e5cba04..459cad76e7d60 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -303,7 +303,7 @@ end function dumptype(io::IO, @nospecialize(x), n::Int, indent) print(io, x) n == 0 && return # too deeply nested - isa(x, DataType) && x.abstract && dumpsubtypes(io, x, Main, n, indent) + isa(x, DataType) && x.name.abstract && dumpsubtypes(io, x, Main, n, indent) nothing end diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index cfb554f6cae32..2ff223beff4b2 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.abstract ? "abstract type " : - T.mutable ? "mutable struct " : + T.name.abstract ? "abstract type " : + T.name.mutable ? "mutable struct " : Base.isstructtype(T) ? "struct " : "primitive type ") supert = supertype(T) println(io, T) println(io, "```") - if !T.abstract && T.name !== Tuple.name && !isempty(fieldnames(T)) + if !T.name.abstract && 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 f644c73762c2f..9f53d865ad7fb 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, primary.abstract) - serialize(s, primary.mutable) + serialize(s, t.abstract) + serialize(s, t.mutable) serialize(s, primary.ninitialized) 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.mutable + if t.name.mutable 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.mutable && length(t.types) > 0 # manual specialization of fieldcount + if t.name.mutable && length(t.types) > 0 # manual specialization of fieldcount slot = s.counter; s.counter += 1 push!(s.pending_refs, slot) end @@ -1253,8 +1253,8 @@ function deserialize_typename(s::AbstractSerializer, number) else # reuse the same name for the type, if possible, for nicer debugging tn_name = isdefined(__deserialized_types__, name) ? gensym() : name - tn = ccall(:jl_new_typename_in, Ref{Core.TypeName}, (Any, Any), - tn_name, __deserialized_types__) + tn = ccall(:jl_new_typename_in, Ref{Core.TypeName}, (Any, Any, Cint, Cint), + tn_name, __deserialized_types__, false, false) makenew = true end remember_object(s, tn, number) @@ -1270,7 +1270,7 @@ function deserialize_typename(s::AbstractSerializer, number) ninitialized = deserialize(s)::Int32 if makenew - tn.names = names + Core.setfield!(tn, :names, names) # TODO: there's an unhanded cycle in the dependency graph at this point: # while deserializing super and/or types, we may have encountered # tn.wrapper and throw UndefRefException before we get to this point @@ -1422,7 +1422,7 @@ function deserialize(s::AbstractSerializer, t::DataType) if nf == 0 && t.size > 0 # bits type return read(s.io, t) - elseif t.mutable + elseif t.name.mutable x = ccall(:jl_new_struct_uninit, Any, (Any,), t) deserialize_cycle(s, x) for i in 1:nf diff --git a/sysimage.mk b/sysimage.mk index de5c3e22f253a..57479da366583 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -60,7 +60,7 @@ RELBUILDROOT := $(call rel_path,$(JULIAHOME)/base,$(BUILDROOT)/base)/ # <-- make $(build_private_libdir)/corecompiler.ji: $(COMPILER_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ $(call spawn,$(JULIA_EXECUTABLE)) -C "$(JULIA_CPU_TARGET)" --output-ji $(call cygpath_w,$@).tmp \ - --startup-file=no --warn-overwrite=yes -g0 -O0 compiler/compiler.jl) + --startup-file=no --warn-overwrite=yes -g1 -O0 compiler/compiler.jl) @mv $@.tmp $@ $(build_private_libdir)/sys.ji: $(build_private_libdir)/corecompiler.ji $(JULIAHOME)/VERSION $(BASE_SRCS) $(STDLIB_SRCS) diff --git a/test/ccall.jl b/test/ccall.jl index b7367c96549a5..77e17c6843db1 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).mutable) + if $(t).name.mutable @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).mutable) + if $(t).name.mutable @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).mutable) + if $(t).name.mutable @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).mutable) + if $(t).name.mutable @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).mutable) + if $(t).name.mutable @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).mutable) + if $(t).name.mutable @test !(b === a) end let cf = @cfunction($fname, Ref{AbstractString}, (Ref{Any},)) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index b6eb4acb3cf1d..19b090bad7772 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), Const(:mutable)) == Const(false) -@test Core.Compiler.getfield_tfunc(Const(Vector{Int}), Const(:mutable)) == Const(true) -@test Core.Compiler.getfield_tfunc(DataType, Const(:mutable)) == Bool +@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 # 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 42839d4d954e6..ea0761320e700 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -162,8 +162,8 @@ function fully_eliminated(f, args, retval) end end -# check that type.mutable can be fully eliminated -f_mutable_nothrow(s::String) = Val{typeof(s).mutable} +# check that ismutabletype(type) can be fully eliminated +f_mutable_nothrow(s::String) = Val{typeof(s).name.mutable} @test fully_eliminated(f_mutable_nothrow, (String,)) # check that ifelse can be fully eliminated