diff --git a/src/codegen.cpp b/src/codegen.cpp index e55424d47170e..cefa88a579fc0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2455,8 +2455,8 @@ static jl_cgval_t emit_getfield(jl_value_t *expr, jl_sym_t *name, jl_codectx_t * JL_GC_PUSH1(&sty); if (jl_is_type_type((jl_value_t*)sty) && jl_is_leaf_type(jl_tparam0(sty))) sty = (jl_datatype_t*)jl_typeof(jl_tparam0(sty)); - if (jl_is_structtype(sty) && sty != jl_module_type && sty->uid != 0 && - jl_is_leaf_type((jl_value_t*)sty)) { + sty = (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)sty); + if (jl_is_structtype(sty) && sty != jl_module_type && sty->layout) { unsigned idx = jl_field_index(sty, name, 0); if (idx != (unsigned)-1) { jl_cgval_t strct = emit_expr(expr, ctx); @@ -2971,8 +2971,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, JL_GC_POP(); return true; } - jl_datatype_t *stt = (jl_datatype_t*)expr_type(args[1], ctx); - jl_value_t *fldt = expr_type(args[2], ctx); + jl_value_t *fldt = expr_type(args[2], ctx); // VA tuple if (ctx->vaStack && slot_eq(args[1], ctx->vaSlot)) { @@ -2989,22 +2988,25 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, return true; } - if (fldt == (jl_value_t*)jl_long_type && jl_is_leaf_type((jl_value_t*)stt)) { - if ((jl_is_structtype(stt) || jl_is_tuple_type(stt)) && !jl_subtype((jl_value_t*)jl_module_type, (jl_value_t*)stt)) { - size_t nfields = jl_datatype_nfields(stt); + jl_datatype_t *stt = (jl_datatype_t*)expr_type(args[1], ctx); + jl_value_t *utt = jl_unwrap_unionall((jl_value_t*)stt); + + if (fldt == (jl_value_t*)jl_long_type && jl_is_datatype(utt) && ((jl_datatype_t*)utt)->layout) { + if ((jl_is_structtype(utt) || jl_is_tuple_type(utt)) && !jl_subtype((jl_value_t*)jl_module_type, (jl_value_t*)stt)) { + size_t nfields = jl_datatype_nfields(utt); jl_cgval_t strct = emit_expr(args[1], ctx); // integer index size_t idx; if (jl_is_long(args[2]) && (idx=jl_unbox_long(args[2])-1) < nfields) { // known index - *ret = emit_getfield_knownidx(strct, idx, stt, ctx); + *ret = emit_getfield_knownidx(strct, idx, (jl_datatype_t*)utt, ctx); JL_GC_POP(); return true; } else { // unknown index Value *vidx = emit_unbox(T_size, emit_expr(args[2], ctx), (jl_value_t*)jl_long_type); - if (emit_getfield_unknownidx(ret, strct, vidx, stt, ctx)) { + if (emit_getfield_unknownidx(ret, strct, vidx, (jl_datatype_t*)utt, ctx)) { if (ret->typ == (jl_value_t*)jl_any_type) // improve the type, if known from the expr ret->typ = expr_type(expr, ctx); JL_GC_POP(); @@ -3012,8 +3014,8 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, } } } - } else { - jl_value_t *utt = jl_unwrap_unionall((jl_value_t*)stt); + } + else { if (jl_is_tuple_type(utt) && is_tupletype_homogeneous(((jl_datatype_t*)utt)->types, true)) { // For tuples, we can emit code even if we don't know the exact // type (e.g. because we don't know the length). This is possible @@ -3045,10 +3047,11 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, else if (f==jl_builtin_setfield && nargs==3) { jl_datatype_t *sty = (jl_datatype_t*)expr_type(args[1], ctx); rt1 = (jl_value_t*)sty; - if (jl_is_structtype(sty) && sty != jl_module_type) { + jl_datatype_t *uty = (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)sty); + if (jl_is_structtype(uty) && uty != jl_module_type) { size_t idx = (size_t)-1; if (jl_is_quotenode(args[2]) && jl_is_symbol(jl_fieldref(args[2],0))) { - idx = jl_field_index(sty, (jl_sym_t*)jl_fieldref(args[2],0), 0); + idx = jl_field_index(uty, (jl_sym_t*)jl_fieldref(args[2],0), 0); } else if (jl_is_long(args[2]) || (jl_is_quotenode(args[2]) && jl_is_long(jl_fieldref(args[2],0)))) { ssize_t i; @@ -3056,14 +3059,14 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, i = jl_unbox_long(args[2]); else i = jl_unbox_long(jl_fieldref(args[2],0)); - if (i > 0 && i <= jl_datatype_nfields(sty)) + if (i > 0 && i <= jl_datatype_nfields(uty)) idx = i-1; } if (idx != (size_t)-1) { - jl_value_t *ft = jl_svecref(sty->types, idx); + jl_value_t *ft = jl_svecref(uty->types, idx); jl_value_t *rhst = expr_type(args[3], ctx); rt2 = rhst; - if (jl_is_leaf_type((jl_value_t*)sty) && jl_subtype(rhst, ft)) { + if (uty->layout && jl_subtype(rhst, ft)) { // TODO: attempt better codegen for approximate types jl_cgval_t strct = emit_expr(args[1], ctx); // emit lhs *ret = emit_expr(args[3], ctx); diff --git a/src/datatype.c b/src/datatype.c index 1d8005fe462e7..6bf0388894004 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -227,11 +227,37 @@ void jl_compute_field_offsets(jl_datatype_t *st) size_t sz = 0, alignm = 1; int homogeneous = 1; jl_value_t *lastty = NULL; - uint64_t max_offset = (((uint64_t)1) << 32) - 1; uint64_t max_size = max_offset >> 1; + if (st->name->wrapper) { + // If layout doesn't depend on type parameters, it's stored in st->name->wrapper + // and reused by all subtypes. + jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper); + if (st != w && // this check allows us to re-compute layout for some types during init + w->layout) { + st->layout = w->layout; + st->size = w->size; + return; + } + } + if (st->types == NULL) + return; uint32_t nfields = jl_svec_len(st->types); + if (nfields == 0 && st != jl_sym_type && st != jl_simplevector_type) { + // reuse the same layout for all singletons + static const jl_datatype_layout_t singleton_layout = {0, 1, 0, 0, 0}; + st->layout = &singleton_layout; + return; + } + if (!jl_is_leaf_type((jl_value_t*)st)) { + // compute layout whenever field types have no free variables + for (size_t i = 0; i < nfields; i++) { + if (jl_has_free_typevars(jl_field_type(st, i))) + return; + } + } + size_t descsz = nfields * sizeof(jl_fielddesc32_t); jl_fielddesc32_t *desc; if (descsz < jl_page_size) @@ -372,18 +398,11 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super } jl_precompute_memoized_dt(t); - if (abstract || jl_svec_len(parameters) > 0) { - t->uid = 0; - } - else { - t->uid = jl_assign_type_uid(); - if (t->types != NULL && t->isleaftype) { - static const jl_datatype_layout_t singleton_layout = {0, 1, 0, 0, 0}; - if (fnames == jl_emptysvec) - t->layout = &singleton_layout; - else - jl_compute_field_offsets(t); - } + t->uid = 0; + if (!abstract) { + if (jl_svec_len(parameters) == 0) + t->uid = jl_assign_type_uid(); + jl_compute_field_offsets(t); } JL_GC_POP(); return t; diff --git a/src/interpreter.c b/src/interpreter.c index a4743edcec4b4..4e78fea57383a 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -470,10 +470,7 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s) b->value = temp; jl_rethrow(); } - if (dt->name->names == jl_emptysvec) - dt->layout = jl_void_type->layout; // reuse the same layout for all singletons - else if (jl_is_leaf_type((jl_value_t*)dt)) - jl_compute_field_offsets(dt); + jl_compute_field_offsets(dt); if (para == (jl_value_t*)jl_emptysvec && jl_is_datatype_make_singleton(dt)) { dt->instance = jl_gc_alloc(ptls, 0, dt); jl_gc_wb(dt, dt->instance);