-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8346657: Improve out of bounds exception messages for MemorySegments #28124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hextriclosan
wants to merge
8
commits into
openjdk:master
Choose a base branch
from
hextriclosan:JDK-8346657
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+93
−30
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
a106ac8
JDK-8346657: Improve out of bounds exception messages for MemorySegments
hextriclosan adc7a06
Fixes according to reviewer's comments
hextriclosan 49c35fa
Merge branch 'openjdk:master' into JDK-8346657
hextriclosan 53f68ba
Remove the length > 0 condition, as it brakes multiple unit tests
hextriclosan fb7b28c
missed condition fix
hextriclosan b96a015
rework
hextriclosan 9a2cc13
rework: eliminate lambda binding; introduce lightweight wrapper which…
hextriclosan df86a85
Adjust to TestMergeStoresMemorySegment.java requirements
hextriclosan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,7 +68,7 @@ | |
| * {@link MappedMemorySegmentImpl}. | ||
| */ | ||
| public abstract sealed class AbstractMemorySegmentImpl | ||
| implements MemorySegment, SegmentAllocator, BiFunction<String, List<Number>, RuntimeException> | ||
| implements MemorySegment, SegmentAllocator | ||
| permits HeapMemorySegmentImpl, NativeMemorySegmentImpl { | ||
|
|
||
| static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); | ||
|
|
@@ -100,19 +100,19 @@ public boolean isReadOnly() { | |
|
|
||
| @Override | ||
| public AbstractMemorySegmentImpl asSlice(long offset, long newSize) { | ||
| checkBounds(offset, newSize); | ||
| checkSliceBounds(offset, newSize); | ||
| return asSliceNoCheck(offset, newSize); | ||
| } | ||
|
|
||
| @Override | ||
| public AbstractMemorySegmentImpl asSlice(long offset) { | ||
| checkBounds(offset, 0); | ||
| checkSliceBounds(offset, 0); | ||
| return asSliceNoCheck(offset, length - offset); | ||
| } | ||
|
|
||
| @Override | ||
| public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { | ||
| checkBounds(offset, newSize); | ||
| checkSliceBounds(offset, newSize); | ||
| Utils.checkAlign(byteAlignment); | ||
|
|
||
| if (!isAlignedForElement(offset, byteAlignment)) { | ||
|
|
@@ -354,7 +354,7 @@ public void checkReadOnly(boolean readOnly) { | |
| @ForceInline | ||
| public void checkAccess(long offset, long length, boolean readOnly) { | ||
| checkReadOnly(readOnly); | ||
| checkBounds(offset, length); | ||
| checkAccessBounds(offset, length); | ||
| } | ||
|
|
||
| @ForceInline | ||
|
|
@@ -398,20 +398,22 @@ private int checkArraySize(String typeName, int elemSize) { | |
| } | ||
|
|
||
| @ForceInline | ||
| void checkBounds(long offset, long length) { | ||
| if (length > 0) { | ||
| Preconditions.checkIndex(offset, this.length - length + 1, this); | ||
| } else if (length < 0 || offset < 0 || | ||
| offset > this.length - length) { | ||
| throw outOfBoundException(offset, length); | ||
| } | ||
| void checkSliceBounds(long offset, long length) { | ||
| checkBounds(offset, length, BoundPolicy.SLICE); | ||
| } | ||
|
|
||
| @Override | ||
| public RuntimeException apply(String s, List<Number> numbers) { | ||
| long offset = numbers.get(0).longValue(); | ||
| long length = byteSize() - numbers.get(1).longValue() + 1; | ||
| return outOfBoundException(offset, length); | ||
| @ForceInline | ||
| void checkAccessBounds(long offset, long length) { | ||
| checkBounds(offset, length, BoundPolicy.ACCESS); | ||
| } | ||
|
|
||
| @ForceInline | ||
| private void checkBounds(long offset, long length, BoundPolicy policy) { | ||
| if (length > 0) { | ||
| Preconditions.checkIndex(offset, this.length - length + 1, new BoundsCheckHandler(this, policy)); | ||
| } else if (length < 0 || offset < 0 || offset > this.length - length) { | ||
| throw policy.outOfBoundException(this, offset, length, this.length); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -429,11 +431,6 @@ public final MemorySessionImpl sessionImpl() { | |
| return scope; | ||
| } | ||
|
|
||
| private IndexOutOfBoundsException outOfBoundException(long offset, long length) { | ||
| return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d", | ||
| this, offset, length)); | ||
| } | ||
|
|
||
| static class SegmentSplitter implements Spliterator<MemorySegment> { | ||
| AbstractMemorySegmentImpl segment; | ||
| long elemCount; | ||
|
|
@@ -508,6 +505,54 @@ public int characteristics() { | |
| } | ||
| } | ||
|
|
||
| private enum BoundPolicy { | ||
| SLICE { | ||
| @Override | ||
| String format(AbstractMemorySegmentImpl segment, long offset, long size, long length) { | ||
| return String.format( | ||
| "Out of bound access on segment %s; attempting to get slice of length %d at offset %d " + | ||
| "which is outside the valid range 0 <= offset+length < byteSize (=%d)", | ||
| segment, size, offset, length | ||
| ); | ||
| } | ||
| }, | ||
| ACCESS { | ||
| @Override | ||
| String format(AbstractMemorySegmentImpl segment, long offset, long size, long length) { | ||
| return String.format( | ||
| "Out of bound access on segment %s; attempting to access an element of length %d at offset %d " + | ||
| "which is outside the valid range 0 <= offset+length < byteSize (=%d)", | ||
| segment, size, offset, length | ||
| ); | ||
| } | ||
| }; | ||
|
|
||
| private IndexOutOfBoundsException outOfBoundException(AbstractMemorySegmentImpl segment, long offset, long size, | ||
| long length) { | ||
| return new IndexOutOfBoundsException(format(segment, offset, size, length)); | ||
| } | ||
|
|
||
| abstract String format(AbstractMemorySegmentImpl segment, long offset, long size, long length); | ||
| } | ||
|
|
||
| private static final class BoundsCheckHandler implements BiFunction<String, List<Number>, IndexOutOfBoundsException> { | ||
| final AbstractMemorySegmentImpl segment; | ||
| final BoundPolicy policy; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recommend turning this into a private record. In addition, we should add a comment that we anticipate this record instance creation to be eliminated by escape analysis when segment access is compiled. I wonder if you have run benchmarks to verify this. |
||
|
|
||
| BoundsCheckHandler(AbstractMemorySegmentImpl segment, BoundPolicy policy) { | ||
| this.segment = segment; | ||
| this.policy = policy; | ||
| } | ||
|
|
||
| @Override | ||
| public IndexOutOfBoundsException apply(String s, List<Number> numbers) { | ||
| long offset = numbers.get(0).longValue(); | ||
| long length = segment.byteSize() - numbers.get(1).longValue() + 1; | ||
|
|
||
| return policy.outOfBoundException(segment, offset, length, segment.byteSize()); | ||
| } | ||
| } | ||
|
|
||
| // Object methods | ||
|
|
||
| @Override | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though this does look better, but abstract method in enum means extra classes, which become some extra burden for startup. If you can write this method to have a body like:
This would be less costly.