Skip to content

types: lazy initialize the field-types when first needed #31877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ function nfields_tfunc(@nospecialize(x))
x = widenconst(x)
if isa(x, DataType) && !x.abstract && !(x.name === Tuple.name && isvatuple(x))
if !(x.name === _NAMEDTUPLE_NAME && !isconcretetype(x))
return Const(length(x.types))
return Const(isdefined(x, :types) ? length(x.types) : length(x.name.names))
end
end
return Int
Expand Down Expand Up @@ -588,7 +588,7 @@ function fieldcount_noerror(@nospecialize t)
if abstr
return nothing
end
return length(t.types)
return isdefined(t, :types) ? length(t.types) : length(t.name.names)
end


Expand Down Expand Up @@ -744,7 +744,8 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
# TODO: better approximate inference
return Any
end
if isempty(s.types)
ftypes = datatype_fieldtypes(s)
if isempty(ftypes)
return Bottom
end
if isa(name, Conditional)
Expand All @@ -754,27 +755,27 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
if !(Int <: name || Symbol <: name)
return Bottom
end
if length(s.types) == 1
return rewrap_unionall(unwrapva(s.types[1]), s00)
if length(ftypes) == 1
return rewrap_unionall(unwrapva(ftypes[1]), s00)
end
# union together types of all fields
t = Bottom
for _ft in s.types
for _ft in ftypes
t = tmerge(t, rewrap_unionall(unwrapva(_ft), s00))
t === Any && break
end
return t
end
fld = name.val
if isa(fld,Symbol)
if isa(fld, Symbol)
fld = fieldindex(s, fld, false)
end
if !isa(fld,Int)
if !isa(fld, Int)
return Bottom
end
nf = length(s.types)
if s <: Tuple && fld >= nf && isvarargtype(s.types[nf])
return rewrap_unionall(unwrapva(s.types[nf]), s00)
nf = length(ftypes)
if s <: Tuple && fld >= nf && isvarargtype(ftypes[nf])
return rewrap_unionall(unwrapva(ftypes[nf]), s00)
end
if fld < 1 || fld > nf
return Bottom
Expand All @@ -790,7 +791,7 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
t = const_datatype_getfield_tfunc(sp, fld)
t !== nothing && return t
end
R = s.types[fld]
R = ftypes[fld]
if isempty(s.parameters)
return R
end
Expand Down Expand Up @@ -843,7 +844,7 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
fld = fieldindex(u, fld, false)
end
isa(fld, Int) || return false
ftypes = u.types
ftypes = datatype_fieldtypes(u)
nf = length(ftypes)
(fld >= 1 && fld <= nf) || return false
if u.name === Tuple.name && fld >= nf && isvarargtype(ftypes[nf])
Expand Down Expand Up @@ -893,7 +894,7 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
# TODO: better approximate inference
return Type
end
ftypes = u.types
ftypes = datatype_fieldtypes(u)
if isempty(ftypes)
return Bottom
end
Expand Down
13 changes: 10 additions & 3 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ objectid(@nospecialize(x)) = ccall(:jl_object_id, UInt, (Any,), x)

# concrete datatype predicates

datatype_fieldtypes(x::DataType) = ccall(:jl_get_fieldtypes, Any, (Any,), x)

struct DataTypeLayout
nfields::UInt32
alignment::UInt32
Expand Down Expand Up @@ -407,7 +409,8 @@ function isstructtype(@nospecialize(t::Type))
t = unwrap_unionall(t)
# TODO: what to do for `Union`?
isa(t, DataType) || return false
return length(t.types) != 0 || (t.size == 0 && !t.abstract)
hasfield = !isdefined(t, :types) || !isempty(t.types)
return hasfield || (t.size == 0 && !t.abstract)
end

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

"""
Expand Down Expand Up @@ -674,7 +678,10 @@ function fieldcount(@nospecialize t)
if abstr
throw(ArgumentError("type does not have a definite number of fields"))
end
return length(t.types)
if isdefined(t, :types)
return length(t.types)
end
return length(t.name.names)
end

"""
Expand Down
2 changes: 1 addition & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1729,7 +1729,7 @@ function dump(io::IOContext, x::DataType, n::Int, indent)
end
end
fields = fieldnames(x)
fieldtypes = x.types
fieldtypes = datatype_fieldtypes(x)
for idx in 1:length(fields)
println(io)
print(io, indent, " ", fields[idx], "::")
Expand Down
4 changes: 3 additions & 1 deletion base/summarysize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ function (ss::SummarySize)(obj::DataType)
size::Int = 7 * Core.sizeof(Int) + 6 * Core.sizeof(Int32)
size += 4 * nfields(obj) + ifelse(Sys.WORD_SIZE == 64, 4, 0)
size += ss(obj.parameters)::Int
size += ss(obj.types)::Int
if isdefined(obj, :types)
size += ss(obj.types)::Int
end
return size
end

Expand Down
7 changes: 4 additions & 3 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,10 @@ static inline int is_ntuple_long(jl_value_t *v)
{
if (!jl_is_tuple(v))
return 0;
size_t nfields = jl_nfields(v);
for (size_t i = 0; i < nfields; i++) {
if (jl_field_type(jl_typeof(v), i) != (jl_value_t*)jl_long_type) {
jl_value_t *tt = jl_typeof(v);
size_t i, nfields = jl_nparams(tt);
for (i = 0; i < nfields; i++) {
if (jl_tparam(tt, i) != (jl_value_t*)jl_long_type) {
return 0;
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,8 @@ static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow)
return (jl_value_t*)jl_any_type;
return get_fieldtype(tt, f, dothrow);
}
int nf = jl_field_count(st);
jl_svec_t *types = jl_get_fieldtypes(st);
int nf = jl_svec_len(types);
if (nf > 0 && field_index >= nf-1 && st->name == jl_tuple_typename) {
jl_value_t *ft = jl_field_type(st, nf-1);
if (jl_is_vararg_type(ft))
Expand Down Expand Up @@ -790,8 +791,8 @@ JL_CALLABLE(jl_f_fieldtype)
JL_CALLABLE(jl_f_nfields)
{
JL_NARGS(nfields, 1, 1);
jl_value_t *x = args[0];
return jl_box_long(jl_field_count(jl_typeof(x)));
jl_datatype_t *xt = (jl_datatype_t*)jl_typeof(args[0]);
return jl_box_long(jl_datatype_nfields(xt));
}

JL_CALLABLE(jl_f_isdefined)
Expand Down
14 changes: 8 additions & 6 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,9 +569,10 @@ static bool julia_struct_has_layout(jl_datatype_t *dt, jl_unionall_t *ua)
if (dt->layout || dt->struct_decl || jl_justbits((jl_value_t*)dt))
return true;
if (ua) {
size_t i, ntypes = jl_svec_len(dt->types);
jl_svec_t *types = jl_get_fieldtypes(dt);
size_t i, ntypes = jl_svec_len(types);
for (i = 0; i < ntypes; i++) {
jl_value_t *ty = jl_svecref(dt->types, i);
jl_value_t *ty = jl_svecref(types, i);
if (jl_has_typevar_from_unionall(ty, ua))
return false;
}
Expand Down Expand Up @@ -603,7 +604,8 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox
if (jst->struct_decl != NULL)
return (Type*)jst->struct_decl;
if (jl_is_structtype(jt) && !(jst->layout && jl_is_layout_opaque(jst->layout))) {
size_t i, ntypes = jl_svec_len(jst->types);
jl_svec_t *ftypes = jl_get_fieldtypes(jst);
size_t i, ntypes = jl_svec_len(ftypes);
if (ntypes == 0 || (jst->layout && jl_datatype_nbits(jst) == 0))
return T_void;
if (!julia_struct_has_layout(jst, ua))
Expand All @@ -615,7 +617,7 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox
Type *lasttype = NULL;
bool allghost = true;
for (i = 0; i < ntypes; i++) {
jl_value_t *ty = jl_svecref(jst->types, i);
jl_value_t *ty = jl_svecref(ftypes, i);
if (jlasttype != NULL && ty != jlasttype)
isvector = false;
jlasttype = ty;
Expand Down Expand Up @@ -1496,7 +1498,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
}
else if (is_tupletype_homogeneous(stt->types)) {
assert(nfields > 0); // nf == 0 trapped by all_pointers case
jl_value_t *jt = jl_field_type(stt, 0);
jl_value_t *jt = jl_svecref(stt->types, 0);
idx = emit_bounds_check(ctx, strct, (jl_value_t*)stt, idx, ConstantInt::get(T_size, nfields), inbounds);
Value *ptr = maybe_decay_tracked(data_pointer(ctx, strct));
if (!stt->mutabl && !(maybe_null && jt == (jl_value_t*)jl_bool_type)) {
Expand Down Expand Up @@ -1526,7 +1528,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
return true;
}
assert(!jl_field_isptr(stt, 0));
jl_value_t *jt = jl_field_type(stt, 0);
jl_value_t *jt = jl_svecref(stt->types, 0);
Value *idx0 = emit_bounds_check(ctx, strct, (jl_value_t*)stt, idx, ConstantInt::get(T_size, nfields), inbounds);
if (strct.isghost) {
*ret = ghostValue(jt);
Expand Down
10 changes: 5 additions & 5 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t)
if (mask)
return 0; // nfields has more than two 1s
assert(jl_datatype_nfields(t)==1);
jl_value_t *ty = jl_field_type(t, 0);
jl_value_t *ty = jl_field_type((jl_datatype_t*)t, 0);
if (!jl_is_primitivetype(ty))
// LLVM requires that a vector element be a primitive type.
// LLVM allows pointer types as vector elements, but until a
Expand Down Expand Up @@ -301,19 +301,19 @@ void jl_compute_field_offsets(jl_datatype_t *st)
// based on whether its definition is self-referential
if (w->types != NULL) {
st->isbitstype = st->isconcretetype && !st->mutabl;
size_t i, nf = jl_field_count(st);
size_t i, nf = jl_svec_len(st->types);
for (i = 0; i < nf; i++) {
jl_value_t *fld = jl_field_type(st, i);
jl_value_t *fld = jl_svecref(st->types, i);
if (st->isbitstype)
st->isbitstype = jl_is_datatype(fld) && ((jl_datatype_t*)fld)->isbitstype;
if (!st->zeroinit)
st->zeroinit = (jl_is_datatype(fld) && ((jl_datatype_t*)fld)->isinlinealloc) ? ((jl_datatype_t*)fld)->zeroinit : 1;
}
if (st->isbitstype) {
st->isinlinealloc = 1;
size_t i, nf = jl_field_count(w);
size_t i, nf = jl_svec_len(w->types);
for (i = 0; i < nf; i++) {
jl_value_t *fld = jl_field_type(w, i);
jl_value_t *fld = jl_svecref(w->types, i);
if (references_name(fld, w->name)) {
st->isinlinealloc = 0;
st->isbitstype = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1458,7 +1458,7 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v
dt->super = (jl_datatype_t*)jl_deserialize_value(s, (jl_value_t**)&dt->super);
jl_gc_wb(dt, dt->super);
dt->types = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->types);
jl_gc_wb(dt, dt->types);
if (dt->types) jl_gc_wb(dt, dt->types);

return (jl_value_t*)dt;
}
Expand Down
12 changes: 6 additions & 6 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,13 +421,13 @@ static int very_general_type(jl_value_t *t)
jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i)
{
sig = jl_unwrap_unionall(sig);
size_t len = jl_field_count(sig);
size_t len = jl_nparams(sig);
if (len == 0)
return NULL;
if (i < len-1)
return jl_tparam(sig, i);
if (jl_is_vararg_type(jl_tparam(sig,len-1)))
return jl_unwrap_vararg(jl_tparam(sig,len-1));
if (jl_is_vararg_type(jl_tparam(sig, len-1)))
return jl_unwrap_vararg(jl_tparam(sig, len-1));
if (i == len-1)
return jl_tparam(sig, i);
return NULL;
Expand Down Expand Up @@ -473,7 +473,7 @@ static void jl_compilation_sig(
jl_value_t *decl = definition->sig;
assert(jl_is_tuple_type(tt));
size_t i, np = jl_nparams(tt);
size_t nargs = definition->nargs; // == jl_field_count(jl_unwrap_unionall(decl));
size_t nargs = definition->nargs; // == jl_nparams(jl_unwrap_unionall(decl));
for (i = 0; i < np; i++) {
jl_value_t *elt = jl_tparam(tt, i);
jl_value_t *decl_i = jl_nth_slot_type(decl, i);
Expand Down Expand Up @@ -678,7 +678,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig(
return 0;

size_t i, np = jl_nparams(type);
size_t nargs = definition->nargs; // == jl_field_count(jl_unwrap_unionall(decl));
size_t nargs = definition->nargs; // == jl_nparams(jl_unwrap_unionall(decl));
if (np == 0)
return nargs == 0;

Expand Down Expand Up @@ -2565,7 +2565,7 @@ int jl_has_concrete_subtype(jl_value_t *typ)
return 1;
if (((jl_datatype_t*)typ)->name == jl_namedtuple_typename)
return jl_has_concrete_subtype(jl_tparam1(typ));
jl_svec_t *fields = ((jl_datatype_t*)typ)->types;
jl_svec_t *fields = jl_get_fieldtypes((jl_datatype_t*)typ);
size_t i, l = jl_svec_len(fields);
if (l != ((jl_datatype_t*)typ)->ninitialized)
if (((jl_datatype_t*)typ)->name != jl_tuple_typename)
Expand Down
15 changes: 9 additions & 6 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb)
dta->ninitialized == dtb->ninitialized &&
jl_egal((jl_value_t*)jl_field_names(dta), (jl_value_t*)jl_field_names(dtb)) &&
jl_nparams(dta) == jl_nparams(dtb) &&
jl_field_count(dta) == jl_field_count(dtb)))
jl_svec_len(dta->types) == jl_svec_len(dtb->types)))
return 0;
jl_value_t *a=NULL, *b=NULL;
int ok = 1;
size_t i, nf = jl_field_count(dta);
size_t i, nf = jl_svec_len(dta->types);
JL_GC_PUSH2(&a, &b);
a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper);
b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper);
Expand All @@ -63,7 +63,8 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb)
JL_CATCH {
ok = 0;
}
if (!ok) goto no;
if (!ok)
goto no;
assert(jl_is_datatype(a));
a = dta->name->wrapper;
b = dtb->name->wrapper;
Expand All @@ -77,9 +78,11 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb)
b = ub->body;
}
assert(jl_is_datatype(a) && jl_is_datatype(b));
for (i=0; i < nf; i++) {
jl_value_t *ta = jl_svecref(((jl_datatype_t*)a)->types, i);
jl_value_t *tb = jl_svecref(((jl_datatype_t*)b)->types, i);
a = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)a);
b = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)b);
for (i = 0; i < nf; i++) {
jl_value_t *ta = jl_svecref(a, i);
jl_value_t *tb = jl_svecref(b, i);
if (jl_has_free_typevars(ta)) {
if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb))
goto no;
Expand Down
6 changes: 6 additions & 0 deletions src/jlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ JL_DLLEXPORT jl_value_t *(jl_typeof)(jl_value_t *v)
return jl_typeof(v);
}

JL_DLLEXPORT jl_value_t *(jl_get_fieldtypes)(jl_value_t *v)
{
return (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)v);
}


#ifndef __clang_analyzer__
JL_DLLEXPORT int8_t (jl_gc_unsafe_enter)(void)
{
Expand Down
Loading