-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
8318966: Some methods make promises about Java array element alignment that are too strong #16681
Conversation
👋 Welcome back jvernee! A progress list of the required criteria for merging this PR into |
@JornVernee The following labels will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command. |
* {@link Double#doubleToRawLongBits}, respectively). | ||
* Only plain {@linkplain VarHandle.AccessMode#GET get} and {@linkplain VarHandle.AccessMode#SET set} | ||
* access modes are supported by the returned var handle. For all other access modes, an | ||
* {@link UnsupportedOperationException} will be thrown. |
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.
I recommend adding an api note explaining that native memory segments, direct byte buffers, or heap memory segments backed by long[] should be used if support for other access modes are required.
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.
Good idea. Thanks
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.
Should we make these unaligned access modes throw ISE like before, when the given index is unaligned?
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.
You mean get
and set
? They should never throw, as unaligned access is fine. For other access modes, we can never guarantee that an access is aligned, so UOE is appropriate. (IIRC this is mandated by existing spec. I'll try to find it again)
P.S. See e.g. the javadoc of VarHandle::getVolatile
:
@throws UnsupportedOperationException if the access mode is unsupported for this VarHandle.
P.P.S. Also remembering that we can not have any implementation for the access methods, in order for isAccessModeSupported
to work correctly. And the logic that handles unsupported methods throws UOE (see VarForm::getMemberName
)
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.
Good point, so previous behavior of throwing ISE is out of spec
@@ -4641,6 +4606,8 @@ public static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass, | |||
* update access modes compare values using their bitwise representation | |||
* (see {@link Float#floatToRawIntBits} and | |||
* {@link Double#doubleToRawLongBits}, respectively). | |||
* <p> | |||
* Access to heap byte buffers is always unaligned. |
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.
I recommend merging that sentence into the paragraph on heap byte buffers e.g.:
For direct buffers, access of the bytes at an index is always misaligned. As a result only the plain...
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.
But... surely if I'm just accessing bytes the access cannot possibly be mis-aligned?
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.
Right. I think there is a difference between 'unaligned' and 'misaligned'. Unaligned means there is no effort made to align the access (so it may be misaligned). Misaligned means definitely not aligned. At least, that is my interpretation.
This is what I wrote in the latest version:
* For heap byte buffers, access is always unaligned. As a result, only the plain
* {@linkplain VarHandle.AccessMode#GET get}
* and {@linkplain VarHandle.AccessMode#SET set} access modes are supported by the
* returned var handle. For all other access modes, an {@link IllegalStateException}
* will be thrown.
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.
Uhm, I think my assumption was wrong - the byte
/boolean
carrier is not supported by this method, so there's no case where heap access would be guaranteed to be aligned.
* @implNote | ||
* This implementation throws {@code UnsupportedOperationException} for | ||
* non-direct buffers when the given unit size is greater then {@code 8}. | ||
* non-direct buffers when the given unit size is greater then {@code 1}. |
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.
This is no longer an implementation note, its now part of the specified API. So i think we can simplify the text of the @throws UOE ...
to just say:
@throws UOE if the buffer is non-direct and the unit size > 1
Same for the other method.
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.
Right. Good idea
@@ -736,17 +323,10 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { | |||
static boolean compareAndSet(VarHandle ob, Object obb, int index, $type$ expected, $type$ value) { | |||
ByteBufferHandle handle = (ByteBufferHandle)ob; | |||
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb); | |||
#if[Object] |
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.
Note that I removed this 'if Object' block (and the one below), as the public API does not support object access any way:
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Lines 4591 to 4593 in 9727f4b
* The supported component types (variables types) are {@code short}, | |
* {@code char}, {@code int}, {@code long}, {@code float} and | |
* {@code double}. |
@@ -527,18 +527,6 @@ private static void checkSlice(CharBuffer b, CharBuffer slice) { | |||
|
|||
|
|||
|
|||
|
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.
These white space changes come from re-generating the test files using the script included in the repo. I've kept the changes so that the next contributor won't have to remove them again.
Webrevs
|
Anything else needed to move this forward? I think I've addressed all the review comments made so far. |
@JornVernee This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
@JornVernee This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
/open |
@JornVernee This pull request is now open |
Also curious, is there any documentation (like JVMS) that allows JVMs to make no offset into byte arrays aligned for larger access? Would be helpful if we can have a reference here. |
There is simply no guarantee in the JVMS that array elements are aligned more than their size. So, the public API may not assume that they are, since it needs to be implementable by an arbitrary JVM that is JVMS compliant. |
@JornVernee This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 2 new commits pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the ➡️ To integrate this PR with the above commit message to the |
I'll do one more batch of testing (after merging with the latest master) and then integrate |
/integrate |
Going to push as commit 9c852df.
Your commit was automatically rebased without conflicts. |
@JornVernee Pushed as commit 9c852df. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
See the JBS issue for an extended problem description.
This patch changes the specification and implementation of
MethodHandles::byteArrayViewVarHandle
,MethodHandles::byteBufferViewVarHandle
,ByteBuffer::alignedSlice
, andByteBuffer::alignmentOffset
to weaken the guarantees they make about the alignment of Java array elements, in order to bring them in line with the guarantees made by an arbitrary JVM implementation (which makes no guarantees about array element alignment beyond them being aligned to their natural alignment).MethodHandles::byteArrayViewVarHandle
: we can not guarantee any alignment for the accesses. Which means we can only reliably support plain get and set access modes. The javadoc text explaining which other access modes are supported, or how to compute aligned offsets into the array is dropped, as it is not guaranteed to be correct on all JVM implementations. The implementation of the returned VarHandle is changed to throw anUnsupportedOperationException
for the unsupported access modes, as mandated by the spec ofVarHandle
1.MethodHandles::byteBufferViewVarHandle
: the implementation/spec is incorrect when accessing a heap buffer (wrapping a byte[]), for the same reasons asbyteArrayViewVarHandle
. The spec is changed to specify that when accessing a heap buffer, only plain get and set access modes are supported. The implementation of the returned var handle is changed to throw anIllegalStateException
when an access is attempted on a heap buffer using an access mode other than plain get or set. Note that we don't throw an outrightUnsupportedOperationException
for this case, since whether the access modes are supported depends on the byte buffer instance being used.ByteBuffer::alignedSlice
andByteBuffer::alignmentOffset
: The former method depends directly on the latter for all its alignment computations. We change the implementation of the latter method to throw anUnsupportedOperationException
for all unit sizes greater than 1, when the buffer is non-direct. This change is largely covered by the existing specification:However, the
@implNote
mentions that anUnsupportedOperationException
will be thrown for unit sizes greater than 8. This is updated to say unit sizes greater than 1.Both
byteArrayViewVarHandle
andbyteBufferViewVarHandle
do not supportbyte[]
, orboolean[]
as the view array class, for which accesses would be aligned. So, it is safe to say that access will always be unaligned when using the var handle returned by these methods.Note that the testing code for these APIs is tightly coupled, so it is practically convenient to address all these issues together.
Testing: local
java/lang/invoke/VarHandles
, tier 1-4Progress
Issues
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/16681/head:pull/16681
$ git checkout pull/16681
Update a local copy of the PR:
$ git checkout pull/16681
$ git pull https://git.openjdk.org/jdk.git pull/16681/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 16681
View PR using the GUI difftool:
$ git pr show -t 16681
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/16681.diff
Webrev
Link to Webrev Comment