Skip to content

Commit 2af4eec

Browse files
committed
[GR-52711] Implement GraalWasm SIMD proposal using the Vector API.
PullRequest: graal/20843
2 parents db7cf80 + 46844ea commit 2af4eec

File tree

51 files changed

+4043
-1627
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4043
-1627
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public class KnownTruffleTypes extends AbstractKnownTruffleTypes {
6969
public final ResolvedJavaType BufferOverflowException = lookupType(BufferOverflowException.class);
7070
public final ResolvedJavaType ReadOnlyBufferException = lookupType(ReadOnlyBufferException.class);
7171
public final ResolvedJavaType ScopedMemoryAccess_ScopedAccessError = lookupTypeOptional("jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError");
72+
public final ResolvedJavaType AssertionError = lookupType(AssertionError.class);
7273
public final ResolvedJavaType AbstractMemorySegmentImpl = lookupTypeOptional("jdk.internal.foreign.AbstractMemorySegmentImpl");
7374
public final ResolvedJavaType MemorySegmentProxy = lookupTypeOptional("jdk.internal.access.foreign.MemorySegmentProxy");
7475

@@ -245,6 +246,7 @@ private ResolvedJavaType[] createSkippedExceptionTypes() {
245246
types.add(BufferUnderflowException);
246247
types.add(BufferOverflowException);
247248
types.add(ReadOnlyBufferException);
249+
types.add(AssertionError);
248250
return types.toArray(ResolvedJavaType[]::new);
249251
}
250252

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptState.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ private Object materializeObject(int virtualObjectId, FrameInfoQueryResult sourc
186186

187187
if (ImageSingletons.contains(VectorAPIDeoptimizationSupport.class)) {
188188
VectorAPIDeoptimizationSupport deoptSupport = ImageSingletons.lookup(VectorAPIDeoptimizationSupport.class);
189-
Object payloadArray = deoptSupport.materializePayload(this, hub, encodings[curIdx], sourceFrame);
190-
if (payloadArray != null) {
189+
VectorAPIDeoptimizationSupport.PayloadLayout payloadLayout = deoptSupport.getLayout(DynamicHub.toClass(hub));
190+
if (payloadLayout != null) {
191+
Object payloadArray = deoptSupport.materializePayload(this, payloadLayout, encodings[curIdx], sourceFrame);
191192
JavaConstant arrayConstant = SubstrateObjectConstant.forObject(payloadArray, ReferenceAccess.singleton().haveCompressedReferences());
192193
Deoptimizer.writeValueInMaterializedObj(obj, curOffset, arrayConstant, sourceFrame);
193194
return obj;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/VectorAPIDeoptimizationSupport.java

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import com.oracle.svm.core.code.FrameInfoQueryResult;
3434
import com.oracle.svm.core.config.ConfigurationValues;
3535
import com.oracle.svm.core.config.ObjectLayout;
36-
import com.oracle.svm.core.hub.DynamicHub;
3736

3837
import jdk.graal.compiler.word.Word;
3938
import jdk.vm.ci.meta.JavaConstant;
@@ -45,41 +44,36 @@
4544
public class VectorAPIDeoptimizationSupport {
4645

4746
/**
48-
* If the {@code hub} refers to a Vector API vector, materialize its payload array. That is,
49-
* allocate a primitive array of the appropriate element type and length for the Vector API
50-
* value. Read the vector's entries from the stack and store them in the array.
47+
* Materialize the payload array of a Vector API class. That is, allocate a primitive array of
48+
* the appropriate element type and length for the Vector API value. Read the vector's entries
49+
* from the stack and store them in the array.
5150
*
5251
* @param deoptState state for accessing values on the stack
53-
* @param hub the hub of the object to be materialized
52+
* @param layout non-null payload layout from {@link #getLayout}
5453
* @param vectorEncoding describes the location of the vector on the stack
5554
* @param sourceFrame the source frame containing the vector
5655
* @return a materialized primitive array if the object to be materialized is a Vector API
5756
* vector; {@code null} otherwise
5857
*/
59-
public Object materializePayload(DeoptState deoptState, DynamicHub hub, FrameInfoQueryResult.ValueInfo vectorEncoding, FrameInfoQueryResult sourceFrame) {
60-
Class<?> vectorClass = DynamicHub.toClass(hub);
61-
PayloadLayout layout = typeMap.get(vectorClass);
62-
if (layout != null) {
63-
/*
64-
* Read values from the stack and write them to an array of the same element type. Note
65-
* that vector masks in states are already represented as vectors of byte-sized 0 or 1
66-
* values, this is ensured by the VectorAPIExpansionPhase. Therefore, this code does not
67-
* need to worry about the target's representation of vector masks; an element type of
68-
* boolean in the layout will allow us to handle masks correctly.
69-
*/
70-
JavaKind elementKind = JavaKind.fromJavaClass(layout.elementType);
71-
Object array = Array.newInstance(layout.elementType, layout.vectorLength);
72-
ObjectLayout objectLayout = ConfigurationValues.getObjectLayout();
73-
UnsignedWord curOffset = Word.unsigned(objectLayout.getArrayBaseOffset(elementKind));
74-
for (int i = 0; i < layout.vectorLength; i++) {
75-
FrameInfoQueryResult.ValueInfo elementEncoding = vectorEncoding.copyForElement(elementKind, i * elementKind.getByteCount());
76-
JavaConstant con = readValue(deoptState, elementEncoding, sourceFrame);
77-
writeValueInMaterializedObj(array, curOffset, con, sourceFrame);
78-
curOffset = curOffset.add(objectLayout.sizeInBytes(elementKind));
79-
}
80-
return array;
58+
public Object materializePayload(DeoptState deoptState, PayloadLayout layout, FrameInfoQueryResult.ValueInfo vectorEncoding, FrameInfoQueryResult sourceFrame) {
59+
/*
60+
* Read values from the stack and write them to an array of the same element type. Note that
61+
* vector masks in states are already represented as vectors of byte-sized 0 or 1 values,
62+
* this is ensured by the VectorAPIExpansionPhase. Therefore, this code does not need to
63+
* worry about the target's representation of vector masks; an element type of boolean in
64+
* the layout will allow us to handle masks correctly.
65+
*/
66+
JavaKind elementKind = JavaKind.fromJavaClass(layout.elementType);
67+
Object array = Array.newInstance(layout.elementType, layout.vectorLength);
68+
ObjectLayout objectLayout = ConfigurationValues.getObjectLayout();
69+
UnsignedWord curOffset = Word.unsigned(objectLayout.getArrayBaseOffset(elementKind));
70+
for (int i = 0; i < layout.vectorLength; i++) {
71+
FrameInfoQueryResult.ValueInfo elementEncoding = vectorEncoding.copyForElement(elementKind, i * elementKind.getByteCount());
72+
JavaConstant con = readValue(deoptState, elementEncoding, sourceFrame);
73+
writeValueInMaterializedObj(array, curOffset, con, sourceFrame);
74+
curOffset = curOffset.add(objectLayout.sizeInBytes(elementKind));
8175
}
82-
return null;
76+
return array;
8377
}
8478

8579
protected static JavaConstant readValue(DeoptState deoptState, FrameInfoQueryResult.ValueInfo valueInfo, FrameInfoQueryResult sourceFrame) {
@@ -108,4 +102,8 @@ public record PayloadLayout(Class<?> elementType, int vectorLength) {
108102
public void putLayout(Class<?> vectorClass, PayloadLayout layout) {
109103
typeMap.put(vectorClass, layout);
110104
}
105+
106+
public PayloadLayout getLayout(Class<?> vectorClass) {
107+
return typeMap.get(vectorClass);
108+
}
111109
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_vm_vector_VectorSupport.java

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
*/
2525
package com.oracle.svm.core.jdk;
2626

27+
import java.lang.foreign.MemorySegment;
28+
import java.lang.foreign.ValueLayout;
29+
import java.util.function.IntFunction;
2730
import java.util.stream.Collectors;
2831

2932
import org.graalvm.nativeimage.ImageSingletons;
@@ -109,6 +112,48 @@ private static final class Target_jdk_incubator_vector_VectorOperators_Conversio
109112
@AlwaysInline("Vector API performance")
110113
private static native Target_jdk_incubator_vector_VectorOperators_ConversionImpl<?, ?> ofReinterpret(Target_jdk_incubator_vector_LaneType dom, Target_jdk_incubator_vector_LaneType ran);
111114
}
115+
116+
@TargetClass(className = "jdk.incubator.vector.VectorOperators", innerClass = "Operator", onlyWith = VectorAPIEnabled.class)
117+
interface Target_jdk_incubator_vector_VectorOperators_Operator {
118+
}
119+
120+
@TargetClass(className = "jdk.incubator.vector.VectorOperators", innerClass = "ImplCache", onlyWith = VectorAPIEnabled.class)
121+
static final class Target_jdk_incubator_vector_VectorOperators_ImplCache<OP extends Target_jdk_incubator_vector_VectorOperators_Operator, T> {
122+
123+
@Alias Object[] cache;
124+
125+
/*
126+
* We substitute ImplCache#find to remove the call to isNonCapturingLambda. In the process,
127+
* we simplify the cache lookup by removing lazy cache initialization as we precompute the
128+
* cache.
129+
*/
130+
@Substitute
131+
@AlwaysInline("Vector API fast-path")
132+
@SuppressWarnings({"unchecked", "unused"})
133+
public T find(OP op, int opc, IntFunction<T> supplier) {
134+
T fn = (T) cache[opc];
135+
return fn;
136+
}
137+
}
138+
}
139+
140+
@TargetClass(className = "jdk.incubator.vector.AbstractVector", onlyWith = VectorAPIEnabled.class)
141+
final class Target_jdk_incubator_vector_AbstractVector {
142+
}
143+
144+
@TargetClass(className = "jdk.incubator.vector.AbstractSpecies", onlyWith = VectorAPIEnabled.class)
145+
final class Target_jdk_incubator_vector_AbstractSpecies {
146+
147+
@Alias private Target_jdk_incubator_vector_AbstractVector dummyVector;
148+
149+
/*
150+
* We initialize the `dummyVector` fields during image build-time using VectorAPIFeature. We can
151+
* have the getter method return the precomputed dummy vector directly.
152+
*/
153+
@Substitute
154+
Target_jdk_incubator_vector_AbstractVector dummyVector() {
155+
return dummyVector;
156+
}
112157
}
113158

114159
@TargetClass(className = "jdk.incubator.vector.ByteVector", onlyWith = VectorAPIEnabled.class)
@@ -119,6 +164,20 @@ final class Target_jdk_incubator_vector_ByteVector {
119164
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = byte[].class, isFinal = true) //
120165
@TargetElement(name = "ARRAY_BASE") //
121166
private static long arrayBase;
167+
168+
@Alias @RecomputeFieldValue(isFinal = true, kind = RecomputeFieldValue.Kind.None) //
169+
@TargetElement(name = "ELEMENT_LAYOUT") //
170+
static ValueLayout.OfByte elementLayout;
171+
172+
@Substitute
173+
static void memorySegmentSet(MemorySegment ms, long o, int i, byte e) {
174+
elementLayout.varHandle().set(ms, o + i * 1L, e);
175+
}
176+
177+
@Substitute
178+
static byte memorySegmentGet(MemorySegment ms, long o, int i) {
179+
return (byte) elementLayout.varHandle().get(ms, o + i * 1L);
180+
}
122181
}
123182

124183
@TargetClass(className = "jdk.incubator.vector.ShortVector", onlyWith = VectorAPIEnabled.class)
@@ -129,6 +188,20 @@ final class Target_jdk_incubator_vector_ShortVector {
129188
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = short[].class, isFinal = true) //
130189
@TargetElement(name = "ARRAY_BASE") //
131190
private static long arrayBase;
191+
192+
@Alias @RecomputeFieldValue(isFinal = true, kind = RecomputeFieldValue.Kind.None) //
193+
@TargetElement(name = "ELEMENT_LAYOUT") //
194+
static ValueLayout.OfShort elementLayout;
195+
196+
@Substitute
197+
static void memorySegmentSet(MemorySegment ms, long o, int i, short e) {
198+
elementLayout.varHandle().set(ms, o + i * 2L, e);
199+
}
200+
201+
@Substitute
202+
static short memorySegmentGet(MemorySegment ms, long o, int i) {
203+
return (short) elementLayout.varHandle().get(ms, o + i * 2L);
204+
}
132205
}
133206

134207
@TargetClass(className = "jdk.incubator.vector.IntVector", onlyWith = VectorAPIEnabled.class)
@@ -139,6 +212,20 @@ final class Target_jdk_incubator_vector_IntVector {
139212
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = int[].class, isFinal = true) //
140213
@TargetElement(name = "ARRAY_BASE") //
141214
private static long arrayBase;
215+
216+
@Alias @RecomputeFieldValue(isFinal = true, kind = RecomputeFieldValue.Kind.None) //
217+
@TargetElement(name = "ELEMENT_LAYOUT") //
218+
static ValueLayout.OfInt elementLayout;
219+
220+
@Substitute
221+
static void memorySegmentSet(MemorySegment ms, long o, int i, int e) {
222+
elementLayout.varHandle().set(ms, o + i * 4L, e);
223+
}
224+
225+
@Substitute
226+
static int memorySegmentGet(MemorySegment ms, long o, int i) {
227+
return (int) elementLayout.varHandle().get(ms, o + i * 4L);
228+
}
142229
}
143230

144231
@TargetClass(className = "jdk.incubator.vector.LongVector", onlyWith = VectorAPIEnabled.class)
@@ -149,6 +236,20 @@ final class Target_jdk_incubator_vector_LongVector {
149236
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = long[].class, isFinal = true) //
150237
@TargetElement(name = "ARRAY_BASE") //
151238
private static long arrayBase;
239+
240+
@Alias @RecomputeFieldValue(isFinal = true, kind = RecomputeFieldValue.Kind.None) //
241+
@TargetElement(name = "ELEMENT_LAYOUT") //
242+
static ValueLayout.OfLong elementLayout;
243+
244+
@Substitute
245+
static void memorySegmentSet(MemorySegment ms, long o, int i, long e) {
246+
elementLayout.varHandle().set(ms, o + i * 8L, e);
247+
}
248+
249+
@Substitute
250+
static long memorySegmentGet(MemorySegment ms, long o, int i) {
251+
return (long) elementLayout.varHandle().get(ms, o + i * 8L);
252+
}
152253
}
153254

154255
@TargetClass(className = "jdk.incubator.vector.FloatVector", onlyWith = VectorAPIEnabled.class)
@@ -159,6 +260,20 @@ final class Target_jdk_incubator_vector_FloatVector {
159260
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = float[].class, isFinal = true) //
160261
@TargetElement(name = "ARRAY_BASE") //
161262
private static long arrayBase;
263+
264+
@Alias @RecomputeFieldValue(isFinal = true, kind = RecomputeFieldValue.Kind.None) //
265+
@TargetElement(name = "ELEMENT_LAYOUT") //
266+
static ValueLayout.OfFloat elementLayout;
267+
268+
@Substitute
269+
static void memorySegmentSet(MemorySegment ms, long o, int i, float e) {
270+
elementLayout.varHandle().set(ms, o + i * 4L, e);
271+
}
272+
273+
@Substitute
274+
static float memorySegmentGet(MemorySegment ms, long o, int i) {
275+
return (float) elementLayout.varHandle().get(ms, o + i * 4L);
276+
}
162277
}
163278

164279
@TargetClass(className = "jdk.incubator.vector.DoubleVector", onlyWith = VectorAPIEnabled.class)
@@ -169,4 +284,18 @@ final class Target_jdk_incubator_vector_DoubleVector {
169284
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = double[].class, isFinal = true) //
170285
@TargetElement(name = "ARRAY_BASE") //
171286
private static long arrayBase;
287+
288+
@Alias @RecomputeFieldValue(isFinal = true, kind = RecomputeFieldValue.Kind.None) //
289+
@TargetElement(name = "ELEMENT_LAYOUT") //
290+
static ValueLayout.OfDouble elementLayout;
291+
292+
@Substitute
293+
static void memorySegmentSet(MemorySegment ms, long o, int i, double e) {
294+
elementLayout.varHandle().set(ms, o + i * 8L, e);
295+
}
296+
297+
@Substitute
298+
static double memorySegmentGet(MemorySegment ms, long o, int i) {
299+
return (double) elementLayout.varHandle().get(ms, o + i * 8L);
300+
}
172301
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandle.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,11 @@ private static SubstrateConstructorAccessor getConstructorAccessor(Constructor<?
285285
}
286286

287287
private static <T extends AccessibleObject & Member> void checkMember(T member, boolean isStatic) {
288-
VMError.guarantee(Modifier.isStatic(member.getModifiers()) == isStatic,
289-
"Cannot perform %s operation on a %s member".formatted(isStatic ? "static" : "non-static", isStatic ? "non-static" : "static"));
288+
if (Modifier.isStatic(member.getModifiers()) != isStatic) {
289+
throw VMError.shouldNotReachHere("Cannot perform " +
290+
(isStatic ? "static" : "non-static") + " operation on a " +
291+
(isStatic ? "non-static" : "static") + " member");
292+
}
290293
}
291294

292295
private static SubstrateAccessor getAccessor(Target_java_lang_invoke_MemberName memberName) {
@@ -295,7 +298,10 @@ private static SubstrateAccessor getAccessor(Target_java_lang_invoke_MemberName
295298
}
296299

297300
private static void checkArgs(Object[] args, int expectedLength, String methodName) {
298-
VMError.guarantee((expectedLength == 0 && args == null) || args.length == expectedLength, "%s requires exactly %d arguments".formatted(methodName, expectedLength));
301+
if ((expectedLength == 0 && args == null) || args.length == expectedLength) {
302+
return;
303+
}
304+
throw VMError.shouldNotReachHere(methodName + " requires exactly " + expectedLength + " arguments");
299305
}
300306

301307
private static void convertArgs(Object[] args, MethodType methodType) throws Throwable {

0 commit comments

Comments
 (0)