Skip to content

Commit

Permalink
fix JuliaLang#37974, struct layout of odd-size primitive types (Julia…
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson committed Oct 26, 2020
1 parent f6b51ab commit c3c4dab
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 7 deletions.
2 changes: 1 addition & 1 deletion base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ function sizeof_tfunc(@nospecialize(x),)
x = unwrap_unionall(t)
if exact && isa(x, Union)
isinline, sz, _ = uniontype_layout(x)
return isinline ? Const(Int(sz)) : Bottom
return isinline ? Const(Int(Core.sizeof(x))) : Bottom
end
isa(x, DataType) || return Int
(isconcretetype(x) || isprimitivetype(x)) && return _const_sizeof(x)
Expand Down
4 changes: 2 additions & 2 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,8 @@ JL_CALLABLE(jl_f_sizeof)
jl_value_t *x = args[0];
if (jl_is_unionall(x) || jl_is_uniontype(x)) {
x = jl_unwrap_unionall(x);
size_t elsize = 0, al = 0;
int isinline = jl_islayout_inline(x, &elsize, &al);
size_t elsize = 0;
int isinline = jl_uniontype_size(x, &elsize);
if (isinline)
return jl_box_long(elsize);
if (!jl_is_datatype(x))
Expand Down
17 changes: 13 additions & 4 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,20 +235,23 @@ STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st)
}
}

static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align) JL_NOTSAFEPOINT
static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align, int asfield) JL_NOTSAFEPOINT
{
if (jl_is_uniontype(ty)) {
unsigned na = union_isinlinable(((jl_uniontype_t*)ty)->a, 1, nbytes, align);
unsigned na = union_isinlinable(((jl_uniontype_t*)ty)->a, 1, nbytes, align, asfield);
if (na == 0)
return 0;
unsigned nb = union_isinlinable(((jl_uniontype_t*)ty)->b, 1, nbytes, align);
unsigned nb = union_isinlinable(((jl_uniontype_t*)ty)->b, 1, nbytes, align, asfield);
if (nb == 0)
return 0;
return na + nb;
}
if (jl_is_datatype(ty) && jl_datatype_isinlinealloc(ty) && (!pointerfree || ((jl_datatype_t*)ty)->layout->npointers == 0)) {
size_t sz = jl_datatype_size(ty);
size_t al = jl_datatype_align(ty);
// primitive types in struct slots need their sizes aligned. issue #37974
if (asfield && jl_is_primitivetype(ty))
sz = LLT_ALIGN(sz, al);
if (*nbytes < sz)
*nbytes = sz;
if (*align < al)
Expand All @@ -258,9 +261,15 @@ static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbyte
return 0;
}

int jl_uniontype_size(jl_value_t *ty, size_t *sz) JL_NOTSAFEPOINT
{
size_t al = 0;
return union_isinlinable(ty, 0, sz, &al, 0) != 0;
}

JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al) JL_NOTSAFEPOINT
{
unsigned countbits = union_isinlinable(eltype, 0, fsz, al);
unsigned countbits = union_isinlinable(eltype, 0, fsz, al, 1);
return (countbits > 0 && countbits < 127) ? countbits : 0;
}

Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,7 @@ JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i,
JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i) JL_NOTSAFEPOINT;
JL_DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, const char *fld);
JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a);
int jl_uniontype_size(jl_value_t *ty, size_t *sz) JL_NOTSAFEPOINT;
JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al) JL_NOTSAFEPOINT;

// arrays
Expand Down
12 changes: 12 additions & 0 deletions test/compiler/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,15 @@ end
let f(@nospecialize(x)) = x===Base.ImmutableDict(Int128=>:big)
@test !f(Dict(Int=>Int))
end

# issue #37974
primitive type UInt24 24 end
let a = Core.Intrinsics.trunc_int(UInt24, 3),
f(t) = t[2]
@test f((a, true)) === true
@test f((a, false)) === false
@test sizeof(Tuple{UInt24,Bool}) == 8
@test sizeof(UInt24) == 3
@test sizeof(Union{UInt8,UInt24}) == 3
@test sizeof(Base.RefValue{Union{UInt8,UInt24}}) == 8
end

0 comments on commit c3c4dab

Please sign in to comment.