Skip to content

Commit 1c5f150

Browse files
committed
8331734: Atomic MemorySegment VarHandle operations fails for element layouts
Reviewed-by: pminborg, psandoz
1 parent 65abf24 commit 1c5f150

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package jdk.internal.foreign;
2727

2828
import jdk.internal.vm.annotation.ForceInline;
29+
2930
import java.lang.foreign.AddressLayout;
3031
import java.lang.foreign.GroupLayout;
3132
import java.lang.foreign.MemoryLayout;
@@ -204,10 +205,7 @@ public VarHandle dereferenceHandle(boolean adapt) {
204205
String.format("Path does not select a value layout: %s", breadcrumbs()));
205206
}
206207

207-
// If we have an enclosing layout, drop the alignment check for the accessed element,
208-
// we check the root layout instead
209-
ValueLayout accessedLayout = enclosing != null ? valueLayout.withByteAlignment(1) : valueLayout;
210-
VarHandle handle = accessedLayout.varHandle();
208+
VarHandle handle = valueLayout.varHandle();
211209
handle = MethodHandles.collectCoordinates(handle, 1, offsetHandle());
212210

213211
// we only have to check the alignment of the root layout for the first dereference we do,

test/jdk/java/foreign/TestAccessModes.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2024, 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
@@ -29,11 +29,7 @@
2929
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes
3030
*/
3131

32-
import java.lang.foreign.AddressLayout;
33-
import java.lang.foreign.Arena;
34-
import java.lang.foreign.MemoryLayout;
35-
import java.lang.foreign.MemorySegment;
36-
import java.lang.foreign.ValueLayout;
32+
import java.lang.foreign.*;
3733
import java.lang.invoke.MethodHandle;
3834
import java.lang.invoke.MethodHandles;
3935
import java.lang.invoke.MethodType;
@@ -50,21 +46,32 @@
5046
public class TestAccessModes {
5147

5248
@Test(dataProvider = "segmentsAndLayoutsAndModes")
53-
public void testAccessModes(MemorySegment segment, ValueLayout layout, AccessMode mode) throws Throwable {
54-
VarHandle varHandle = layout.varHandle();
49+
public void testAccessModes(MemorySegment segment, MemoryLayout layout, AccessMode mode) throws Throwable {
50+
VarHandle varHandle = layout instanceof ValueLayout ?
51+
layout.varHandle() :
52+
layout.varHandle(MemoryLayout.PathElement.groupElement(0));
5553
MethodHandle methodHandle = varHandle.toMethodHandle(mode);
56-
boolean compatible = AccessModeKind.supportedModes(layout).contains(AccessModeKind.of(mode));
54+
boolean compatible = AccessModeKind.supportedModes(accessLayout(layout)).contains(AccessModeKind.of(mode));
5755
try {
5856
Object o = methodHandle.invokeWithArguments(makeArgs(segment, varHandle.accessModeType(mode)));
5957
assertTrue(compatible);
6058
} catch (UnsupportedOperationException ex) {
6159
assertFalse(compatible);
6260
} catch (IllegalArgumentException ex) {
6361
// access is unaligned, but access mode is supported
64-
assertTrue(compatible);
62+
assertTrue(compatible ||
63+
(layout instanceof GroupLayout && segment.maxByteAlignment() < layout.byteAlignment()));
6564
}
6665
}
6766

67+
static ValueLayout accessLayout(MemoryLayout layout) {
68+
return switch (layout) {
69+
case ValueLayout vl -> vl;
70+
case GroupLayout gl -> accessLayout(gl.memberLayouts().get(0));
71+
default -> throw new IllegalStateException();
72+
};
73+
}
74+
6875
Object[] makeArgs(MemorySegment segment, MethodType type) throws Throwable {
6976
List<Object> args = new ArrayList<>();
7077
args.add(segment);
@@ -145,6 +152,7 @@ static MemoryLayout[] layouts() {
145152
for (MemoryLayout layout : valueLayouts) {
146153
for (int align : new int[] { 1, 2, 4, 8 }) {
147154
layouts.add(layout.withByteAlignment(align));
155+
layouts.add(MemoryLayout.structLayout(layout.withByteAlignment(align)));
148156
}
149157
}
150158
return layouts.toArray(new MemoryLayout[0]);

test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstant.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2024, 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
@@ -23,6 +23,7 @@
2323
package org.openjdk.bench.java.lang.foreign;
2424

2525
import java.lang.foreign.Arena;
26+
import java.lang.foreign.MemoryLayout;
2627
import java.lang.foreign.MemorySegment;
2728

2829
import org.openjdk.jmh.annotations.Benchmark;
@@ -37,6 +38,8 @@
3738
import org.openjdk.jmh.annotations.Warmup;
3839
import sun.misc.Unsafe;
3940

41+
import java.lang.invoke.MethodHandles;
42+
import java.lang.invoke.VarHandle;
4043
import java.nio.ByteBuffer;
4144
import java.nio.ByteOrder;
4245
import java.util.concurrent.TimeUnit;
@@ -57,6 +60,13 @@ public class LoopOverNonConstant extends JavaLayouts {
5760
static final int CARRIER_SIZE = (int)JAVA_INT.byteSize();
5861
static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE;
5962

63+
static final VarHandle VH_SEQ_INT = bindToZeroOffset(MemoryLayout.sequenceLayout(ELEM_SIZE, JAVA_INT).varHandle(PathElement.sequenceElement()));
64+
static final VarHandle VH_SEQ_INT_UNALIGNED = bindToZeroOffset(MemoryLayout.sequenceLayout(ELEM_SIZE, JAVA_INT.withByteAlignment(1)).varHandle(PathElement.sequenceElement()));
65+
66+
static VarHandle bindToZeroOffset(VarHandle varHandle) {
67+
return MethodHandles.insertCoordinates(varHandle, 1, 0L);
68+
}
69+
6070
Arena arena;
6171
MemorySegment segment;
6272
long unsafe_addr;
@@ -132,6 +142,24 @@ public int segment_loop_unaligned() {
132142
return sum;
133143
}
134144

145+
@Benchmark
146+
public int segment_loop_nested() {
147+
int sum = 0;
148+
for (int i = 0; i < ELEM_SIZE; i++) {
149+
sum += (int) VH_SEQ_INT.get(segment, (long) i);
150+
}
151+
return sum;
152+
}
153+
154+
@Benchmark
155+
public int segment_loop_nested_unaligned() {
156+
int sum = 0;
157+
for (int i = 0; i < ELEM_SIZE; i++) {
158+
sum += (int) VH_SEQ_INT_UNALIGNED.get(segment, (long) i);
159+
}
160+
return sum;
161+
}
162+
135163
@Benchmark
136164
public int segment_loop_instance() {
137165
int sum = 0;

0 commit comments

Comments
 (0)