Skip to content

Commit 477cc26

Browse files
committed
8299181: PaddingLayout unable to return byteAlignment value
Reviewed-by: mcimadamore
1 parent cad8645 commit 477cc26

File tree

9 files changed

+89
-122
lines changed

9 files changed

+89
-122
lines changed

src/java.base/share/classes/java/lang/foreign/MemoryLayout.java

+9-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
3636
import java.util.function.Function;
3737
import java.util.function.Supplier;
3838
import java.util.stream.Stream;
39+
3940
import jdk.internal.foreign.LayoutPath;
4041
import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
4142
import jdk.internal.foreign.Utils;
@@ -235,10 +236,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
235236
* @return the layout alignment constraint, in bytes.
236237
* @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
237238
*/
238-
default long byteAlignment() {
239-
return Utils.bitsToBytesOrThrow(bitAlignment(),
240-
() -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8"));
241-
}
239+
long byteAlignment();
242240

243241
/**
244242
* Returns a memory layout of the same type with the same size and name as this layout,
@@ -611,15 +609,14 @@ static PathElement sequenceElement() {
611609
String toString();
612610

613611
/**
614-
* Creates a padding layout with the given size.
612+
* Creates a padding layout with the given bitSize and a bit-alignment of eight.
615613
*
616-
* @param size the padding size in bits.
614+
* @param bitSize the padding size in bits.
617615
* @return the new selector layout.
618-
* @throws IllegalArgumentException if {@code size <= 0}.
616+
* @throws IllegalArgumentException if {@code bitSize < 0} or {@code bitSize % 8 != 0}
619617
*/
620-
static PaddingLayout paddingLayout(long size) {
621-
MemoryLayoutUtil.checkSize(size);
622-
return PaddingLayoutImpl.of(size);
618+
static PaddingLayout paddingLayout(long bitSize) {
619+
return PaddingLayoutImpl.of(MemoryLayoutUtil.requireBitSizeValid(bitSize));
623620
}
624621

625622
/**
@@ -676,7 +673,7 @@ static ValueLayout valueLayout(Class<?> carrier, ByteOrder order) {
676673
* @throws IllegalArgumentException if {@code elementCount } is negative.
677674
*/
678675
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
679-
MemoryLayoutUtil.checkSize(elementCount, true);
676+
MemoryLayoutUtil.requireNonNegative(elementCount);
680677
Objects.requireNonNull(elementLayout);
681678
return wrapOverflow(() ->
682679
SequenceLayoutImpl.of(elementCount, elementLayout));

src/java.base/share/classes/java/lang/foreign/ValueLayout.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -49,6 +49,7 @@
4949
*
5050
* @implSpec implementing classes and subclasses are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
5151
*
52+
* @sealedGraph
5253
* @since 19
5354
*/
5455
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)

src/java.base/share/classes/jdk/internal/foreign/layout/AbstractGroupLayout.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -145,7 +145,7 @@ long alignof(List<MemoryLayout> elems) {
145145
return elems.stream()
146146
.mapToLong(MemoryLayout::bitAlignment)
147147
.max() // max alignment in case we have member layouts
148-
.orElse(1); // or minimal alignment if no member layout is given
148+
.orElse(8); // or minimal alignment if no member layout is given
149149
}
150150
}
151151
}

src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java

+24-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,6 @@
2525
*/
2626
package jdk.internal.foreign.layout;
2727

28-
import jdk.internal.foreign.Utils;
29-
import jdk.internal.vm.annotation.ForceInline;
30-
import jdk.internal.vm.annotation.Stable;
31-
3228
import java.lang.foreign.GroupLayout;
3329
import java.lang.foreign.MemoryLayout;
3430
import java.lang.foreign.SequenceLayout;
@@ -41,51 +37,47 @@
4137
public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & MemoryLayout>
4238
permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout {
4339

44-
private final long bitSize;
45-
private final long bitAlignment;
40+
private final long byteSize;
41+
private final long byteAlignment;
4642
private final Optional<String> name;
47-
@Stable
48-
private long byteSize;
4943

5044
AbstractLayout(long bitSize, long bitAlignment, Optional<String> name) {
51-
this.bitSize = bitSize;
52-
this.bitAlignment = bitAlignment;
53-
this.name = name;
45+
this.byteSize = MemoryLayoutUtil.requireBitSizeValid(bitSize) / 8;
46+
this.byteAlignment = requirePowerOfTwoAndGreaterOrEqualToEight(bitAlignment) / 8;
47+
this.name = Objects.requireNonNull(name);
5448
}
5549

5650
public final L withName(String name) {
5751
Objects.requireNonNull(name);
58-
return dup(bitAlignment, Optional.of(name));
52+
return dup(bitAlignment(), Optional.of(name));
5953
}
6054

6155
public final Optional<String> name() {
6256
return name;
6357
}
6458

6559
public final L withBitAlignment(long bitAlignment) {
66-
checkAlignment(bitAlignment);
6760
return dup(bitAlignment, name);
6861
}
6962

7063
public final long bitAlignment() {
71-
return bitAlignment;
64+
return byteAlignment * 8;
65+
}
66+
67+
public final long byteAlignment() {
68+
return byteAlignment;
7269
}
7370

74-
@ForceInline
7571
public final long byteSize() {
76-
if (byteSize == 0) {
77-
byteSize = Utils.bitsToBytesOrThrow(bitSize(),
78-
() -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
79-
}
8072
return byteSize;
8173
}
8274

8375
public final long bitSize() {
84-
return bitSize;
76+
return byteSize * 8;
8577
}
8678

8779
public boolean hasNaturalAlignment() {
88-
return bitSize == bitAlignment;
80+
return byteSize == byteAlignment;
8981
}
9082

9183
// the following methods have to copy the same Javadoc as in MemoryLayout, or subclasses will just show
@@ -96,7 +88,7 @@ public boolean hasNaturalAlignment() {
9688
*/
9789
@Override
9890
public int hashCode() {
99-
return Objects.hash(name, bitSize, bitAlignment);
91+
return Objects.hash(name, byteSize, byteAlignment);
10092
}
10193

10294
/**
@@ -124,13 +116,14 @@ public boolean equals(Object other) {
124116

125117
return other instanceof AbstractLayout<?> otherLayout &&
126118
name.equals(otherLayout.name) &&
127-
bitSize == otherLayout.bitSize &&
128-
bitAlignment == otherLayout.bitAlignment;
119+
byteSize == otherLayout.byteSize &&
120+
byteAlignment == otherLayout.byteAlignment;
129121
}
130122

131123
/**
132124
* {@return the string representation of this layout}
133125
*/
126+
@Override
134127
public abstract String toString();
135128

136129
abstract L dup(long alignment, Optional<String> name);
@@ -140,17 +133,17 @@ String decorateLayoutString(String s) {
140133
s = String.format("%s(%s)", s, name().get());
141134
}
142135
if (!hasNaturalAlignment()) {
143-
s = bitAlignment + "%" + s;
136+
s = bitAlignment() + "%" + s;
144137
}
145138
return s;
146139
}
147140

148-
private static void checkAlignment(long alignmentBitCount) {
149-
if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
150-
(alignmentBitCount < 8)) { //alignment must be greater than 8
151-
throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
141+
private static long requirePowerOfTwoAndGreaterOrEqualToEight(long value) {
142+
if (((value & (value - 1)) != 0L) || // value must be a power of two
143+
(value < 8)) { // value must be greater or equal to 8
144+
throw new IllegalArgumentException("Invalid alignment: " + value);
152145
}
146+
return value;
153147
}
154148

155-
156149
}

src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -30,14 +30,18 @@ public final class MemoryLayoutUtil {
3030
private MemoryLayoutUtil() {
3131
}
3232

33-
public static void checkSize(long size) {
34-
checkSize(size, false);
33+
public static long requireNonNegative(long value) {
34+
if (value < 0) {
35+
throw new IllegalArgumentException("The provided value was negative: " + value);
36+
}
37+
return value;
3538
}
3639

37-
public static void checkSize(long size, boolean includeZero) {
38-
if (size < 0 || (!includeZero && size == 0)) {
39-
throw new IllegalArgumentException("Invalid size for layout: " + size);
40+
public static long requireBitSizeValid(long bitSize) {
41+
if (bitSize < 0 || bitSize % 8 != 0) {
42+
throw new IllegalArgumentException("Invalid bitSize: " + bitSize);
4043
}
44+
return bitSize;
4145
}
4246

4347
}

src/java.base/share/classes/jdk/internal/foreign/layout/PaddingLayoutImpl.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
3232
public final class PaddingLayoutImpl extends AbstractLayout<PaddingLayoutImpl> implements PaddingLayout {
3333

3434
private PaddingLayoutImpl(long bitSize) {
35-
this(bitSize, 1, Optional.empty());
35+
this(bitSize, 8, Optional.empty());
3636
}
3737

3838
private PaddingLayoutImpl(long bitSize, long bitAlignment, Optional<String> name) {

src/java.base/share/classes/jdk/internal/foreign/layout/SequenceLayoutImpl.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -68,7 +68,6 @@ public long elementCount() {
6868
* @throws IllegalArgumentException if {@code elementCount < 0}.
6969
*/
7070
public SequenceLayout withElementCount(long elementCount) {
71-
MemoryLayoutUtil.checkSize(elementCount, true);
7271
return new SequenceLayoutImpl(elementCount, elementLayout, bitAlignment(), name());
7372
}
7473

test/jdk/java/foreign/TestLayoutPaths.java

+3-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -168,25 +168,6 @@ public void testByteOffsetHandleBadRange() {
168168
seq.byteOffsetHandle(sequenceElement(0, 1)); // ranges not accepted
169169
}
170170

171-
@Test(expectedExceptions = UnsupportedOperationException.class)
172-
public void testBadMultiple() {
173-
GroupLayout g = MemoryLayout.structLayout(MemoryLayout.paddingLayout(3), JAVA_INT.withName("foo"));
174-
g.byteOffset(groupElement("foo"));
175-
}
176-
177-
@Test(expectedExceptions = UnsupportedOperationException.class)
178-
public void testBadByteOffsetNoMultipleOf8() {
179-
MemoryLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(7), JAVA_INT.withName("x"));
180-
layout.byteOffset(groupElement("x"));
181-
}
182-
183-
@Test(expectedExceptions = UnsupportedOperationException.class)
184-
public void testBadByteOffsetHandleNoMultipleOf8() throws Throwable {
185-
MemoryLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(7), JAVA_INT.withName("x"));
186-
MethodHandle handle = layout.byteOffsetHandle(groupElement("x"));
187-
handle.invoke();
188-
}
189-
190171
@Test
191172
public void testBadContainerAlign() {
192173
GroupLayout g = MemoryLayout.structLayout(JAVA_INT.withBitAlignment(16).withName("foo")).withBitAlignment(8);
@@ -364,10 +345,10 @@ public static Object[][] testLayouts() {
364345
(JAVA_INT.bitSize() * 2) * 4 + JAVA_INT.bitSize()
365346
});
366347
testCases.add(new Object[] {
367-
MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(5), JAVA_INT.withName("y"))),
348+
MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(8), JAVA_INT.withName("y"))),
368349
new PathElement[] { sequenceElement(), groupElement("y") },
369350
new long[] { 4 },
370-
(JAVA_INT.bitSize() + 5) * 4 + 5
351+
(JAVA_INT.bitSize() + 8) * 4 + 8
371352
});
372353
testCases.add(new Object[] {
373354
MemoryLayout.sequenceLayout(10, JAVA_INT),
@@ -441,45 +422,5 @@ public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, lon
441422
}
442423
}
443424

444-
@Test(expectedExceptions = UnsupportedOperationException.class)
445-
public void testSliceHandleUOEInvalidOffsetEager() throws Throwable {
446-
MemoryLayout layout = MemoryLayout.structLayout(
447-
MemoryLayout.paddingLayout(5),
448-
JAVA_INT.withName("y") // offset not a multiple of 8
449-
);
450-
451-
layout.sliceHandle(groupElement("y")); // should throw
452-
}
453-
454-
@Test(expectedExceptions = UnsupportedOperationException.class)
455-
public void testSliceHandleUOEInvalidOffsetLate() throws Throwable {
456-
MemoryLayout layout = MemoryLayout.sequenceLayout(3,
457-
MemoryLayout.structLayout(
458-
MemoryLayout.paddingLayout(4),
459-
JAVA_INT.withName("y") // offset not a multiple of 8
460-
)
461-
);
462-
463-
MethodHandle sliceHandle;
464-
try {
465-
sliceHandle = layout.sliceHandle(sequenceElement(), groupElement("y")); // should work
466-
} catch (UnsupportedOperationException uoe) {
467-
fail("Unexpected exception", uoe);
468-
return;
469-
}
470-
471-
try (Arena arena = Arena.openConfined()) {
472-
MemorySegment segment = MemorySegment.allocateNative(layout, arena.scope());
473-
474-
try {
475-
sliceHandle.invokeExact(segment, 1); // should work
476-
} catch (UnsupportedOperationException uoe) {
477-
fail("Unexpected exception", uoe);
478-
return;
479-
}
480-
481-
sliceHandle.invokeExact(segment, 0); // should throw
482-
}
483-
}
484425
}
485426

0 commit comments

Comments
 (0)