Skip to content

Conversation

@magicus
Copy link
Member

@magicus magicus commented Oct 13, 2021

This patch expands the newly added system for hsdis backends to include LLVM.

The actual code in hsdis-llvm.cpp is based heavily on the work by @luhenry, as published in the never integrated PR #392. (I have basically just ripped out the binutils-based part of it.)

Unfortunately I have not been able to make this work properly on Windows. With some additional flags I made it compile without complaints, but it caused hotspot to segfault in LoadLibrary (!) in os::dll_load when I tried to load the library. This is somewhat ironic, since the initial implementation was created by Ludovic for the very purpose of using it on Windows.

The lack of Windows support in this patch does not mean it is impossible to get it to work, just that I need to co-operate with someone who has more experience of compiling LLVM on Windows, and/or are more eager to get this combination to work.


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

Reviewers

Contributors

  • Magnus Ihse Bursie <ihse@openjdk.org>
  • Ludovic Henry <luhenry@openjdk.org>
  • Nick Gasson <ngasson@openjdk.org>

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/5920/head:pull/5920
$ git checkout pull/5920

Update a local copy of the PR:
$ git checkout pull/5920
$ git pull https://git.openjdk.java.net/jdk pull/5920/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 5920

View PR using the GUI difftool:
$ git pr show -t 5920

Using diff file

Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/5920.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 13, 2021

👋 Welcome back ihse! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@magicus
Copy link
Member Author

magicus commented Oct 13, 2021

/contributor add ihse
/contributor add luhenry

@openjdk openjdk bot added the rfr Pull request is ready for review label Oct 13, 2021
@openjdk
Copy link

openjdk bot commented Oct 13, 2021

@magicus
Contributor Magnus Ihse Bursie <ihse@openjdk.org> successfully added.

@openjdk
Copy link

openjdk bot commented Oct 13, 2021

@magicus
Contributor Ludovic Henry <luhenry@openjdk.org> successfully added.

@openjdk
Copy link

openjdk bot commented Oct 13, 2021

@magicus The following labels will be automatically applied to this pull request:

  • build
  • hotspot-compiler

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.

@openjdk openjdk bot added build build-dev@openjdk.org hotspot-compiler hotspot-compiler-dev@openjdk.org labels Oct 13, 2021
@mlbridge
Copy link

mlbridge bot commented Oct 13, 2021

@JornVernee
Copy link
Member

but it caused hotspot to segfault in LoadLibrary (!) in os::dll_load when I tried to load the library.

I tried compiling the binutils-based hsdis earlier as well, but on WSL instead of cygwin (using the mingw-w64 package), and ran into the same issue. It kept segfaulting when loading the library.

My guess was that it is a problem caused by mixing libraries that are compiled with different toolchains, as the JDK itself is compiled with MSVC.

AFAIK binutils can only be built with mingw (based on my earlier experiments), but LLVM can be built with MSVC as well, so maybe the regular MSVC toolchain could be used to build the llvm-based hsdis.

@luhenry
Copy link
Member

luhenry commented Oct 13, 2021

Very happy to see it landing :) Thank you!

I don't have access to a windows machine, and even less a Windows-AArch64 machine. @lewurm would you be able to take a look?

@magicus
Copy link
Member Author

magicus commented Oct 13, 2021

@JornVernee It is likely that the LLVM-based backend can be build by MSVC, yes. I did not explore that further in this patch. I suggest that the way forward is to get this patch into mainline, and then experiment with how to get Windows support working properly. (The main problem with the MSVS approach is that the LLVM libraries, as returned by llvm-config, is in gcc format (-lLLFoobarnicator) which we can't send to CL. (It seems Ludovic tried to work around this by transforming the command line in his original PR.)

@openjdk
Copy link

openjdk bot commented Oct 13, 2021

@magicus 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:

8253757: Add LLVM-based backend for hsdis

Co-authored-by: Magnus Ihse Bursie <ihse@openjdk.org>
Co-authored-by: Ludovic Henry <luhenry@openjdk.org>
Co-authored-by: Nick Gasson <ngasson@openjdk.org>
Reviewed-by: erikj, luhenry

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 10 new commits pushed to the master branch:

  • d5b4666: 8281829: runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java fails after JDK-8281467
  • fef5d74: 8281812: x86: Use short jumps in TemplateTable::condy_helper
  • a86cab8: 8236136: tests which use CompilationMode shouldn't be run w/ TieredStopAtLevel
  • 0af356b: 8278173: [vectorapi] Add x64 intrinsics for unsigned (zero extended) casts
  • a24498b: 8281771: Crash in java_lang_invoke_MethodType::print_signature
  • 1aff44b: 8279949: JavaThread::_free_handle_block leaks native memory
  • 394ce5f: 8280825: Modules that "provide" ToolProvider should document the name that can be used
  • 745f7e7: 8281186: runtime/cds/appcds/DumpingWithNoCoops.java fails
  • 1870465: 8281744: x86: Use short jumps in TIG::set_vtos_entry_points
  • 2fe0bf6: 8281748: runtime/logging/RedefineClasses.java failed "assert(addr != __null) failed: invariant"

Please see this link for an up-to-date comparison between the source branch of this pull request and the master branch.
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

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

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Oct 13, 2021
@JornVernee
Copy link
Member

JornVernee commented Oct 13, 2021

In my experience the output of llvm-config is also not usable. I think the output also depends on the toolchain you use to build llvm FWIW. The output of my locally built llvm-config does contain the MSVC flags, but the paths it points to are incorrect (all pointing to the build directory, instead of the package install location).

I have a patch here that gets me a working hsdis based on the llvm package I built manually using MSVC (the official package doesn't seem to contain the needed header files): pr/5920...JornVernee:hsdis_llvm_windows

(The only issue currently is that the code I used to filter out the incorrect -I flags from what llvm-config gives me doesn't seem to work, though the build still passes).

I built llvm using something like this (according to my notes):

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build_llvm
cd build_llvm
cmake ../llvm -D"LLVM_TARGETS_TO_BUILD:STRING=X86" -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_INSTALL_PREFIX=install_local" -A x64 -T host=x64
cmake --build . --config Release --target install

This then uses MSVC to build me an llvm 'package' in build_llvm/install_local, which I then point to using --with-llvm.

The only other issue I had is that install-hsdis only copies the library to the exploded JDK, so I manually copy it to images/jdk/bin/server afterwards.

As you say, Windows support can be added later, so this doesn't need to be added to the current patch IMO. But, I might not have time to get back to this myself, so just leaving the steps I used that worked for me in case anyone else wants to pick it up as well.

@theRealAph
Copy link
Contributor

This patch expands the newly added system for hsdis backends to include LLVM.

The actual code in hsdis-llvm.cpp is based heavily on the work by @luhenry, as published in the never integrated PR #392. (I have basically just ripped out the binutils-based part of it.)

Unfortunately I have not been able to make this work properly on Windows.

What is it for, then?

hsdis builds on AArch64-MacOS-LLVM with

  cd src/utils/hsdis
  mkdir build
  cd build
  git clone https://github.com/bminor/binutils-gdb
  ln -s binutils-gdb binutils
  cd ..
  make

@magicus
Copy link
Member Author

magicus commented Oct 13, 2021

@theRealAph As you might be aware, the licensing criteria for binutils makes it impossible to distribute a binutils-based hsdis with the JDK. While IANAL, my understanding is that the LLVM license is less problematic in that way.

Also, this is to allow a bit of freedom of choice. If you prefer the LLVM backend (I've been told that it generates better disassembly in some case) you should be able to select it.

And finally, I do think that the LLVM backend should be able to work on Windows, too. It's just that this is tricky enough to motivate doing this in a separate, later, step.

@magicus
Copy link
Member Author

magicus commented Oct 13, 2021

The only other issue I had is that install-hsdis only copies the library to the exploded JDK, so I manually copy it to images/jdk/bin/server afterwards.

@JornVernee Ah, good point! I need to make sure it gets copied to the image as well.

And thank you for your patch, I'll have a look at it and see if I can incorporate it in this patch, or if it's better to make it a separate patch. It's worth noting that I used the llvm package from cygwin, neither the "official" package nor a self-built. I can imagine that the self-built works better, so it might be worth adding a --with-llvm-src option to help build it as well.

@theRealAph
Copy link
Contributor

@theRealAph As you might be aware, the licensing criteria for binutils makes it impossible to distribute a binutils-based hsdis with the JDK. While IANAL, my understanding is that the LLVM license is less problematic in that way.

Also, this is to allow a bit of freedom of choice. If you prefer the LLVM backend (I've been told that it generates better disassembly in some case) you should be able to select it.

And finally, I do think that the LLVM backend should be able to work on Windows, too. It's just that this is tricky enough to motivate doing this in a separate, later, step.

OK, but how do you build it? I have applied this patch, and the instructions in hsdis/README don't mention LLVM, just binutils. Shouldn't the instructions have been updated?

@theRealAph
Copy link
Contributor

So I figured out how to build it with make build-hsdis. The instructions need to be fixed.

Two problems: firstly, the library seems to be built with the wrong name, so the runtime doesn't find it. I had to use
ln -sf ~/lib/libhsdis.dylib ~/lib/hsdis-aarch64.dylib
to get it to work.

More severely, the disassembly is truncated, so lots of stuff doesn't work. The binutils-based hsdis prints


 0x00000001105665b4:   stp     wzr, wzr, [x20, #60]        ;*putfield preCounterBlock {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - com.sun.crypto.provider.GaloisCounterMode$GCMEngine::<init>@80 (line 673)
                                                            ; - com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt::<init>@8 (line 1346)
                                                            ; - com.sun.crypto.provider.GaloisCounterMode::checkInit@60 (line 329)
 ;; B6: #       out( B242 B7 ) <- in( B192 B5 )  Freq: 0.999999
  0x00000001105665b8:   cbnz    x21, 0x00000001105665c8
 ;; null oop passed to encode_heap_oop_not_null2
  0x00000001105665bc:   dcps1   #0xdeae
  0x00000001105665c0:   .inst   0x082adca6 ; undefined
  0x00000001105665c4:   udf     #1
  0x00000001105665c8:   lsr     x10, x21, #3                ;*invokevirtual getLongUnaligned {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - java.lang.invoke.VarHandleByteArrayAsLongs$ArrayHandle::get@32 (line 115)
   ... lots more

but the llvm-based one stops here:

  0x000000010ed79034:           stp     wzr, wzr, [x20, #0x3c];*putfield preCounterBlock {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - com.sun.crypto.provider.GaloisCounterMode$GCMEngine::<init>@80 (line 673)
                                                            ; - com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt::<init>@8 (line 1346)
                                                            ; - com.sun.crypto.provider.GaloisCounterMode::checkInit@60 (line 329)
 ;; B6: #       out( B242 B7 ) <- in( B192 B5 )  Freq: 0.999999
  0x000000010ed79038:           cbnz    x21, #0x10
 ;; null oop passed to encode_heap_oop_not_null2
  0x000000010ed7903c:           dcps1   #0xdeae
  0x000000010ed79040:   --------------------------------------------------------------------------------
[/Disassembly]

I think it's giving up as soon as it sees something it doesn't recognize, so it's pretty much useless.

In addition, even when it does work the LLVM disassembly is pretty poor. For example, the unverified entry point looks like

  0x000000010ed78f80:           ldr     w8, [x1, #0x8]
  0x000000010ed78f84:           cmp     w9, w8
  0x000000010ed78f88:           b.eq    #0x10
  0x000000010ed78f8c:           adrp    x8, #-128524288     ;   {runtime_call ic_miss_stub}
  0x000000010ed78f90:           add     x8, x8, #0x1c0
  0x000000010ed78f94:           br      x8

instead of

  0x0000000110566500:   ldr     w8, [x1, #8]
  0x0000000110566504:   cmp     w9, w8
  0x0000000110566508:   b.eq    0x0000000110566518  // b.none
  0x000000011056650c:   adrp    x8, 0x0000000108ae6000      ;   {runtime_call ic_miss_stub}
  0x0000000110566510:   add     x8, x8, #0x1c0
  0x0000000110566514:   br      x8

Sure, it's good to have a choice, but the LLVM-based hsdis doesn't look to me like a serious alternative for professional work.

@magicus
Copy link
Member Author

magicus commented Oct 14, 2021

@theRealAph Yes, the build instructions needs to be updated. I could have sworn I did that, but maybe that fix is just lying around un-committed in one of my repos on one of my test computers. I'll have to go around and check. Or write it again if I can't fix it. That needs to go with this PR.

You can do make install-hsdis to avoid doing the symlinking yourself. As Jorn pointed out, there is currently a bug in that the library does not get copied from the "exploded jdk" to the image. I will fix that in an upcoming commit to this PR.

As for LLVM not giving you a good user experience; I can't really tell what's wrong. Apparently @luhenry (and @JornVernee I believe) has used this. I'm not really the target audience myself; I'm only trying to make it possible to use. If it is so severly limited as you say maybe this isn't worth pursuing. Some feedback from those who have tested it would be appeciated here, to help med understand if this patch should be dropped.

@theRealAph
Copy link
Contributor

As for LLVM not giving you a good user experience; I can't really tell what's wrong. Apparently @luhenry (and @JornVernee I believe) has used this. I'm not really the target audience myself; I'm only trying to make it possible to use. If it is so severly limited as you say maybe this isn't worth pursuing. Some feedback from those who have tested it would be appeciated here, to help med understand if this patch should be dropped.

I don't think it should be dropped, but I imagine that the bugs can be fixed. If LLVM's disassembler always dies as soon as it sees something it can't recognize, I'm astonished. Maybe the LLVM I'm using is bad.

@JornVernee
Copy link
Member

Some feedback from those who have tested it would be appeciated here

I haven't really tested it beyond building the lib and seeing if assembly was output instead of just bytes, so I can't really comment on that I'm afraid.

Since the binutils hsdis wasn't buildable on Windows for me in the past, I've always been using the fcml based hsdis on Windows.

@luhenry
Copy link
Member

luhenry commented Oct 15, 2021

The value add of this LLVM-based hsdis is two-fold:

  • It supports platforms that aren't supported by binutils (Windows-AArch64 for example)
  • The license being more permissive would allow to build it as part of the OpenJDK build more easily (and even maybe ship it?)

LLVM has a strong track record of supporting new platforms (Windows-AArch64 and macOS-AArch64 for example, mostly because of investment from Microsoft and Apple respectively), and hsdis is a necessary tool for porting the OpenJDK to any new platform. Since the maintenance is fairly low (small codebase, small and knowledgable user base), I would be biased towards including it with appropriate warnings.

@mlbridge
Copy link

mlbridge bot commented Oct 15, 2021

Mailing list message from monica beckwith on hotspot-compiler-dev:

Hi all,

I am on vacation right now, but we can take a look next week and see how we
can support the LLVM backend for hsdis. It is much required by
Windows-AArch64 and we would hate for all the good work to not make it
upstream.

Monica

Sent from my Arm powered smart device.

On Thu, Oct 14, 2021, 9:07 AM Andrew Haley <aph at openjdk.java.net> wrote:

@theRealAph
Copy link
Contributor

Since the maintenance is fairly low (small codebase, small and knowledgable user base), I would be biased towards including it with appropriate warnings.

I don't think we should commit code that we know is broken. I don't believe that this view might be controversial.
Maybe someone should try to reproduce the failure I've seen, and then we should look at fixing it. Maybe it's a local problem.

Also, this patch breaks all current hsdis builds that follow the installation instructions. Either we get revised instructions or the build should be fixed.

@magicus
Copy link
Member Author

magicus commented Oct 16, 2021

@theRealAph We should not push broken code, and we should not break the existing build of hsdis. I fully agree with this. I will not push this patch until all reviewers are happy, so you don't need to worry about that. :)

My initial plan was to get the unix platforms working in this push, and tackle Windows later on, but it seems now that it's better to keep this PR around for a bit longer instead, and fold Windows support into it as well. (Which means I'll wait for Monica to return and being able to test and help out.)

I need to understand better why things are failing for you. Can you describe a reproducer?

@theRealAph
Copy link
Contributor

Can you describe a reproducer?
Sure. Create a .hotspot_compiler file containing print java.lang.String::checkIndex then

Sorry, thinko. You don't need the .hotspot_compiler file

@nick-arm
Copy link
Contributor

The problem is LLVMDisasmInstruction() returns zero size as soon as it hits an instruction it doesn't understand. Something kludgy like this works:

diff --git a/src/utils/hsdis/llvm/hsdis-llvm.cpp b/src/utils/hsdis/llvm/hsdis-llvm.cpp
index a491082f14fa..3c50ee8e3b40 100644
--- a/src/utils/hsdis/llvm/hsdis-llvm.cpp
+++ b/src/utils/hsdis/llvm/hsdis-llvm.cpp
@@ -307,6 +307,10 @@ class hsdis_backend : public hsdis_backend_base {
   virtual size_t decode_instruction(uintptr_t p, uintptr_t start, uintptr_t end) {
     char buf[128];
     size_t size = LLVMDisasmInstruction(_dcontext, (uint8_t*)p, (uint64_t)(end - start), (uint64_t)p, buf, sizeof(buf));
+    if (size == 0 && end - start >= 4) {
+      snprintf(buf, sizeof(buf), "\t.word\t#0x%08x", *(uint32_t*)p);
+      size = 4;
+    }
     if (size > 0) {
       (*_printf_callback)(_printf_stream, "%s", buf);
     }
  0x0000ffff94685454:           br      x8
  0x0000ffff94685458:           .word   #0x93e3f4c0
  0x0000ffff9468545c:           udf     #0xffff
[Exception Handler]
  0x0000ffff94685460:           adrp    x8, #-0x795000      ;   {runtime_call handle_exception_from_callee Runtime1 stub}

@nick-arm
Copy link
Contributor

Rather than introduce a new dependency on all of LLVM you might like to take a look at Capstone - https://www.capstone-engine.org/ . AFAIK the disassemblers are generated from the same LLVM architecture description files so the instruction coverage should be the same but the library is much more lightweight. It's packaged in most Linux distributions and there's pre-built Windows binaries available.

@magicus
Copy link
Member Author

magicus commented Oct 20, 2021

@nick-arm That'd introduce a new dependency to Capstone. ;-)

But your suggestion is excellent -- in fact, I have a branch in my personal fork that builds hsdis with Capstone as backend. I just scheduled for myself to submit this PR first. (Which maybe was a mistake; it was obviously more tricky to get right than I anticipated.) I might reconsider that choice and let this PR wait until I've pushed the Capstone backend first, instead.

@bridgekeeper
Copy link

bridgekeeper bot commented Nov 17, 2021

@magicus 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!

@magicus
Copy link
Member Author

magicus commented Nov 17, 2021

Yeah bot, I'm still working on it.

@bridgekeeper
Copy link

bridgekeeper bot commented Dec 15, 2021

@magicus 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!

@swesonga
Copy link
Contributor

swesonga commented Jan 11, 2022

@magicus @JornVernee Thank you for starting this PR and for the notes on the Windows changes. I'm trying them out on macOS and Windows.

@theRealAph I'm not as familiar with the mac platform. Did you need to do anything special to address these errors? I was adding -L/opt/homebrew/opt/llvm/lib to the HSDIS_LDFLAGS.

  "_LLVMCreateDisasm", referenced from:
      hsdis_backend::hsdis_backend(unsigned long, unsigned long, unsigned char*, unsigned long, void* (*)(void*, char const*, void*), void*, int (*)(void*, char const*, ...), void*, char const*, int) in hsdis-llvm.o
  "_LLVMDisasmDispose", referenced from:
      hsdis_backend::~hsdis_backend() in hsdis-llvm.o
...
ld: symbol(s) not found for architecture arm64
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)

@swesonga
Copy link
Contributor

@magicus @JornVernee Thank you for starting this PR and for the notes on the Windows changes. I'm trying them out on macOS and Windows.

@theRealAph I'm not as familiar with the mac platform. Did you need to do anything special to address these errors? I was adding -L/opt/homebrew/opt/llvm/lib to the HSDIS_LDFLAGS.

  "_LLVMCreateDisasm", referenced from:
      hsdis_backend::hsdis_backend(unsigned long, unsigned long, unsigned char*, unsigned long, void* (*)(void*, char const*, void*), void*, int (*)(void*, char const*, ...), void*, char const*, int) in hsdis-llvm.o
  "_LLVMDisasmDispose", referenced from:
      hsdis_backend::~hsdis_backend() in hsdis-llvm.o
...
ld: symbol(s) not found for architecture arm64
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)

Turns out I just needed to add /opt/homebrew/opt/llvm/bin to my PATH. I can now use --with-hsdis=llvm.

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 9, 2022

@magicus 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!

@magicus
Copy link
Member Author

magicus commented Feb 10, 2022

Yes bot, thank you for the reminder.

@magicus magicus marked this pull request as draft February 15, 2022 15:03
@openjdk
Copy link

openjdk bot commented Feb 15, 2022

@magicus this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout hsdis-backend-llvm
git fetch https://git.openjdk.java.net/jdk master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@openjdk openjdk bot added merge-conflict Pull request has merge conflict with target branch and removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Feb 15, 2022
@openjdk openjdk bot added ready Pull request is ready to be integrated and removed merge-conflict Pull request has merge conflict with target branch labels Feb 15, 2022
@magicus
Copy link
Member Author

magicus commented Feb 15, 2022

/contributor add @nick-arm

@openjdk
Copy link

openjdk bot commented Feb 15, 2022

@magicus
Contributor Nick Gasson <ngasson@openjdk.org> successfully added.

@magicus
Copy link
Member Author

magicus commented Feb 16, 2022

This PR has just gotten too messy. :-( I'll close this one for now, focus on getting the (much simpler) Capstone backend integrated, and then I can come back and revisit this functionality, but in a fresh new PR.

@magicus magicus closed this Feb 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build build-dev@openjdk.org hotspot-compiler hotspot-compiler-dev@openjdk.org ready Pull request is ready to be integrated

Development

Successfully merging this pull request may close these issues.

7 participants