Skip to content

Commit

Permalink
8331734: Atomic MemorySegment VarHandle operations fails for element …
Browse files Browse the repository at this point in the history
…layouts

Reviewed-by: pminborg, psandoz
  • Loading branch information
mcimadamore committed May 10, 2024
1 parent 65abf24 commit 1c5f150
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package jdk.internal.foreign;

import jdk.internal.vm.annotation.ForceInline;

import java.lang.foreign.AddressLayout;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout;
Expand Down Expand Up @@ -204,10 +205,7 @@ public VarHandle dereferenceHandle(boolean adapt) {
String.format("Path does not select a value layout: %s", breadcrumbs()));
}

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

// we only have to check the alignment of the root layout for the first dereference we do,
Expand Down
28 changes: 18 additions & 10 deletions test/jdk/java/foreign/TestAccessModes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -29,11 +29,7 @@
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes
*/

import java.lang.foreign.AddressLayout;
import java.lang.foreign.Arena;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
Expand All @@ -50,21 +46,32 @@
public class TestAccessModes {

@Test(dataProvider = "segmentsAndLayoutsAndModes")
public void testAccessModes(MemorySegment segment, ValueLayout layout, AccessMode mode) throws Throwable {
VarHandle varHandle = layout.varHandle();
public void testAccessModes(MemorySegment segment, MemoryLayout layout, AccessMode mode) throws Throwable {
VarHandle varHandle = layout instanceof ValueLayout ?
layout.varHandle() :
layout.varHandle(MemoryLayout.PathElement.groupElement(0));
MethodHandle methodHandle = varHandle.toMethodHandle(mode);
boolean compatible = AccessModeKind.supportedModes(layout).contains(AccessModeKind.of(mode));
boolean compatible = AccessModeKind.supportedModes(accessLayout(layout)).contains(AccessModeKind.of(mode));
try {
Object o = methodHandle.invokeWithArguments(makeArgs(segment, varHandle.accessModeType(mode)));
assertTrue(compatible);
} catch (UnsupportedOperationException ex) {
assertFalse(compatible);
} catch (IllegalArgumentException ex) {
// access is unaligned, but access mode is supported
assertTrue(compatible);
assertTrue(compatible ||
(layout instanceof GroupLayout && segment.maxByteAlignment() < layout.byteAlignment()));
}
}

static ValueLayout accessLayout(MemoryLayout layout) {
return switch (layout) {
case ValueLayout vl -> vl;
case GroupLayout gl -> accessLayout(gl.memberLayouts().get(0));
default -> throw new IllegalStateException();
};
}

Object[] makeArgs(MemorySegment segment, MethodType type) throws Throwable {
List<Object> args = new ArrayList<>();
args.add(segment);
Expand Down Expand Up @@ -145,6 +152,7 @@ static MemoryLayout[] layouts() {
for (MemoryLayout layout : valueLayouts) {
for (int align : new int[] { 1, 2, 4, 8 }) {
layouts.add(layout.withByteAlignment(align));
layouts.add(MemoryLayout.structLayout(layout.withByteAlignment(align)));
}
}
return layouts.toArray(new MemoryLayout[0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -23,6 +23,7 @@
package org.openjdk.bench.java.lang.foreign;

import java.lang.foreign.Arena;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;

import org.openjdk.jmh.annotations.Benchmark;
Expand All @@ -37,6 +38,8 @@
import org.openjdk.jmh.annotations.Warmup;
import sun.misc.Unsafe;

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

static final VarHandle VH_SEQ_INT = bindToZeroOffset(MemoryLayout.sequenceLayout(ELEM_SIZE, JAVA_INT).varHandle(PathElement.sequenceElement()));
static final VarHandle VH_SEQ_INT_UNALIGNED = bindToZeroOffset(MemoryLayout.sequenceLayout(ELEM_SIZE, JAVA_INT.withByteAlignment(1)).varHandle(PathElement.sequenceElement()));

static VarHandle bindToZeroOffset(VarHandle varHandle) {
return MethodHandles.insertCoordinates(varHandle, 1, 0L);
}

Arena arena;
MemorySegment segment;
long unsafe_addr;
Expand Down Expand Up @@ -132,6 +142,24 @@ public int segment_loop_unaligned() {
return sum;
}

@Benchmark
public int segment_loop_nested() {
int sum = 0;
for (int i = 0; i < ELEM_SIZE; i++) {
sum += (int) VH_SEQ_INT.get(segment, (long) i);
}
return sum;
}

@Benchmark
public int segment_loop_nested_unaligned() {
int sum = 0;
for (int i = 0; i < ELEM_SIZE; i++) {
sum += (int) VH_SEQ_INT_UNALIGNED.get(segment, (long) i);
}
return sum;
}

@Benchmark
public int segment_loop_instance() {
int sum = 0;
Expand Down

1 comment on commit 1c5f150

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.