8279930: Synthetic cast causes generation of store barriers when using heap segments
Reviewed-by: psandoz
This commit is contained in:
parent
45f20633f6
commit
c6b027559c
src/jdk.incubator.foreign/share/classes/jdk
test/micro/org/openjdk/bench/jdk/incubator/foreign
@ -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>
|
||||
|
@ -36,13 +36,17 @@ import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Implementation for heap memory segments. An heap memory segment is composed by an offset and
|
||||
* Implementation for heap memory segments. A heap memory segment is composed by an offset and
|
||||
* a base object (typically an array). To enhance performances, the access to the base object needs to feature
|
||||
* sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses
|
||||
* 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.
|
||||
* {@link HeapMemorySegmentImpl#base()} method so that it returns an array of the correct (sharp) type. Note that
|
||||
* the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses
|
||||
* accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as
|
||||
* using sharper types would require use of type-conversions, which in turn would inhibit some C2 optimizations,
|
||||
* such as the elimination of store barriers in methods like {@link HeapMemorySegmentImpl#dup(long, long, int, ResourceScopeImpl)}.
|
||||
*/
|
||||
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,17 +57,17 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
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() {
|
||||
@ -71,7 +75,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
@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 +88,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
// 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) {
|
||||
super(offset, base, length, mask);
|
||||
}
|
||||
|
||||
@ -97,7 +101,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
byte[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (byte[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(byte[] arr) {
|
||||
@ -112,9 +116,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
}
|
||||
|
||||
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 +129,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
char[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (char[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(char[] arr) {
|
||||
@ -140,9 +144,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
}
|
||||
|
||||
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 +157,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
short[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (short[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(short[] arr) {
|
||||
@ -168,9 +172,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
}
|
||||
|
||||
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 +185,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
int[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (int[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(int[] arr) {
|
||||
@ -196,9 +200,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
}
|
||||
|
||||
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 +213,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
long[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (long[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(long[] arr) {
|
||||
@ -224,9 +228,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
}
|
||||
|
||||
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 +241,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
float[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (float[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(float[] arr) {
|
||||
@ -252,9 +256,9 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
}
|
||||
|
||||
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 +269,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
|
||||
@Override
|
||||
double[] base() {
|
||||
return Objects.requireNonNull(base);
|
||||
return (double[])Objects.requireNonNull(base);
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(double[] arr) {
|
||||
|
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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.MemorySegment;
|
||||
import jdk.incubator.foreign.ResourceScope;
|
||||
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 java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
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;
|
||||
IntBuffer nativeBuffer, heapBuffer;
|
||||
ResourceScope scope;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
scope = ResourceScope.newConfinedScope();
|
||||
nativeSegment = MemorySegment.allocateNative(ALLOC_SIZE, scope);
|
||||
heapSegment = MemorySegment.ofArray(new int[ELEM_SIZE]);
|
||||
nativeBuffer = ByteBuffer.allocateDirect(ALLOC_SIZE).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
|
||||
heapBuffer = IntBuffer.wrap(new int[ELEM_SIZE]);
|
||||
}
|
||||
|
||||
@TearDown
|
||||
public void tearDown() {
|
||||
scope.close();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void native_segment_slice_loop() {
|
||||
new NativeSegmentWrapper(nativeSegment).forEach(NativeSegmentWrapper.Element::get);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void native_buffer_slice_loop() {
|
||||
new NativeBufferWrapper(nativeBuffer).forEach(NativeBufferWrapper.Element::get);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void heap_segment_slice_loop() {
|
||||
new HeapSegmentWrapper(heapSegment).forEach(HeapSegmentWrapper.Element::get);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void heap_buffer_slice_loop() {
|
||||
new HeapBufferWrapper(heapBuffer).forEach(HeapBufferWrapper.Element::get);
|
||||
}
|
||||
|
||||
class HeapSegmentWrapper implements Iterable<HeapSegmentWrapper.Element> {
|
||||
final MemorySegment segment;
|
||||
|
||||
public HeapSegmentWrapper(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 NativeSegmentWrapper implements Iterable<NativeSegmentWrapper.Element> {
|
||||
final MemorySegment segment;
|
||||
|
||||
public NativeSegmentWrapper(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 NativeBufferWrapper implements Iterable<NativeBufferWrapper.Element> {
|
||||
final IntBuffer buffer;
|
||||
|
||||
public NativeBufferWrapper(IntBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Element> iterator() {
|
||||
return new Iterator<Element>() {
|
||||
|
||||
IntBuffer current = buffer;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current.position() < current.limit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element next() {
|
||||
Element element = new Element(current);
|
||||
int lim = current.limit();
|
||||
current = current.slice(1, lim - 1);
|
||||
return element;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Element {
|
||||
final IntBuffer buffer;
|
||||
|
||||
public Element(IntBuffer segment) {
|
||||
this.buffer = segment;
|
||||
}
|
||||
|
||||
int get() {
|
||||
return buffer.get( 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HeapBufferWrapper implements Iterable<HeapBufferWrapper.Element> {
|
||||
final IntBuffer buffer;
|
||||
|
||||
public HeapBufferWrapper(IntBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Element> iterator() {
|
||||
return new Iterator<Element>() {
|
||||
|
||||
IntBuffer current = buffer;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current.position() < current.limit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element next() {
|
||||
Element element = new Element(current);
|
||||
int lim = current.limit();
|
||||
current = current.slice(1, lim - 1);
|
||||
return element;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Element {
|
||||
final IntBuffer buffer;
|
||||
|
||||
public Element(IntBuffer segment) {
|
||||
this.buffer = segment;
|
||||
}
|
||||
|
||||
int get() {
|
||||
return buffer.get( 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user