Skip to content
This repository has been archived by the owner. It is now read-only.

8279930: Synthetic cast causes generation of store barriers when using heap segments

Closed
Closed
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -266,7 +266,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
* <p>
* The returned spliterator splits this segment according to the specified element layout; that is,
* if the supplied layout has size N, then calling {@link Spliterator#trySplit()} will result in a spliterator serving
* approximately {@code S/N/2} elements (depending on whether N is even or not), where {@code S} is the size of
* approximately {@code S/N} elements (depending on whether N is even or not), where {@code S} is the size of
* this segment. As such, splitting is possible as long as {@code S/N >= 2}. The spliterator returns segments that
* are associated with the same scope as this segment.
* <p>
@@ -42,7 +42,7 @@
* of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}, so that each subclass can override the
* {@link HeapMemorySegmentImpl#base()} method so that it returns an array of the correct (sharp) type.
*/
public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {

private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class);
@@ -53,25 +53,25 @@
private static final long MAX_ALIGN_8 = 8;

final long offset;
final H base;
final Object base;

@ForceInline
HeapMemorySegmentImpl(long offset, H base, long length, int mask) {
HeapMemorySegmentImpl(long offset, Object base, long length, int mask) {
super(length, mask, ResourceScopeImpl.GLOBAL);
this.offset = offset;
this.base = base;
}

@Override
abstract H base();
abstract Object base();

@Override
long min() {
return offset;
}

@Override
abstract HeapMemorySegmentImpl<H> dup(long offset, long size, int mask, ResourceScopeImpl scope);
abstract HeapMemorySegmentImpl dup(long offset, long size, int mask, ResourceScopeImpl scope);

@Override
ByteBuffer makeByteBuffer() {
@@ -84,9 +84,9 @@ ByteBuffer makeByteBuffer() {

// factories

public static class OfByte extends HeapMemorySegmentImpl<byte[]> {
public static class OfByte extends HeapMemorySegmentImpl {

OfByte(long offset, byte[] base, long length, int mask) {
OfByte(long offset, Object base, long length, int mask) {
Copy link
Member

@PaulSandoz PaulSandoz Jan 12, 2022

Choose a reason for hiding this comment

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

Is it possible to retain the array type for the constructor?

Copy link
Contributor Author

@mcimadamore mcimadamore Jan 12, 2022

Choose a reason for hiding this comment

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

yes, that should be harmless

Copy link
Contributor Author

@mcimadamore mcimadamore Jan 12, 2022

Choose a reason for hiding this comment

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

Actually, no, sorry. If I sharpen the type, then dup has to cast, so we go back to the original issue.

Copy link
Member

@PaulSandoz PaulSandoz Jan 12, 2022

Choose a reason for hiding this comment

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

Ah yes, i see. Maybe it's worth adding a general comment to the class doc of HeapMemorySegmentImpl briefly explaining the reasons for use of Object.

super(offset, base, length, mask);
}

@@ -97,7 +97,7 @@ OfByte dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
byte[] base() {
return Objects.requireNonNull(base);
return (byte[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(byte[] arr) {
@@ -112,9 +112,9 @@ public long maxAlignMask() {
}
}

public static class OfChar extends HeapMemorySegmentImpl<char[]> {
public static class OfChar extends HeapMemorySegmentImpl {

OfChar(long offset, char[] base, long length, int mask) {
OfChar(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
}

@@ -125,7 +125,7 @@ OfChar dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
char[] base() {
return Objects.requireNonNull(base);
return (char[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(char[] arr) {
@@ -140,9 +140,9 @@ public long maxAlignMask() {
}
}

public static class OfShort extends HeapMemorySegmentImpl<short[]> {
public static class OfShort extends HeapMemorySegmentImpl {

OfShort(long offset, short[] base, long length, int mask) {
OfShort(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
}

@@ -153,7 +153,7 @@ OfShort dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
short[] base() {
return Objects.requireNonNull(base);
return (short[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(short[] arr) {
@@ -168,9 +168,9 @@ public long maxAlignMask() {
}
}

public static class OfInt extends HeapMemorySegmentImpl<int[]> {
public static class OfInt extends HeapMemorySegmentImpl {

OfInt(long offset, int[] base, long length, int mask) {
OfInt(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
}

@@ -181,7 +181,7 @@ OfInt dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
int[] base() {
return Objects.requireNonNull(base);
return (int[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(int[] arr) {
@@ -196,9 +196,9 @@ public long maxAlignMask() {
}
}

public static class OfLong extends HeapMemorySegmentImpl<long[]> {
public static class OfLong extends HeapMemorySegmentImpl {

OfLong(long offset, long[] base, long length, int mask) {
OfLong(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
}

@@ -209,7 +209,7 @@ OfLong dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
long[] base() {
return Objects.requireNonNull(base);
return (long[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(long[] arr) {
@@ -224,9 +224,9 @@ public long maxAlignMask() {
}
}

public static class OfFloat extends HeapMemorySegmentImpl<float[]> {
public static class OfFloat extends HeapMemorySegmentImpl {

OfFloat(long offset, float[] base, long length, int mask) {
OfFloat(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
}

@@ -237,7 +237,7 @@ OfFloat dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
float[] base() {
return Objects.requireNonNull(base);
return (float[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(float[] arr) {
@@ -252,9 +252,9 @@ public long maxAlignMask() {
}
}

public static class OfDouble extends HeapMemorySegmentImpl<double[]> {
public static class OfDouble extends HeapMemorySegmentImpl {

OfDouble(long offset, double[] base, long length, int mask) {
OfDouble(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
}

@@ -265,7 +265,7 @@ OfDouble dup(long offset, long size, int mask, ResourceScopeImpl scope) {

@Override
double[] base() {
return Objects.requireNonNull(base);
return (double[])Objects.requireNonNull(base);
}

public static MemorySegment fromArray(double[] arr) {
@@ -0,0 +1,172 @@
/*
* Copyright (c) 2022, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.jdk.incubator.foreign;

import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.ValueLayout;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import sun.misc.Unsafe;

import java.lang.invoke.VarHandle;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement;
import static jdk.incubator.foreign.ValueLayout.JAVA_INT;

@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@State(org.openjdk.jmh.annotations.Scope.Thread)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" })

public class LoopOverSlice {

static final int ELEM_SIZE = 1_000_000;
static final int CARRIER_SIZE = (int)JAVA_INT.byteSize();
static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE;

MemorySegment nativeSegment, heapSegment;
ResourceScope scope;

@Setup
public void setup() {
scope = ResourceScope.newConfinedScope();
nativeSegment = MemorySegment.allocateNative(ALLOC_SIZE, scope);
heapSegment = MemorySegment.ofArray(new float[ELEM_SIZE]);
Copy link
Member

@PaulSandoz PaulSandoz Jan 13, 2022

Choose a reason for hiding this comment

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

The heap MemorySegment wraps float[] but is accessed as if int[], same bit size, but I suspect it was not intentional?

}

@TearDown
public void tearDown() {
scope.close();
}

@Benchmark
public void native_slice_loop() {
new NativeWrapper(nativeSegment).forEach(NativeWrapper.Element::get);
}

@Benchmark
public void heap_slice_loop() {
new HeapWrapper(heapSegment).forEach(HeapWrapper.Element::get);
}

class HeapWrapper implements Iterable<HeapWrapper.Element> {
final MemorySegment segment;

public HeapWrapper(MemorySegment segment) {
this.segment = segment;
}

@Override
public Iterator<Element> iterator() {
return new Iterator<Element>() {

MemorySegment current = segment;

@Override
public boolean hasNext() {
return current.byteSize() > 4;
}

@Override
public Element next() {
Element element = new Element(current);
current = current.asSlice(4);
return element;
}
};
}

static class Element {
final MemorySegment segment;

public Element(MemorySegment segment) {
this.segment = segment;
}

int get() {
return segment.getAtIndex(JAVA_INT, 0);
}
}
}

class NativeWrapper implements Iterable<NativeWrapper.Element> {
final MemorySegment segment;

public NativeWrapper(MemorySegment segment) {
this.segment = segment;
}

int get() {
return segment.getAtIndex(JAVA_INT, 0);
}

@Override
public Iterator<Element> iterator() {
return new Iterator<Element>() {

MemorySegment current = segment;

@Override
public boolean hasNext() {
return current.byteSize() > 4;
}

@Override
public Element next() {
Element element = new Element(current);
current = current.asSlice(4);
return element;
}
};
}

static class Element {
final MemorySegment segment;

public Element(MemorySegment segment) {
this.segment = segment;
}

int get() {
return segment.getAtIndex(JAVA_INT, 0);
}
}
}
}