Skip to content
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

8249879: Split MemorySegment and MemoryAddress #260

Closed

Conversation

mcimadamore
Copy link
Collaborator

@mcimadamore mcimadamore commented Jul 22, 2020

This patch splits, as the title suggests, the memory segment abstraction from the memory address abstraction, as described in this email:

https://mail.openjdk.java.net/pipermail/panama-dev/2020-July/009928.html

Aside from the obvious updates to the two interfaces (and their implementation), this patch greatly simplifies the way memory access var handles are generated; instead of spinning them on the fly (see MemoryAccessVarHandleGenerator, which is now removed) now all var handles can be derived from a primitive from which takes a segment and a byte offset. This caused the removal of several methods in the JavaLangInvokeAccess interface.

The new memory segment interface has some more methods to perform slicing - which can basically be used to give a new base to an existing segment and can therefore be used in a lot of cases as a replacement for MemoryAddress::addOffset.

The memory address interface is simplified, and features an additional segmentOffset method, which returns the byte offset of an address relative to the given segment (this is similar to the old MemorySegment::rebase method, which is now removed).

The MemoryAccess class needed a lot of tweaks in the various signatures, to take a segment instead of a base address.

I tried to update the documentation as best as I could, but it's possible I missed some references to the old relationship between segment and addresses, please double check.

Of course integrating this patch is gonna cause issues in foreign-abi and foreign-jextract, as these branches make (heavy) use of memory access var handles. I suspect that integration will trigger a merge failure, so we can fix followup issues as part of the merge process, so that we can guarantee that all the branches remain buildable.


Progress

  • Change must not contain extraneous whitespace
  • Change must be properly reviewed

Issue

Reviewers

Download

$ git fetch https://git.openjdk.java.net/panama-foreign pull/260/head:pull/260
$ git checkout pull/260

@bridgekeeper
Copy link

bridgekeeper bot commented Jul 22, 2020

👋 Welcome back mcimadamore! A progress list of the required criteria for merging this PR into foreign-memaccess will be added to the body of your pull request.

@openjdk openjdk bot added the rfr Ready for review label Jul 22, 2020
@mlbridge
Copy link

mlbridge bot commented Jul 22, 2020

Webrevs

Copy link
Collaborator

@slowhog slowhog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good to me.
The change in LayoutPath looks reasonable, but I cannot assure I fully get it. Assuming we have enough test coverage. :)

/** alignment constraint (in bytes, expressed as a bit mask) **/
final long alignmentMask;

MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask) {
/** alignment constraint (in bytes, expressed as a bit mask) **/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment need to be updated

@@ -313,27 +313,32 @@ else if (viewComponentType == float.class) {
* @param carrier the Java carrier type.
* @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need comment for skipOffsetCheck

} else {
if ((address & alignmentMask) != 0) {
throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a little odd to me, as there is no performance gain with skipOffsetCheck.

The else block check only address but not base and offset separately is not the same, although I think that's correct as it's what matters.

However, if this is desired, I don't see why we don't simply check address without the difference.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The final address is the sum of two components - a base B and an offset O. In a hot loop, B is typically constant (e.g. the base address of a segment) while O keeps changing. So, if the alignment check is only performed on B, the VM can prove that this check can be hoisted outside the loop. Of course that leaves the correctness problem - e.g. what if B is aligned but B + O is not? Luckily, by construction, this is not possible - skipOffsetCheck is only set when we construct a memory access var handle from a layout - and in that case the layout API make sure that the O part of the final address is aligned accordingly.

So, while it "looks" as if there's no performance gain, in reality the gain is quite big, because that move allows the alignment check to be moved outside the loop.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation

* and whose new size is computed by subtracting the specified offset from this segment size.
* @param offset The new segment base offset (relative to the current segment base address), specified in bytes.
* @return a new memory segment view with updated base/limit addresses.
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}

* (see {@link MemoryAddress#segmentOffset(MemorySegment)}) from this segment size.
* @param address The new segment base offset (relative to the current segment base address), specified in bytes.
* @return a new memory segment view with updated base/limit addresses.
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address.segmentOffset can throw IllegalArgumentException.
As IndexOutOfBoundException maybe simply saying the calculated offset < 0 or > byteSize()

@openjdk
Copy link

openjdk bot commented Jul 22, 2020

@mcimadamore This change now passes all automated pre-integration checks, type /integrate in a new comment to proceed. After integration, the commit message will be:

8249879: Split MemorySegment and MemoryAddress

Reviewed-by: henryjen, psandoz, jvernee
  • If you would like to add a summary, use the /summary command.
  • To credit additional contributors, use the /contributor command.
  • To add additional solved issues, use the /issue command.

Since the source branch of this PR was last updated there have been 76 commits pushed to the foreign-memaccess branch:

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid automatic rebasing, please merge foreign-memaccess into your branch, and then specify the current head hash when integrating, like this: /integrate 00986e8234468f7a7fa0ee250be7ac313fa3de7a.

➡️ To integrate this PR with the above commit message to the foreign-memaccess branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Ready to be integrated label Jul 22, 2020
//note: the offset portion has already been aligned-checked, by construction
if ((base & alignmentMask) != 0) {
throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address);
if (skipOffsetCheck) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two alignment checks, one to the type size in bytes itself, and another to presumably multiples of the type size, otherwise the first would fail. The name of skipOffsetCheck is a little confusing, skipAlignmentMaskCheck would be more verbose but accurate. Documenting the rational on MemoryAccessVarHandleBase would i think help maintainers/reviewers of the code.

@@ -46,37 +46,20 @@
* (all primitive types but {@code void} and {@code boolean} are supported), as well as the alignment constraint and the
* byte order associated to a memory access var handle. The resulting memory access var handle can then be combined in various ways
* to emulate different addressing modes. The var handles created by this class feature a <em>mandatory</em> coordinate type
* (of type {@link MemoryAddress}), and zero or more {@code long} coordinate types, which can be used to emulate
* multi-dimensional array indexing.
* (of type {@link MemorySegment}), and one {@code long} coordinate types, which represents the offset, in bytes, relative
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/type/types

@@ -125,7 +105,7 @@ default MemoryAddress address() {
* The <em>unchecked</em> memory address instance modelling the {@code NULL} address. This address is <em>not</em> backed by
* a memory segment and hence it cannot be dereferenced.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refers to "backed by a memory segment".

*/
long segmentOffset();
long segmentOffset(MemorySegment segment);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth explaining how this works e.g. equivalent to this.toRawLongValue() - segment.address().toRawLongValue(), and pointing out the resulting offset can be beyond the spatial bounds of the segment (negative value, or greater).

Copy link
Member

@PaulSandoz PaulSandoz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice collapsing of code.

@@ -147,15 +146,15 @@ public int segment_loop() {
public int segment_loop_static() {
int res = 0;
for (int i = 0; i < ELEM_SIZE; i ++) {
res += MemoryAccess.getIntAtIndex(segment.address(), i);
res += MemoryAccess.getIntAtIndex(segment, i * CARRIER_SIZE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this multiply by CARRIER_SIZE? That should be done by the accessor.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mistake - will fix (but this has nothing to do with this patch, I think?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this patch adds the multiply...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this patch adds the multiply...

Ugh - that's a bug then

@mcimadamore
Copy link
Collaborator Author

/integrate

@openjdk openjdk bot closed this Jul 27, 2020
@openjdk openjdk bot added integrated Pull request has been integrated and removed ready Ready to be integrated rfr Ready for review labels Jul 27, 2020
@openjdk
Copy link

openjdk bot commented Jul 27, 2020

@mcimadamore The following commits have been pushed to foreign-memaccess since your change was applied:

  • 00986e8: Automatic merge of master into foreign-memaccess
  • ca19721: Automatic merge of jdk:master into master
  • 8b005fa: 8249945: Improve ARRAY_SIZE()
  • 26680f0: 8248668: AArch64: Avoid MIN/MAX macros when using MSVC
  • eaeb435: 8249225: Move definition of PADDING_ELEM_NUM
  • 22006dc: 8249781: AArch64: AOT compiled code crashes if C2 allocates r27
  • df923ff: 8249944: Move and improve the AllStatic class
  • 55b19e8: 8247908: Replace IsRegisteredEnum with std::is_enum
  • 0ef8029: 8250240: Address use of default constructors in the java.util.concurrent
  • 1f91e0e: 8194309: JNI handle allocation failure not reported correctly
  • e427697: 8246373: AArch64: Refactor register spilling code in ZGC barriers
  • 5c8a154: 8250237: Address use of default constructors in the javax.script package
  • 2abefad: 8250236: ProblemList java/lang/invoke/lambda/LambdaFileEncodingSerialization.java on linux-x64
  • 9f23c2c: 8249812: java/net/DatagramSocket/PortUnreachable.java still fails intermittently with SocketTimeoutException
  • 6d665ed: 8249192: MonitorInfo stores raw oops across safepoints
  • bb6647c: 8250221: Address use of default constructors in java.logging
  • 6e198fe: 8249197: JShell: variable declaration with unicode type name gets garbled result
  • 5088193: 8249630: unused is_static_archive parameter in SystemDictionaryShared::write_dictionary
  • 8b87402: 8247592: refactor test/jdk/tools/launcher/Test7029048.java
  • 1f63603: 8248655: Support supplementary characters in String case insensitive operations
  • dc80e63: 8249953: Shenandoah: gc/shenandoah/mxbeans tests should account for corner cases
  • 63d2421: 8249888: failure to create a libgraal JavaVM should result in a VM crash
  • 993b1b0: 8249612: Remove unused ISNANF and ISNAND from jdk_util_md.h
  • 2f8653f: 8248666: AArch64: Use THREAD_LOCAL instead of __thread
  • 1b1c1cd: 8249940: Remove unnecessary includes of jni_util.h in native tests
  • 401d3ea: 8249875: GCC 10 warnings -Wtype-limits with JFR code
  • 9cf96bf: Merge
  • 668acc7: Added tag jdk-16+7 for changeset c3a4a7ea7c30
  • 54ad4f9: Added tag jdk-15+33 for changeset 6b65f4e7a975
  • f8a06bc: 8245311: [macos] misc package tests failed due to "execution error: Finder got an error: AppleEvent timed out."
  • 33016a8: 8249880: JVMCI calling register_nmethod without CodeCache lock
  • a764279: 8249880: JVMCI calling register_nmethod without CodeCache lock
  • 9b42f47: 8249884: Shenandoah: Call report_num_dead() from ShParallelWeakRootsCleaningTask destructor
  • 2d8e74d: 8249768: Move static oops and NullPointerException oops from Universe into OopStorage
  • 4d43cf9: 8222187: java.util.Base64.Decoder stream adds unexpected null bytes at the end
  • 45e17d8: 8249877: Shenandoah: Report number of dead weak oops during STW weak roots
  • 18cf3d8: 8247743: Segmentation fault in debug builds due to stack overflow in find_recur with deep graphs
  • 4f99e1f: 8248467: C2: compiler/intrinsics/object/TestClone fails with -XX:+VerifyGraphEdges
  • 73c75ed: 8249650: Optimize JNIHandle::make_local thread variable usage
  • 2a8f92e: 8246032: Implementation of JEP 347: Enable C++14 Language Features
  • 39b22d1: 8242895: failed: sanity at src/hotspot/share/opto/escape.cpp:2361
  • dff37f8: 8248671: AArch64: Remove unused variables
  • 9ff01f7: Merge
  • c7b074a: 8249713: JFR: java.base events have incomplete stacktraces
  • f8c1d79: 8249697: remove temporary fixes from java/lang/invoke/RicochetTest.java
  • cd98f7d: 8249672: Include microcode revision in features_string on x86
  • 006d0bc: 8249801: Shenandoah: Clear soft-refs on requested GC cycle
  • a20c318: 8249748: gtest silently ignores bad jvm arguments
  • d116022: 8249774: Add java/foreign/TestMismatch.java to ProblemList.txt
  • 35554ea: 8217527: jmod hash does not work if --hash-module does not include the target module
  • 3a69dfb: 8245652: some tests at RecordCompilationTests are resetting the wrong compilation options
  • 8d97637: 8249700: java/io/File/GetXSpace.java should be added to exclude list, and not @Ignore-d
  • af0d6d2: 8249698: java/lang/invoke/LFCaching/LFGarbageCollectedTest.java should be ProblemList-ed and not @ignored
  • 6ee76b6: 8249760: Unnecessary #include oopStorageSet
  • ac38b39: 8249681: gc/stress/TestJNIBlockFullGC/TestJNIBlockFullGC.java fails w/ UnsatisfiedLinkError
  • 4a4003e: 8249678: @ignore should be used instead of ProblemList for 8158860, 8163894, 8193479, 8194310
  • 1c882d9: 8249673: cleanup graal problem lists
  • 24a7d8c: 8249622: use 8249621 to ignore 8 jvmci tests
  • d63aebe: 8246381: VM crashes with "Current BasicObjectLock* below than low_mark"
  • 4320afb: 8242935: test/jdk/java/util/ServiceLoader/ReloadTest.java uses nashorn script engine
  • 546158f: 8249543: Force DirectBufferAllocTest to run with -ExplicitGCInvokesConcurrent
  • 9694ca9: 8249560: Shenandoah: Fix racy GC request handling
  • 3770be7: 8249367: JShell uses 100% of one core all the time
  • 3e0dc68: 8248901: Signed immediate support in .../share/assembler.hpp is broken
  • ba2caf0: 8249720: Generated bytecodes of EventWriter don't be output to the log
  • 907719b: 8245694: java.util.Properties.entrySet() does not override Object methods
  • 99eccaf: 8247878: Move Management strong oops to OopStorage
  • c7d8485: 8248414: AArch64: Remove uses of long and unsigned long ints
  • ec07401: Merge
  • 9376dd8: 8236042: [TESTBUG] serviceability/sa/ClhsdbCDSCore.java fails with -Xcomp -XX:TieredStopAtLevel=1
  • 5d27067: 8249649: Shenandoah: provide per-cycle pacing stats
  • b7c307c: 8249687: Use inline @jls and @jvm tages in more places in java.base
  • d1d1720: 8249632: remove no-arg constructor from ToolProvider
  • 59cd79a: 8247734: [macos] jpackage fails to retrieve signing certificate when there are multiple
  • 7339cf8: 8247615: Initialize the bytes left for the heap sampler
  • 2f6afe5: 8249289: Exception thrown when --temp points to non-existant directory

Your commit was automatically rebased without conflicts.

Pushed as commit 21442f6.

@mcimadamore mcimadamore deleted the segment-address-split branch November 13, 2020 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

None yet

4 participants