Skip to content

Commit 2372aba

Browse files
committed
8326172: Dubious claim on long[]/double[] alignment in MemorySegment javadoc
Reviewed-by: mcimadamore
1 parent c653e67 commit 2372aba

File tree

10 files changed

+44
-49
lines changed

10 files changed

+44
-49
lines changed

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

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,7 @@
305305
* and/or garbage collection behavior).
306306
* <p>
307307
* In practice, the Java runtime lays out arrays in memory so that each n-byte element
308-
* occurs at an n-byte aligned physical address (except for {@code long[]} and
309-
* {@code double[]}, where alignment is platform-dependent, as explained below). The
308+
* occurs at an n-byte aligned physical address. The
310309
* runtime preserves this invariant even if the array is relocated during garbage
311310
* collection. Access operations rely on this invariant to determine if the specified
312311
* offset in a heap segment refers to an aligned address in physical memory.
@@ -325,26 +324,17 @@
325324
* would correspond to physical address 1008 but offset 4 would correspond to
326325
* physical address 1010.</li>
327326
* <li>The starting physical address of a {@code long[]} array will be 8-byte aligned
328-
* (e.g. 1000) on 64-bit platforms, so that successive long elements occur at
329-
* 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms,
330-
* a heap segment backed by a {@code long[]} array can be accessed at offsets
331-
* 0, 8, 16, 24, etc under an 8-byte alignment constraint. In addition, the segment
332-
* can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
333-
* because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And,
334-
* the segment can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment
335-
* constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are
336-
* 2-byte aligned.</li>
337-
* <li>The starting physical address of a {@code long[]} array will be 4-byte aligned
338-
* (e.g. 1004) on 32-bit platforms, so that successive long elements occur at 4-byte
339-
* aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit platforms, a heap
340-
* segment backed by a {@code long[]} array can be accessed at offsets
341-
* 0, 4, 8, 12, etc under a 4-byte alignment constraint, because the target addresses
342-
* (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment can be accessed at
343-
* offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target
344-
* addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.</li>
327+
* (e.g. 1000), so that successive long elements occur at 8-byte aligned addresses
328+
* (e.g., 1000, 1008, 1016, 1024, etc.) A heap segment backed by a {@code long[]}
329+
* array can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment
330+
* constraint. In addition, the segment can be accessed at offsets 0, 4, 8, 12,
331+
* etc under a 4-byte alignment constraint, because the target addresses (1000, 1004,
332+
* 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets 0, 2,
333+
* 4, 6, etc under a 2-byte alignment constraint, because the target addresses (e.g.
334+
* 1000, 1002, 1004, 1006) are 2-byte aligned.</li>
345335
* </ul>
346336
* <p>
347-
* In other words, heap segments feature a (platform-dependent) <em>maximum</em>
337+
* In other words, heap segments feature a <em>maximum</em>
348338
* alignment which is derived from the size of the elements of the Java array backing the
349339
* segment, as shown in the following table:
350340
*
@@ -389,10 +379,7 @@
389379
* In such circumstances, clients have two options. They can use a heap segment backed
390380
* by a different array type (e.g. {@code long[]}), capable of supporting greater maximum
391381
* alignment. More specifically, the maximum alignment associated with {@code long[]} is
392-
* set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent
393-
* value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is
394-
* guaranteed to provide at least 8-byte alignment in 64-bit platforms, but only 4-byte
395-
* alignment in 32-bit platforms:
382+
* set to {@code ValueLayout.JAVA_LONG.byteAlignment()}, which is 8 bytes:
396383
*
397384
* {@snippet lang=java :
398385
* MemorySegment longSegment = MemorySegment.ofArray(new long[10]);

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@
4747
* For instance, the byte order of these constants is set to the
4848
* {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy
4949
* to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}.
50-
* Moreover, the alignment constraint of {@link ValueLayout#JAVA_LONG} and
51-
* {@link ValueLayout#JAVA_DOUBLE} is set to 8 bytes on 64-bit platforms,
52-
* but only to 4 bytes on 32-bit platforms.
5350
*
5451
* @implSpec implementing classes and subclasses are immutable, thread-safe and
5552
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.

src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@
4949
abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
5050

5151
// Constants defining the maximum alignment supported by various kinds of heap arrays.
52-
// While for most arrays, the maximum alignment is constant (the size, in bytes, of the array elements),
53-
// note that the alignment of a long[]/double[] depends on the platform: it's 4-byte on x86, but 8 bytes on x64
54-
// (as specified by the JAVA_LONG layout constant).
5552

5653
private static final long MAX_ALIGN_BYTE_ARRAY = ValueLayout.JAVA_BYTE.byteAlignment();
5754
private static final long MAX_ALIGN_SHORT_ARRAY = ValueLayout.JAVA_SHORT.byteAlignment();

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,8 @@ class Holder {
307307
Map.entry("bool", JAVA_BOOLEAN),
308308
Map.entry("char", JAVA_BYTE),
309309
Map.entry("float", JAVA_FLOAT),
310-
Map.entry("long long", JAVA_LONG),
311-
Map.entry("double", JAVA_DOUBLE),
310+
Map.entry("long long", JAVA_LONG.withByteAlignment(LibFallback.longLongAlign())),
311+
Map.entry("double", JAVA_DOUBLE.withByteAlignment(LibFallback.doubleAlign())),
312312
Map.entry("void*", ADDRESS),
313313
// platform-dependent sizes
314314
Map.entry("size_t", FFIType.SIZE_T),

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public Boolean run() {
7373
static int intSize() { return NativeConstants.SIZEOF_INT; }
7474
static int longSize() {return NativeConstants.SIZEOF_LONG; }
7575
static int wcharSize() {return NativeConstants.SIZEOF_WCHAR; }
76+
static int longLongAlign() { return NativeConstants.ALIGNOF_LONG_LONG; }
77+
static int doubleAlign() { return NativeConstants.ALIGNOF_DOUBLE; }
7678

7779
static short structTag() { return NativeConstants.STRUCT_TAG; }
7880

@@ -242,6 +244,9 @@ private static native void doDowncall(long cif, long fn, long rvalue, long avalu
242244
private static native int ffi_sizeof_long();
243245
private static native int ffi_sizeof_wchar();
244246

247+
private static native int alignof_long_long();
248+
private static native int alignof_double();
249+
245250
// put these in a separate class to avoid an UnsatisfiedLinkError
246251
// when LibFallback is initialized but the library is not present
247252
private static final class NativeConstants {
@@ -263,6 +268,8 @@ private NativeConstants() {}
263268
static final int SIZEOF_LONG = ffi_sizeof_long();
264269
static final int SIZEOF_WCHAR = ffi_sizeof_wchar();
265270

271+
static final int ALIGNOF_LONG_LONG = alignof_long_long();
272+
static final int ALIGNOF_DOUBLE = alignof_double();
266273

267274
static final MemorySegment VOID_TYPE = MemorySegment.ofAddress(ffi_type_void());
268275
static final short STRUCT_TAG = ffi_type_struct();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ OfLongImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
278278
}
279279

280280
public static OfLong of(ByteOrder order) {
281-
return new OfLongImpl(order, ADDRESS_SIZE_BYTES, Optional.empty());
281+
return new OfLongImpl(order, Long.BYTES, Optional.empty());
282282
}
283283
}
284284

@@ -294,7 +294,7 @@ OfDoubleImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
294294
}
295295

296296
public static OfDouble of(ByteOrder order) {
297-
return new OfDoubleImpl(order, ADDRESS_SIZE_BYTES, Optional.empty());
297+
return new OfDoubleImpl(order, Double.BYTES, Optional.empty());
298298
}
299299

300300
}

src/java.base/share/native/libfallbackLinker/fallbackLinker.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <ffi.h>
2929

3030
#include <errno.h>
31+
#include <stdalign.h>
3132
#include <stdint.h>
3233
#include <stdlib.h>
3334
#include <wchar.h>
@@ -275,3 +276,13 @@ JNIEXPORT jint JNICALL
275276
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1sizeof_1wchar(JNIEnv* env, jclass cls) {
276277
return sizeof(wchar_t);
277278
}
279+
280+
JNIEXPORT jint JNICALL
281+
Java_jdk_internal_foreign_abi_fallback_LibFallback_alignof_1long_1long(JNIEnv* env, jclass cls) {
282+
return alignof(long long);
283+
}
284+
285+
JNIEXPORT jint JNICALL
286+
Java_jdk_internal_foreign_abi_fallback_LibFallback_alignof_1double(JNIEnv* env, jclass cls) {
287+
return alignof(double);
288+
}

test/jdk/java/foreign/TestLayouts.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public void testStructSizeAndAlign() {
161161
ValueLayout.JAVA_LONG
162162
);
163163
assertEquals(struct.byteSize(), 1 + 1 + 2 + 4 + 8);
164-
assertEquals(struct.byteAlignment(), ADDRESS.byteSize());
164+
assertEquals(struct.byteAlignment(), 8);
165165
}
166166

167167
@Test(dataProvider="basicLayouts")
@@ -192,7 +192,7 @@ public void testUnionSizeAndAlign() {
192192
ValueLayout.JAVA_LONG
193193
);
194194
assertEquals(struct.byteSize(), 8);
195-
assertEquals(struct.byteAlignment(), ADDRESS.byteSize());
195+
assertEquals(struct.byteAlignment(), 8);
196196
}
197197

198198
@Test
@@ -477,24 +477,24 @@ public Object[][] layoutsAndAlignments() {
477477
List<Object[]> layoutsAndAlignments = new ArrayList<>();
478478
int i = 0;
479479
//add basic layouts
480-
for (MemoryLayout l : basicLayoutsNoLongDouble) {
480+
for (MemoryLayout l : basicLayouts) {
481481
layoutsAndAlignments.add(new Object[] { l, l.byteAlignment() });
482482
}
483483
//add basic layouts wrapped in a sequence with given size
484-
for (MemoryLayout l : basicLayoutsNoLongDouble) {
484+
for (MemoryLayout l : basicLayouts) {
485485
layoutsAndAlignments.add(new Object[] { MemoryLayout.sequenceLayout(4, l), l.byteAlignment() });
486486
}
487487
//add basic layouts wrapped in a struct
488-
for (MemoryLayout l1 : basicLayoutsNoLongDouble) {
489-
for (MemoryLayout l2 : basicLayoutsNoLongDouble) {
488+
for (MemoryLayout l1 : basicLayouts) {
489+
for (MemoryLayout l2 : basicLayouts) {
490490
if (l1.byteSize() % l2.byteAlignment() != 0) continue; // second element is not aligned, skip
491491
long align = Math.max(l1.byteAlignment(), l2.byteAlignment());
492492
layoutsAndAlignments.add(new Object[]{MemoryLayout.structLayout(l1, l2), align});
493493
}
494494
}
495495
//add basic layouts wrapped in a union
496-
for (MemoryLayout l1 : basicLayoutsNoLongDouble) {
497-
for (MemoryLayout l2 : basicLayoutsNoLongDouble) {
496+
for (MemoryLayout l1 : basicLayouts) {
497+
for (MemoryLayout l2 : basicLayouts) {
498498
long align = Math.max(l1.byteAlignment(), l2.byteAlignment());
499499
layoutsAndAlignments.add(new Object[]{MemoryLayout.unionLayout(l1, l2), align});
500500
}
@@ -543,8 +543,4 @@ static Stream<MemoryLayout> groupLayoutStream() {
543543
ValueLayout.JAVA_LONG,
544544
ValueLayout.JAVA_DOUBLE,
545545
};
546-
547-
static MemoryLayout[] basicLayoutsNoLongDouble = Stream.of(basicLayouts)
548-
.filter(l -> l.carrier() != long.class && l.carrier() != double.class)
549-
.toArray(MemoryLayout[]::new);
550546
}

test/jdk/java/foreign/TestValueLayouts.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void testIntUnaligned() {
7070

7171
@Test
7272
public void testLong() {
73-
testAligned(JAVA_LONG, long.class, Long.BYTES, ADDRESS.byteSize());
73+
testAligned(JAVA_LONG, long.class, Long.BYTES, Long.BYTES);
7474
}
7575

7676
@Test
@@ -90,7 +90,7 @@ public void testFloatUnaligned() {
9090

9191
@Test
9292
public void testDouble() {
93-
testAligned(JAVA_DOUBLE, double.class, Double.BYTES, ADDRESS.byteSize());
93+
testAligned(JAVA_DOUBLE, double.class, Double.BYTES, Double.BYTES);
9494
}
9595

9696
@Test

test/jdk/java/foreign/stackwalk/TestReentrantUpcalls.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static void main(String[] args) throws Throwable {
7676
}
7777

7878
static void m(int depth, MemorySegment thisStub, MethodHandle downcallHandle) throws Throwable {
79-
if (depth < 100) {
79+
if (depth < 50) {
8080
downcallHandle.invokeExact(depth + 1, thisStub);
8181
} else {
8282
WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/true);

0 commit comments

Comments
 (0)