Skip to content

Commit

Permalink
Initial push
Browse files Browse the repository at this point in the history
  • Loading branch information
mcimadamore committed May 9, 2024
1 parent 23a72a1 commit 7cfd222
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,10 @@ public sealed interface MemoryLayout
* derived from the size of the element layout of a sequence, and
* {@code c_1}, {@code c_2}, ... {@code c_m} are other <em>static</em> offset
* constants (such as field offsets) which are derived from the layout path.
* <p>
* The returned method handle throws {@link IndexOutOfBoundsException} if the provided layout path has an open
* path element whose size is {@code S}, and its corresponding trailing {@code long} parameter
* has a value {@code I} such that {@code I >= S} or {@code I < 0}.
*
* @apiNote The returned method handle can be used to compute a layout offset,
* similarly to {@link #byteOffset(PathElement...)}, but more flexibly, as
Expand Down Expand Up @@ -609,7 +613,7 @@ public sealed interface MemoryLayout
* offset {@code O} of the access operation is computed as follows:
*
* {@snippet lang = "java":
* O = this.offsetHandle(P).invokeExact(B, I1, I2, ... In);
* O = this.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);
* }
* <p>
* Accessing a memory segment using the var handle returned by this method is subject
Expand Down Expand Up @@ -728,7 +732,7 @@ public sealed interface MemoryLayout
* offset {@code O} of the access operation is computed as follows:
*
* {@snippet lang = "java":
* O = this.offsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
* O = this.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
* }
* <p>
* More formally, this method can be obtained from the {@link #varHandle(PathElement...)},
Expand Down Expand Up @@ -838,7 +842,8 @@ public sealed interface MemoryLayout
* layout as its target layout.</li>
* </ul>
* Sequence path elements selecting more than one sequence element layout are called
* <a href="MemoryLayout.html#open-path-elements">open path elements</a>.
* <a href="MemoryLayout.html#open-path-elements">open path elements</a>. The <em>size</em>
* of an open path element determines the number of element layouts that can be selected by it.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and
Expand Down Expand Up @@ -906,6 +911,7 @@ static PathElement sequenceElement(long index) {
* <li>if {@code F > 0}, then {@code B = ceilDiv(C - S, F)}</li>
* <li>if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}</li>
* </ul>
* That is, the size of the returned open path element is {@code B}.
*
* @param start the index of the first sequence element to be selected
* @param step the step factor at which subsequence sequence elements are to be
Expand All @@ -924,7 +930,7 @@ static PathElement sequenceElement(long start, long step) {
* <p>
* The exact sequence element selected by this layout is expressed as an index
* {@code I}. If {@code C} is the sequence element count, it follows that
* {@code 0 <= I < C}.
* {@code 0 <= I < C}. That is, {@code C} is the size of the returned open path element.
*/
static PathElement sequenceElement() {
return LayoutPath.SequenceElement.instance();
Expand Down
20 changes: 20 additions & 0 deletions test/jdk/java/foreign/TestLayoutPaths.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.IntFunction;
import java.util.stream.Stream;

import static java.lang.foreign.MemoryLayout.PathElement.groupElement;
import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement;
Expand Down Expand Up @@ -311,6 +313,24 @@ public void testOffsetHandle(MemoryLayout layout, PathElement[] pathElements, lo
assertEquals(actualByteOffset, expectedByteOffset);
}

@Test(dataProvider = "testLayouts")
public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
long expectedByteOffset) throws Throwable {
int[] badIndices = { -1, 10 };
MemoryLayout seqLayout = MemoryLayout.sequenceLayout(badIndices[1], layout);
for (int badIndex : badIndices) {
PathElement[] seqPathElements = new PathElement[pathElements.length + 1];
long[] seqIndexes = new long[indexes.length + 1];
System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length);
System.arraycopy(indexes, 0, seqIndexes, 1, indexes.length);
seqPathElements[0] = PathElement.sequenceElement();
seqIndexes[0] = badIndex;
MethodHandle seqByteOffsetHandle = seqLayout.byteOffsetHandle(seqPathElements)
.asSpreader(long[].class, seqIndexes.length);
assertThrows(IndexOutOfBoundsException.class, () -> seqByteOffsetHandle.invoke(0L, seqIndexes));
}
}

@Test
public void testHashCodeCollision() {
PathElement sequenceElement = PathElement.sequenceElement();
Expand Down

0 comments on commit 7cfd222

Please sign in to comment.