Skip to content

Commit c545eab

Browse files
committed
codegen: complete handling for partial-layout objects
Fixes #41425
1 parent da59cdb commit c545eab

File tree

6 files changed

+46
-39
lines changed

6 files changed

+46
-39
lines changed

src/ccall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ static Value *julia_to_native(
493493
assert(!byRef); // don't expect any ABI to pass pointers by pointer
494494
return boxed(ctx, jvinfo);
495495
}
496-
assert(jl_is_datatype(jlto) && julia_struct_has_layout((jl_datatype_t*)jlto));
496+
assert(jl_is_datatype(jlto) && jl_struct_try_layout((jl_datatype_t*)jlto));
497497

498498
typeassert_input(ctx, jvinfo, jlto, jlto_env, argn);
499499
if (!byRef)

src/cgutils.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ static size_t dereferenceable_size(jl_value_t *jt)
321321
// Array has at least this much data
322322
return sizeof(jl_array_t);
323323
}
324-
else if (jl_is_datatype(jt) && ((jl_datatype_t*)jt)->layout) {
324+
else if (jl_is_datatype(jt) && jl_struct_try_layout((jl_datatype_t*)jt)) {
325325
return jl_datatype_size(jt);
326326
}
327327
return 0;
@@ -339,7 +339,7 @@ static unsigned julia_alignment(jl_value_t *jt)
339339
// and this is the guarantee we have for the GC bits
340340
return 16;
341341
}
342-
assert(jl_is_datatype(jt) && ((jl_datatype_t*)jt)->layout);
342+
assert(jl_is_datatype(jt) && jl_struct_try_layout((jl_datatype_t*)jt));
343343
unsigned alignment = jl_datatype_align(jt);
344344
if (alignment > JL_HEAP_ALIGNMENT)
345345
return JL_HEAP_ALIGNMENT;
@@ -555,16 +555,10 @@ static Type *bitstype_to_llvm(jl_value_t *bt, bool llvmcall = false)
555555
}
556556

557557
static bool jl_type_hasptr(jl_value_t* typ)
558-
{ // assumes that jl_stored_inline(typ) is true
558+
{ // assumes that jl_stored_inline(typ) is true (and therefore that layout is defined)
559559
return jl_is_datatype(typ) && ((jl_datatype_t*)typ)->layout->npointers > 0;
560560
}
561561

562-
// return whether all concrete subtypes of this type have the same layout
563-
static bool julia_struct_has_layout(jl_datatype_t *dt)
564-
{
565-
return dt->layout || jl_has_fixed_layout(dt);
566-
}
567-
568562
static unsigned jl_field_align(jl_datatype_t *dt, size_t i)
569563
{
570564
unsigned al = jl_field_offset(dt, i);
@@ -588,11 +582,8 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, boo
588582
bool isTuple = jl_is_tuple_type(jt);
589583
jl_svec_t *ftypes = jl_get_fieldtypes(jst);
590584
size_t i, ntypes = jl_svec_len(ftypes);
591-
if (!julia_struct_has_layout(jst))
585+
if (!jl_struct_try_layout(jst))
592586
return NULL; // caller should have checked jl_type_mappable_to_c already, but we'll be nice
593-
if (jst->layout == NULL)
594-
jl_compute_field_offsets(jst);
595-
assert(jst->layout);
596587
if (ntypes == 0 || jl_datatype_nbits(jst) == 0)
597588
return T_void;
598589
Type *_struct_decl = NULL;
@@ -1904,6 +1895,9 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
19041895
return true;
19051896
}
19061897
if (nfields == 1) {
1898+
if (jl_has_free_typevars(jl_field_type(stt, 0))) {
1899+
return false;
1900+
}
19071901
(void)idx0();
19081902
*ret = emit_getfield_knownidx(ctx, strct, 0, stt, order);
19091903
return true;

src/codegen.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -933,12 +933,12 @@ static MDNode *best_tbaa(jl_value_t *jt) {
933933
// note that this includes jl_isbits, although codegen should work regardless
934934
static bool jl_is_concrete_immutable(jl_value_t* t)
935935
{
936-
return jl_is_immutable_datatype(t) && ((jl_datatype_t*)t)->layout;
936+
return jl_is_immutable_datatype(t) && ((jl_datatype_t*)t)->isconcretetype;
937937
}
938938

939939
static bool jl_is_pointerfree(jl_value_t* t)
940940
{
941-
if (!jl_is_immutable_datatype(t))
941+
if (!jl_is_concrete_immutable(t))
942942
return 0;
943943
const jl_datatype_layout_t *layout = ((jl_datatype_t*)t)->layout;
944944
return layout && layout->npointers == 0;
@@ -3033,9 +3033,9 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
30333033
return true;
30343034
}
30353035

3036-
if (jl_is_datatype(utt) && utt->layout) {
3036+
if (jl_is_datatype(utt) && jl_struct_try_layout(utt)) {
30373037
ssize_t idx = jl_field_index(utt, name, 0);
3038-
if (idx != -1) {
3038+
if (idx != -1 && !jl_has_free_typevars(jl_field_type(utt, idx))) {
30393039
*ret = emit_getfield_knownidx(ctx, obj, idx, utt, order);
30403040
return true;
30413041
}
@@ -3063,14 +3063,16 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
30633063
}
30643064

30653065
if (jl_is_datatype(utt)) {
3066-
if (jl_is_structtype(utt) && utt->layout) {
3066+
if (jl_struct_try_layout(utt)) {
30673067
size_t nfields = jl_datatype_nfields(utt);
30683068
// integer index
30693069
size_t idx;
30703070
if (fld.constant && (idx = jl_unbox_long(fld.constant) - 1) < nfields) {
3071-
// known index
3072-
*ret = emit_getfield_knownidx(ctx, obj, idx, utt, order);
3073-
return true;
3071+
if (!jl_has_free_typevars(jl_field_type(utt, idx))) {
3072+
// known index
3073+
*ret = emit_getfield_knownidx(ctx, obj, idx, utt, order);
3074+
return true;
3075+
}
30743076
}
30753077
else {
30763078
// unknown index
@@ -3115,8 +3117,6 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
31153117
}
31163118
}
31173119
}
3118-
// TODO: attempt better codegen for approximate types, if the types
3119-
// and offsets of some fields are independent of parameters.
31203120
// TODO: generic getfield func with more efficient calling convention
31213121
return false;
31223122
}
@@ -3155,7 +3155,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
31553155
}
31563156

31573157
jl_datatype_t *uty = (jl_datatype_t*)jl_unwrap_unionall(obj.typ);
3158-
if (jl_is_structtype(uty) && uty->layout) {
3158+
if (jl_is_datatype(uty) && jl_struct_try_layout(uty)) {
31593159
ssize_t idx = -1;
31603160
if (fld.constant && fld.typ == (jl_value_t*)jl_symbol_type) {
31613161
idx = jl_field_index(uty, (jl_sym_t*)fld.constant, 0);

src/datatype.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,27 +220,36 @@ unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t)
220220
return next_power_of_two(size);
221221
}
222222

223-
STATIC_INLINE int jl_is_datatype_make_singleton(jl_datatype_t *d)
223+
STATIC_INLINE int jl_is_datatype_make_singleton(jl_datatype_t *d) JL_NOTSAFEPOINT
224224
{
225225
return (!d->name->abstract && jl_datatype_size(d) == 0 && d != jl_symbol_type && d->name != jl_array_typename &&
226226
d->isconcretetype && !d->name->mutabl);
227227
}
228228

229-
STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st)
229+
STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) JL_NOTSAFEPOINT
230230
{
231231
if (jl_is_datatype_make_singleton(st)) {
232232
// It's possible for st to already have an ->instance if it was redefined
233-
if (!st->instance) {
234-
jl_task_t *ct = jl_current_task;
235-
st->instance = jl_gc_alloc(ct->ptls, 0, st);
236-
jl_gc_wb(st, st->instance);
237-
}
233+
if (!st->instance)
234+
st->instance = jl_gc_permobj(0, st);
238235
}
239236
}
240237

238+
// return whether all concrete subtypes of this type have the same layout
239+
int jl_struct_try_layout(jl_datatype_t *dt)
240+
{
241+
if (dt->layout)
242+
return 1;
243+
else if (!jl_has_fixed_layout(dt))
244+
return 0;
245+
jl_compute_field_offsets(dt);
246+
assert(dt->layout);
247+
return 1;
248+
}
249+
241250
int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_NOTSAFEPOINT
242251
{
243-
if (ty->name->mayinlinealloc && ty->layout) {
252+
if (ty->name->mayinlinealloc && (ty->isconcretetype || ((jl_datatype_t*)jl_unwrap_unionall(ty->name->wrapper))->layout)) { // TODO: use jl_struct_try_layout(dt) (but it is a safepoint)
244253
if (ty->layout->npointers > 0) {
245254
if (pointerfree)
246255
return 0;

src/jltypes.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ int jl_has_fixed_layout(jl_datatype_t *dt)
223223
{
224224
if (dt->layout || dt->isconcretetype)
225225
return 1;
226-
if (jl_is_tuple_type(dt))
226+
if (dt->name->abstract)
227+
return 0;
228+
if (jl_is_tuple_type(dt) || jl_is_namedtuple_type(dt))
227229
return 0; // TODO: relax more?
228230
jl_svec_t *types = jl_get_fieldtypes(dt);
229231
size_t i, l = jl_svec_len(types);
@@ -242,9 +244,10 @@ int jl_type_mappable_to_c(jl_value_t *ty)
242244
assert(!jl_is_typevar(ty) && jl_is_type(ty));
243245
if (jl_is_structtype(ty)) {
244246
jl_datatype_t *jst = (jl_datatype_t*)ty;
245-
return jst->layout || jl_has_fixed_layout(jst);
247+
return jl_has_fixed_layout(jst);
246248
}
247-
if (jl_is_tuple_type(jl_unwrap_unionall(ty)))
249+
ty = jl_unwrap_unionall(ty);
250+
if (jl_is_tuple_type(ty) || jl_is_namedtuple_type(ty))
248251
return 0; // TODO: relax some?
249252
return 1; // as boxed or primitive
250253
}
@@ -1437,7 +1440,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
14371440
jl_gc_wb(ndt, ndt->parameters);
14381441
ndt->types = NULL; // to be filled in below
14391442
if (istuple) {
1440-
ndt->types = p;
1443+
ndt->types = p; // TODO: this may need to filter out certain types
14411444
}
14421445
else if (isnamedtuple) {
14431446
jl_value_t *names_tup = jl_svecref(p, 0);
@@ -1463,7 +1466,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
14631466
jl_gc_wb(ndt, ndt->types);
14641467
}
14651468
else {
1466-
ndt->types = jl_emptysvec;
1469+
ndt->types = jl_emptysvec; // XXX: this is essentially always false
14671470
}
14681471
}
14691472
ndt->size = 0;

src/julia_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz)
388388
return jl_gc_alloc(ptls, sz, (void*)jl_buff_tag);
389389
}
390390

391-
STATIC_INLINE jl_value_t *jl_gc_permobj(size_t sz, void *ty)
391+
STATIC_INLINE jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT
392392
{
393393
const size_t allocsz = sz + sizeof(jl_taggedvalue_t);
394394
unsigned align = (sz == 0 ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ?
@@ -539,6 +539,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a
539539
int jl_obviously_unequal(jl_value_t *a, jl_value_t *b);
540540
JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v);
541541
int jl_has_fixed_layout(jl_datatype_t *t);
542+
int jl_struct_try_layout(jl_datatype_t *dt);
542543
int jl_type_mappable_to_c(jl_value_t *ty);
543544
jl_svec_t *jl_outer_unionall_vars(jl_value_t *u);
544545
jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, int *issubty);

0 commit comments

Comments
 (0)