memorylayouts padding, jextract C_BOOL
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Fri Jan 31 16:15:49 UTC 2020
For the records - filed:
https://bugs.openjdk.java.net/browse/JDK-8238325
https://bugs.openjdk.java.net/browse/JDK-8238320
https://bugs.openjdk.java.net/browse/JDK-8238316
Thanks
Maurizio
On 31/01/2020 15:48, Maurizio Cimadamore wrote:
> This is odd -I'd expect a C_BYTE, not a C_BOOL. There must be a bug
> somewhere - I hope not in libclang reporting the wrong type - we'll
> look into it.
>
> The alignment issues you report are also odd, and I agree that having
> padding alignment be 8 bits always would be a better solution,
> although I'm not sure that's the only issue you are seeing there.
>
> Thanks for the reports - some comments inline
>
> Maurizio
>
> On 31/01/2020 08:08, Michael Zucchi wrote:
>>
>> Hi guys,
>>
>> I just noticed jextract turns a 'char' into a C_BOOL. I suppose it
>> doesn't make a difference but it just looks wrong. _Bool exists in
>> C99+ but an 8 bit int is more likely to be a int8_t or char than
>> _Bool (imo). I think the whole idea of 'c named types' just isn't
>> adding any value and they should all be basically the "stdint.h"
>> types with the platform byte ordering, but it's no big deal. The
>> scoped allocator sort of muddies it further by using java types, but
>> at least they have defined sizes which map to fixed stdint types.
>>
>> Also, this:
>>
>> struct foo {
>> char x;
>> int v __attribute__ ((aligned(8)));
>> };
>>
>> generates:
>>
>> public static final MemoryLayout foo$LAYOUT = MemoryLayout.ofStruct(
>> MemoryLayouts.SysV.C_BOOL.withName("x"),
>> MemoryLayout.ofPaddingBits(56),
>> MemoryLayouts.SysV.C_INT.withName("v"),
>> MemoryLayout.ofPaddingBits(32)
>> ).withName("foo");
> This seems already wrong - that is, the alignment constraint is not
> reflected in the layout (you can specify custom alignment on a layout
> using the MemoryLayout::withBitAlignment method) but that doesn't seem
> to happen here.
>>
>> which breaks at this:
>>
>> MemorySegment seg = MemorySegment.allocateNative(foo);
>>
>> Exception in thread "main" java.lang.IllegalArgumentException:
>> Invalid alignment constraint : 7
>> at
>> jdk.incubator.foreign/jdk.incubator.foreign.MemorySegment.allocateNative(MemorySegment.java:422)
>> at
>> jdk.incubator.foreign/jdk.incubator.foreign.MemorySegment.allocateNative(MemorySegment.java:360)
>> at notzed...
>>
>> This is because MemoryLayou8ts.ofPaddingBits(X) creates a padding of
>> "X" bits with "X" bit alignment, which is just not likely to work in
>> the general case.
>
> The exception occurs because the byte size is 16, while the byte
> alignment (the max alignment in the struct) is 7. So, alignment is not
> a power of two. As you say, the issue here is the fact that the
> inferred layout for padding is wrong and interferes with the alignment
> computation for the overall layout. Two solutions:
>
> - force align padding to 8 always
> - skip padding layouts when computing compound layout alignments
>
>
>> I hit this trying to use padding to skip private/unimportant fields
>> (by using large bit paddings) and then recreated the problem using
>> jextract.
>>
>> Given it's specifically padding which almost by definition isn't
>> aligned, maybe padding alignment bits should always just be 8? Or
>> just provide the alignment argument in MemoryLayout.ofPaddingBits()
>> so you don't have to call.withBitAligment(8) every time (this
>> currently works).
> Yeah - this seems good; in fact I'm thinking that perhaps padding bits
> should always come with 8-bit alignment, regardless of the size, so as
> not to interfere with the computations we do.
>>
>> From .withBitAlignment() javadoc it seems the alignment has to be >=8
>> and 2^n so that means the MemoryLayouts.ofPaddingBits()
>> implementation is incorrect in passing X as the alignment to new
>> PaddingLayout().
>>
>> /**
>> * Creates a new layout which features the desired alignment
>> constraint.
>> *
>> * @param bitAlignment the layout alignment constraint, expressed
>> in bits.
>> * @return a new layout which is the same as this layout, except
>> for the alignment constraint associated to it.
>> * @throws IllegalArgumentException if {@code bitAlignment} is
>> not a power of two, or if it's less than than 8.
>> */
>> MemoryLayout withBitAlignment(long bitAlignment);
>>
>> But other functions say it can be < 8 bits so it's a little messy
>> here. If it's intended for describing bitfields well it doesn't
>> really fit the api constraints, and for bitfields you'd want a bit
>> alignment of 1 by definition.
> I agree docs should be cleaned up here. In general, I think >= 8
> should be enforced everywhere. Bitfields are implemented by doing a
> get/set of a bigger word and then doing bitmask manipulation on it -
> while originally we had some desire to capture this bitfield layout in
> the layout API itself, I'm not 100% sure it's the right way to go -
> this was an issue that was put on the sideline as we were working on
> the memory access API, and I think we should re-assess and make sure
> the API specifies constraints that are consistent in spirit.
>>
>> Also note that this however /does/ work:
>>
>> struct foo {
>> char x;
>> long v;
>> };
>>
>> public static final MemoryLayout foo$LAYOUT = MemoryLayout.ofStruct(
>> MemoryLayouts.SysV.C_BOOL.withName("x"),
>> MemoryLayout.ofPaddingBits(56),
>> MemoryLayouts.SysV.C_LONG.withName("v"),
>> ).withName("foo");
>>
>> Which doesn't make any sense if the padding alignment really was 56??
>
> That's because the alignment of the struct is inferred (where not
> provided) to be the MAX alignment of all the components. You have a
> LONG here which means 64 beats 56. So the struct is 8-byte aligned,
> which is fine.
>
> Maurizio
>
>
>>
>> Cheers,
>> Z
>>
>>
>>
>>
More information about the panama-dev
mailing list