Skip to content

Commit d2ddf07

Browse files
committed
8256477: Specialize heap memory segment implementations
Reviewed-by: jvernee, chegar
1 parent 9707496 commit d2ddf07

File tree

4 files changed

+183
-47
lines changed

4 files changed

+183
-47
lines changed

src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ static MemorySegment ofByteBuffer(ByteBuffer bb) {
691691
* @return a new confined array memory segment.
692692
*/
693693
static MemorySegment ofArray(byte[] arr) {
694-
return HeapMemorySegmentImpl.makeArraySegment(arr);
694+
return HeapMemorySegmentImpl.OfByte.fromArray(arr);
695695
}
696696

697697
/**
@@ -705,7 +705,7 @@ static MemorySegment ofArray(byte[] arr) {
705705
* @return a new confined array memory segment.
706706
*/
707707
static MemorySegment ofArray(char[] arr) {
708-
return HeapMemorySegmentImpl.makeArraySegment(arr);
708+
return HeapMemorySegmentImpl.OfChar.fromArray(arr);
709709
}
710710

711711
/**
@@ -719,7 +719,7 @@ static MemorySegment ofArray(char[] arr) {
719719
* @return a new confined array memory segment.
720720
*/
721721
static MemorySegment ofArray(short[] arr) {
722-
return HeapMemorySegmentImpl.makeArraySegment(arr);
722+
return HeapMemorySegmentImpl.OfShort.fromArray(arr);
723723
}
724724

725725
/**
@@ -733,7 +733,7 @@ static MemorySegment ofArray(short[] arr) {
733733
* @return a new confined array memory segment.
734734
*/
735735
static MemorySegment ofArray(int[] arr) {
736-
return HeapMemorySegmentImpl.makeArraySegment(arr);
736+
return HeapMemorySegmentImpl.OfInt.fromArray(arr);
737737
}
738738

739739
/**
@@ -747,7 +747,7 @@ static MemorySegment ofArray(int[] arr) {
747747
* @return a new confined array memory segment.
748748
*/
749749
static MemorySegment ofArray(float[] arr) {
750-
return HeapMemorySegmentImpl.makeArraySegment(arr);
750+
return HeapMemorySegmentImpl.OfFloat.fromArray(arr);
751751
}
752752

753753
/**
@@ -761,7 +761,7 @@ static MemorySegment ofArray(float[] arr) {
761761
* @return a new confined array memory segment.
762762
*/
763763
static MemorySegment ofArray(long[] arr) {
764-
return HeapMemorySegmentImpl.makeArraySegment(arr);
764+
return HeapMemorySegmentImpl.OfLong.fromArray(arr);
765765
}
766766

767767
/**
@@ -775,7 +775,7 @@ static MemorySegment ofArray(long[] arr) {
775775
* @return a new confined array memory segment.
776776
*/
777777
static MemorySegment ofArray(double[] arr) {
778-
return HeapMemorySegmentImpl.makeArraySegment(arr);
778+
return HeapMemorySegmentImpl.OfDouble.fromArray(arr);
779779
}
780780

781781
/**

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ public static AbstractMemorySegmentImpl ofBuffer(ByteBuffer bb) {
588588
modes &= ~WRITE;
589589
}
590590
if (base != null) {
591-
return new HeapMemorySegmentImpl<>(bbAddress + pos, () -> (byte[])base, size, modes, bufferScope);
591+
return new HeapMemorySegmentImpl.OfByte(bbAddress + pos, (byte[])base, size, modes, bufferScope);
592592
} else if (unmapper == null) {
593593
return new NativeMemorySegmentImpl(bbAddress + pos, size, modes, bufferScope);
594594
} else {

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

Lines changed: 155 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,35 @@
3939
/**
4040
* Implementation for heap memory segments. An heap memory segment is composed by an offset and
4141
* a base object (typically an array). To enhance performances, the access to the base object needs to feature
42-
* sharp type information, as well as sharp null-check information. For this reason, the factories for heap segments
43-
* use a lambda to implement the base object accessor, so that the type information will remain sharp (e.g.
44-
* the static compiler will generate specialized base accessor for us).
42+
* sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses
43+
* of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}, so that each subclass can override the
44+
* {@link HeapMemorySegmentImpl#base()} method so that it returns an array of the correct (sharp) type.
4545
*/
46-
public class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
46+
public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
4747

4848
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
4949
private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class);
5050

5151
final long offset;
52-
final Supplier<H> baseProvider;
52+
final H base;
5353

5454
@ForceInline
55-
HeapMemorySegmentImpl(long offset, Supplier<H> baseProvider, long length, int mask, MemoryScope scope) {
55+
HeapMemorySegmentImpl(long offset, H base, long length, int mask, MemoryScope scope) {
5656
super(length, mask, scope);
5757
this.offset = offset;
58-
this.baseProvider = baseProvider;
58+
this.base = base;
5959
}
6060

6161
@Override
62-
H base() {
63-
return Objects.requireNonNull(baseProvider.get());
64-
}
62+
abstract H base();
6563

6664
@Override
6765
long min() {
6866
return offset;
6967
}
7068

7169
@Override
72-
HeapMemorySegmentImpl<H> dup(long offset, long size, int mask, MemoryScope scope) {
73-
return new HeapMemorySegmentImpl<>(this.offset + offset, baseProvider, size, mask, scope);
74-
}
70+
abstract HeapMemorySegmentImpl<H> dup(long offset, long size, int mask, MemoryScope scope);
7571

7672
@Override
7773
ByteBuffer makeByteBuffer() {
@@ -84,44 +80,164 @@ ByteBuffer makeByteBuffer() {
8480

8581
// factories
8682

87-
public static MemorySegment makeArraySegment(byte[] arr) {
88-
return makeHeapSegment(() -> arr, arr.length,
89-
Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE);
90-
}
83+
public static class OfByte extends HeapMemorySegmentImpl<byte[]> {
84+
85+
OfByte(long offset, byte[] base, long length, int mask, MemoryScope scope) {
86+
super(offset, base, length, mask, scope);
87+
}
88+
89+
@Override
90+
OfByte dup(long offset, long size, int mask, MemoryScope scope) {
91+
return new OfByte(this.offset + offset, base, size, mask, scope);
92+
}
9193

92-
public static MemorySegment makeArraySegment(char[] arr) {
93-
return makeHeapSegment(() -> arr, arr.length,
94-
Unsafe.ARRAY_CHAR_BASE_OFFSET, Unsafe.ARRAY_CHAR_INDEX_SCALE);
94+
@Override
95+
byte[] base() {
96+
return Objects.requireNonNull(base);
97+
}
98+
99+
public static MemorySegment fromArray(byte[] arr) {
100+
int byteSize = arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE;
101+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
102+
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
103+
}
95104
}
96105

97-
public static MemorySegment makeArraySegment(short[] arr) {
98-
return makeHeapSegment(() -> arr, arr.length,
99-
Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE);
106+
public static class OfChar extends HeapMemorySegmentImpl<char[]> {
107+
108+
OfChar(long offset, char[] base, long length, int mask, MemoryScope scope) {
109+
super(offset, base, length, mask, scope);
110+
}
111+
112+
@Override
113+
OfChar dup(long offset, long size, int mask, MemoryScope scope) {
114+
return new OfChar(this.offset + offset, base, size, mask, scope);
115+
}
116+
117+
@Override
118+
char[] base() {
119+
return Objects.requireNonNull(base);
120+
}
121+
122+
public static MemorySegment fromArray(char[] arr) {
123+
int byteSize = arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE;
124+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
125+
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
126+
}
100127
}
101128

102-
public static MemorySegment makeArraySegment(int[] arr) {
103-
return makeHeapSegment(() -> arr, arr.length,
104-
Unsafe.ARRAY_INT_BASE_OFFSET, Unsafe.ARRAY_INT_INDEX_SCALE);
129+
public static class OfShort extends HeapMemorySegmentImpl<short[]> {
130+
131+
OfShort(long offset, short[] base, long length, int mask, MemoryScope scope) {
132+
super(offset, base, length, mask, scope);
133+
}
134+
135+
@Override
136+
OfShort dup(long offset, long size, int mask, MemoryScope scope) {
137+
return new OfShort(this.offset + offset, base, size, mask, scope);
138+
}
139+
140+
@Override
141+
short[] base() {
142+
return Objects.requireNonNull(base);
143+
}
144+
145+
public static MemorySegment fromArray(short[] arr) {
146+
int byteSize = arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE;
147+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
148+
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
149+
}
105150
}
106151

107-
public static MemorySegment makeArraySegment(long[] arr) {
108-
return makeHeapSegment(() -> arr, arr.length,
109-
Unsafe.ARRAY_LONG_BASE_OFFSET, Unsafe.ARRAY_LONG_INDEX_SCALE);
152+
public static class OfInt extends HeapMemorySegmentImpl<int[]> {
153+
154+
OfInt(long offset, int[] base, long length, int mask, MemoryScope scope) {
155+
super(offset, base, length, mask, scope);
156+
}
157+
158+
@Override
159+
OfInt dup(long offset, long size, int mask, MemoryScope scope) {
160+
return new OfInt(this.offset + offset, base, size, mask, scope);
161+
}
162+
163+
@Override
164+
int[] base() {
165+
return Objects.requireNonNull(base);
166+
}
167+
168+
public static MemorySegment fromArray(int[] arr) {
169+
int byteSize = arr.length * Unsafe.ARRAY_INT_INDEX_SCALE;
170+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
171+
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
172+
}
110173
}
111174

112-
public static MemorySegment makeArraySegment(float[] arr) {
113-
return makeHeapSegment(() -> arr, arr.length,
114-
Unsafe.ARRAY_FLOAT_BASE_OFFSET, Unsafe.ARRAY_FLOAT_INDEX_SCALE);
175+
public static class OfLong extends HeapMemorySegmentImpl<long[]> {
176+
177+
OfLong(long offset, long[] base, long length, int mask, MemoryScope scope) {
178+
super(offset, base, length, mask, scope);
179+
}
180+
181+
@Override
182+
OfLong dup(long offset, long size, int mask, MemoryScope scope) {
183+
return new OfLong(this.offset + offset, base, size, mask, scope);
184+
}
185+
186+
@Override
187+
long[] base() {
188+
return Objects.requireNonNull(base);
189+
}
190+
191+
public static MemorySegment fromArray(long[] arr) {
192+
int byteSize = arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE;
193+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
194+
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
195+
}
115196
}
116197

117-
public static MemorySegment makeArraySegment(double[] arr) {
118-
return makeHeapSegment(() -> arr, arr.length,
119-
Unsafe.ARRAY_DOUBLE_BASE_OFFSET, Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
198+
public static class OfFloat extends HeapMemorySegmentImpl<float[]> {
199+
200+
OfFloat(long offset, float[] base, long length, int mask, MemoryScope scope) {
201+
super(offset, base, length, mask, scope);
202+
}
203+
204+
@Override
205+
OfFloat dup(long offset, long size, int mask, MemoryScope scope) {
206+
return new OfFloat(this.offset + offset, base, size, mask, scope);
207+
}
208+
209+
@Override
210+
float[] base() {
211+
return Objects.requireNonNull(base);
212+
}
213+
214+
public static MemorySegment fromArray(float[] arr) {
215+
int byteSize = arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE;
216+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
217+
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
218+
}
120219
}
121220

122-
static <Z> HeapMemorySegmentImpl<Z> makeHeapSegment(Supplier<Z> obj, int length, int base, int scale) {
123-
int byteSize = length * scale;
124-
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
125-
return new HeapMemorySegmentImpl<>(base, obj, byteSize, defaultAccessModes(byteSize), scope);
221+
public static class OfDouble extends HeapMemorySegmentImpl<double[]> {
222+
223+
OfDouble(long offset, double[] base, long length, int mask, MemoryScope scope) {
224+
super(offset, base, length, mask, scope);
225+
}
226+
227+
@Override
228+
OfDouble dup(long offset, long size, int mask, MemoryScope scope) {
229+
return new OfDouble(this.offset + offset, base, size, mask, scope);
230+
}
231+
232+
@Override
233+
double[] base() {
234+
return Objects.requireNonNull(base);
235+
}
236+
237+
public static MemorySegment fromArray(double[] arr) {
238+
int byteSize = arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
239+
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
240+
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
241+
}
126242
}
127243
}

test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantHeap.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.openjdk.jmh.annotations.Measurement;
3333
import org.openjdk.jmh.annotations.Mode;
3434
import org.openjdk.jmh.annotations.OutputTimeUnit;
35+
import org.openjdk.jmh.annotations.Param;
3536
import org.openjdk.jmh.annotations.Setup;
3637
import org.openjdk.jmh.annotations.State;
3738
import org.openjdk.jmh.annotations.TearDown;
@@ -67,8 +68,27 @@ public class LoopOverNonConstantHeap {
6768

6869
ByteBuffer byteBuffer;
6970

71+
@Param(value = {"false", "true"})
72+
boolean polluteProfile;
73+
7074
@Setup
7175
public void setup() {
76+
if (polluteProfile) {
77+
MemorySegment intB = MemorySegment.ofArray(new byte[ALLOC_SIZE]);
78+
MemorySegment intI = MemorySegment.ofArray(new int[ALLOC_SIZE]);
79+
MemorySegment intD = MemorySegment.ofArray(new double[ALLOC_SIZE]);
80+
MemorySegment intF = MemorySegment.ofArray(new float[ALLOC_SIZE]);
81+
try (MemorySegment s = MemorySegment.allocateNative(ALLOC_SIZE)) {
82+
for (int i = 0; i < ALLOC_SIZE; i++) {
83+
MemoryAccess.setByteAtOffset(intB, i, (byte)i);
84+
MemoryAccess.setIntAtIndex(intI, i, i);
85+
MemoryAccess.setDoubleAtIndex(intD, i, i);
86+
MemoryAccess.setFloatAtIndex(intF, i, i);
87+
MemoryAccess.setByteAtOffset(s, i, (byte) i);
88+
}
89+
}
90+
}
91+
7292
base = new byte[ALLOC_SIZE];
7393
for (int i = 0; i < ELEM_SIZE; i++) {
7494
unsafe.putInt(base, UNSAFE_BYTE_BASE + (i * CARRIER_SIZE) , i);

0 commit comments

Comments
 (0)