Skip to content

Commit

Permalink
remove more extraneous fields from DataType
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Jun 5, 2021
1 parent 443a1b6 commit de6f62a
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 115 deletions.
8 changes: 3 additions & 5 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const DATATYPE_PARAMETERS_FIELDINDEX = fieldindex(DataType, :parameters)
const DATATYPE_TYPES_FIELDINDEX = fieldindex(DataType, :types)
const DATATYPE_SUPER_FIELDINDEX = fieldindex(DataType, :super)
const DATATYPE_INSTANCE_FIELDINDEX = fieldindex(DataType, :instance)
const DATATYPE_NAMES_FIELDINDEX = fieldindex(DataType, :names)
const DATATYPE_HASH_FIELDINDEX = fieldindex(DataType, :hash)

const TYPENAME_NAME_FIELDINDEX = fieldindex(Core.TypeName, :name)
Expand Down Expand Up @@ -289,7 +288,7 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym))
else
return Bottom
end
if 1 <= idx <= a1.ninitialized
if 1 <= idx <= datatype_min_ninitialized(a1)
return Const(true)
elseif a1.name === _NAMEDTUPLE_NAME
if isconcretetype(a1)
Expand Down Expand Up @@ -620,7 +619,6 @@ is_dt_const_field(fld::Int) = (
fld == DATATYPE_TYPES_FIELDINDEX ||
fld == DATATYPE_SUPER_FIELDINDEX ||
fld == DATATYPE_INSTANCE_FIELDINDEX ||
fld == DATATYPE_NAMES_FIELDINDEX ||
fld == DATATYPE_HASH_FIELDINDEX
)
function const_datatype_getfield_tfunc(@nospecialize(sv), fld::Int)
Expand Down Expand Up @@ -738,14 +736,14 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), boundscheck::
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
if !boundscheck && !isvatuple(s) && s.name !== NamedTuple.body.body.name && fieldcount(s) == s.ninitialized
if !boundscheck && s.name.n_uninitialized == 0
return true
end
# Else we need to know what the field is
isa(name, Const) || return false
field = try_compute_fieldidx(s, name.val)
field === nothing && return false
field <= s.ninitialized && return true
field <= datatype_min_ninitialized(s) && return true
# `try_compute_fieldidx` already check for field index bound.
!isvatuple(s) && isbitstype(fieldtype(s0, field)) && return true
end
Expand Down
32 changes: 32 additions & 0 deletions base/compiler/typeutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,38 @@ function isknownlength(t::DataType)
return isdefined(va, :N) && va.N isa Int
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
if t.name === NamedTuple_typename
names, types = t.parameters[1], t.parameters[2]
if names isa Tuple
return length(names)
end
t = argument_datatype(types)
if !(t isa DataType && t.name === Tuple.name)
return 0
end
end
if t.name === Tuple.name
n = length(t.parameters)
n == 0 && return 0
va = t.parameters[n]
if isvarargtype(va)
n -= 1
if isdefined(va, :N)
va = va.N
if va isa Int
n += va
end
end
end
return n
end
return length(t.name.names) - t.name.n_uninitialized
end

# test if non-Type, non-TypeVar `x` can be used to parameterize a type
function valid_tparam(@nospecialize(x))
if isa(x, Tuple)
Expand Down
4 changes: 2 additions & 2 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ function _fieldnames(@nospecialize t)
throw(ArgumentError("type does not have definite field names"))
end
end
isdefined(t, :names) ? t.names : t.name.names
return t.name.names
end

"""
Expand Down Expand Up @@ -749,7 +749,7 @@ function fieldcount(@nospecialize t)
throw(TypeError(:fieldcount, DataType, t))
end
if t.name === NamedTuple_typename
names, types = t.parameters
names, types = t.parameters[1], t.parameters[2]
if names isa Tuple
return length(names)
end
Expand Down
21 changes: 12 additions & 9 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1531,16 +1531,17 @@ 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;
if (!dt->name->mutabl) {
dt->name->mayinlinealloc = 1;
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->mayinlinealloc = 0;
break;
}
}
}
if (!dt->name->mutabl && !dt->name->references_self)
dt->name->mayinlinealloc = 1;
}
}

Expand All @@ -1566,8 +1567,10 @@ 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->name->abstract == dtb->name->abstract &&
dta->name->mutabl == dtb->name->mutabl &&
dta->name->n_uninitialized == dtb->name->n_uninitialized &&
(jl_svec_len(jl_field_names(dta)) != 0 || dta->size == dtb->size) &&
dta->ninitialized == dtb->ninitialized &&
(dta->name->atomicfields == NULL
? dtb->name->atomicfields == NULL
: (dtb->name->atomicfields != NULL &&
Expand Down
5 changes: 3 additions & 2 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1636,7 +1636,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
enum jl_memory_order order)
{
size_t nfields = jl_datatype_nfields(stt);
bool maybe_null = (unsigned)stt->ninitialized != nfields;
bool maybe_null = (unsigned)stt->name->n_uninitialized != 0;
auto idx0 = [&]() {
return emit_bounds_check(ctx, strct, (jl_value_t*)stt, idx, ConstantInt::get(T_size, nfields), inbounds);
};
Expand Down Expand Up @@ -1796,7 +1796,8 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st
}
if (type_is_ghost(julia_type_to_llvm(ctx, jfty)))
return ghostValue(jfty);
bool maybe_null = idx >= (unsigned)jt->ninitialized;
size_t nfields = jl_datatype_nfields(jt);
bool maybe_null = idx >= nfields - (unsigned)jt->name->n_uninitialized;
size_t byte_offset = jl_field_offset(jt, idx);
auto tbaa = strct.tbaa;
if (tbaa == tbaa_datatype && byte_offset != offsetof(jl_datatype_t, types))
Expand Down
5 changes: 3 additions & 2 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3347,7 +3347,8 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
*ret = jl_cgval_t(); // unreachable
return true;
}
if (fieldidx < 0 || fieldidx >= jl_datatype_nfields(stt)) {
ssize_t nf = jl_datatype_nfields(stt);
if (fieldidx < 0 || fieldidx >= nf) {
if (order != jl_memory_order_unspecified) {
emit_atomic_error(ctx, "isdefined: atomic ordering cannot be specified for nonexistent field");
*ret = jl_cgval_t(); // unreachable
Expand All @@ -3367,7 +3368,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
*ret = jl_cgval_t(); // unreachable
return true;
}
if (fieldidx < stt->ninitialized) {
else if (fieldidx < nf - stt->name->n_uninitialized) {
*ret = mark_julia_const(jl_true);
}
else if (jl_field_isptr(stt, fieldidx) || jl_type_hasptr(jl_field_type(stt, fieldidx))) {
Expand Down
39 changes: 18 additions & 21 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu
tn->hash = bitmix(bitmix(module ? module->build_id : 0, name->hash), 0xa1ada1da);
tn->abstract = abstract;
tn->mutabl = mutabl;
tn->references_self = 0;
tn->mayinlinealloc = 0;
tn->mt = NULL;
tn->partial = NULL;
Expand Down Expand Up @@ -105,7 +104,6 @@ jl_datatype_t *jl_new_uninitialized_datatype(void)
t->super = NULL;
t->parameters = NULL;
t->layout = NULL;
t->names = NULL;
t->types = NULL;
t->instance = NULL;
return t;
Expand Down Expand Up @@ -246,7 +244,7 @@ int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_NOTSAFEPOIN
if (ty->layout->npointers > 0) {
if (pointerfree)
return 0;
if (ty->ninitialized != jl_svec_len(ty->types))
if (ty->name->n_uninitialized != 0)
return 0;
if (ty->layout->fielddesc_type > 1) // GC only implements support for 8 and 16 (not array32)
return 0;
Expand Down Expand Up @@ -352,7 +350,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper);
assert(st->types && w->types);
size_t i, nfields = jl_svec_len(st->types);
assert(st->ninitialized <= nfields);
assert(st->name->n_uninitialized <= nfields);
if (st == w && st->layout) {
// this check allows us to force re-computation of the layout for some types during init
st->layout = NULL;
Expand Down Expand Up @@ -392,7 +390,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
}
else {
// compute a conservative estimate of whether there could exist an instance of a subtype of this
for (i = 0; st->has_concrete_subtype && i < st->ninitialized; i++) {
for (i = 0; st->has_concrete_subtype && i < nfields - st->name->n_uninitialized; i++) {
jl_value_t *fld = jl_svecref(st->types, i);
if (fld == jl_bottom_type)
st->has_concrete_subtype = 0;
Expand Down Expand Up @@ -448,7 +446,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
uint32_t fld_npointers = ((jl_datatype_t*)fld)->layout->npointers;
if (((jl_datatype_t*)fld)->layout->haspadding)
haspadding = 1;
if (i >= st->ninitialized && fld_npointers &&
if (i >= nfields - st->name->n_uninitialized && fld_npointers &&
fld_npointers * sizeof(void*) != fsz) {
// field may be undef (may be uninitialized and contains pointer),
// and contains non-pointer fields of non-zero sizes.
Expand Down Expand Up @@ -577,7 +575,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->ninitialized = ninitialized;
t->size = 0;

t->name = NULL;
Expand Down Expand Up @@ -606,6 +603,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
jl_gc_wb(t, t->name);
t->name->names = fnames;
jl_gc_wb(t->name, t->name->names);
tn->n_uninitialized = jl_svec_len(fnames) - ninitialized;

uint32_t *volatile atomicfields = NULL;
int i;
Expand Down Expand Up @@ -1212,7 +1210,8 @@ JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args,
if (!jl_is_datatype(type) || type->layout == NULL) {
jl_type_error("new", (jl_value_t*)jl_datatype_type, (jl_value_t*)type);
}
if (type->ninitialized > na || na > jl_datatype_nfields(type))
size_t nf = jl_datatype_nfields(type);
if (nf - type->name->n_uninitialized > na || na > nf)
jl_error("invalid struct allocation");
for (size_t i = 0; i < na; i++) {
jl_value_t *ft = jl_field_type_concrete(type, i);
Expand Down Expand Up @@ -1312,24 +1311,22 @@ JL_DLLEXPORT void jl_unlock_value(jl_value_t *v) JL_NOTSAFEPOINT

JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err)
{
jl_svec_t *fn = jl_field_names(t);
size_t n = jl_svec_len(fn);
if (n == 0) {
if (jl_is_namedtuple_type(t)) {
jl_value_t *ns = jl_tparam0(t);
if (jl_is_tuple(ns)) {
n = jl_nfields(ns);
for(size_t i=0; i < n; i++) {
if (jl_get_nth_field(ns, i) == (jl_value_t*)fld) {
return (int)i;
}
if (jl_is_namedtuple_type(t)) {
jl_value_t *ns = jl_tparam0(t);
if (jl_is_tuple(ns)) {
size_t i, n = jl_nfields(ns);
for (i = 0; i < n; i++) {
if (jl_get_nth_field(ns, i) == (jl_value_t*)fld) {
return (int)i;
}
}
}
}
else {
for(size_t i=0; i < n; i++) {
if (jl_svecref(fn,i) == (jl_value_t*)fld) {
jl_svec_t *fn = jl_field_names(t);
size_t i, n = jl_svec_len(fn);
for (i = 0; i < n; i++) {
if (jl_svecref(fn, i) == (jl_value_t*)fld) {
return (int)i;
}
}
Expand Down
28 changes: 11 additions & 17 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,17 +271,14 @@ 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->name->abstract | (has_layout << 1) | (has_instance << 2));
write_uint8(s->s, has_layout | (has_instance << 1));
write_uint8(s->s, dt->hasfreetypevars
| (dt->isconcretetype << 1)
| (dt->isdispatchtuple << 2)
| (dt->isbitstype << 3)
| (dt->zeroinit << 4)
| (dt->has_concrete_subtype << 5)
| (dt->cached_by_hash << 6));
if (!dt->name->abstract) {
write_uint16(s->s, dt->ninitialized);
}
write_int32(s->s, dt->hash);

if (has_layout) {
Expand Down Expand Up @@ -311,7 +308,6 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt) JL_
if (has_instance)
jl_serialize_value(s, dt->instance);
jl_serialize_value(s, dt->name);
jl_serialize_value(s, dt->names);
jl_serialize_value(s, dt->parameters);
jl_serialize_value(s, dt->super);
jl_serialize_value(s, dt->types);
Expand Down Expand Up @@ -815,7 +811,9 @@ 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) | (tn->mayinlinealloc << 3));
write_uint8(s->s, tn->abstract | (tn->mutabl << 1) | (tn->mayinlinealloc << 2));
if (!tn->abstract)
write_uint16(s->s, tn->n_uninitialized);
size_t nb = tn->atomicfields ? (jl_svec_len(tn->names) + 31) / 32 * sizeof(uint32_t) : 0;
write_int32(s->s, nb);
if (nb)
Expand Down Expand Up @@ -1273,20 +1271,15 @@ 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;
int abstract = flags & 1;
int has_layout = (flags >> 1) & 1;
int has_instance = (flags >> 2) & 1;
int has_layout = flags & 1;
int has_instance = (flags >> 1) & 1;
dt->hasfreetypevars = memflags & 1;
dt->isconcretetype = (memflags >> 1) & 1;
dt->isdispatchtuple = (memflags >> 2) & 1;
dt->isbitstype = (memflags >> 3) & 1;
dt->zeroinit = (memflags >> 4) & 1;
dt->has_concrete_subtype = (memflags >> 5) & 1;
dt->cached_by_hash = (memflags >> 6) & 1;
if (abstract)
dt->ninitialized = 0;
else
dt->ninitialized = read_uint16(s->s);
dt->hash = read_int32(s->s);

if (has_layout) {
Expand Down Expand Up @@ -1334,8 +1327,6 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v
}
dt->name = (jl_typename_t*)jl_deserialize_value(s, (jl_value_t**)&dt->name);
jl_gc_wb(dt, dt->name);
dt->names = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->names);
jl_gc_wb(dt, dt->names);
dt->parameters = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->parameters);
jl_gc_wb(dt, dt->parameters);
dt->super = (jl_datatype_t*)jl_deserialize_value(s, (jl_value_t**)&dt->super);
Expand Down Expand Up @@ -1738,8 +1729,11 @@ static jl_value_t *jl_deserialize_value_any(jl_serializer_state *s, uint8_t tag,
int8_t flags = read_int8(s->s);
tn->abstract = flags & 1;
tn->mutabl = (flags>>1) & 1;
tn->references_self = (flags>>2) & 1;
tn->mayinlinealloc = (flags>>3) & 1;
tn->mayinlinealloc = (flags>>2) & 1;
if (tn->abstract)
tn->n_uninitialized = 0;
else
tn->n_uninitialized = read_uint16(s->s);
size_t nfields = read_int32(s->s);
if (nfields) {
tn->atomicfields = (uint32_t*)malloc(nfields);
Expand Down
2 changes: 1 addition & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3137,7 +3137,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, int offs,
}

// see if it might be possible to construct an instance of `typ`
// if ninitialized == nfields, but a fieldtype is Union{},
// if n_uninitialized == 0, but a fieldtype is Union{},
// that type will not be constructable, for example, tested recursively
int jl_has_concrete_subtype(jl_value_t *typ)
{
Expand Down
Loading

0 comments on commit de6f62a

Please sign in to comment.