RFR: 8017234: Hotspot should stop using mapfiles
Magnus Ihse Bursie
ihse at openjdk.org
Wed Feb 21 23:37:01 UTC 2024
On Wed, 21 Feb 2024 23:32:15 GMT, Magnus Ihse Bursie <ihse at openjdk.org> wrote:
> **Summary:** Finally get rid of the mapfiles in Hotspot, and replace it with compiler options and JNIEXPORT on all platforms.
>
> The bug that this PR solves, [JDK-8017234](https://bugs.openjdk.org/browse/JDK-8017234), was created in 2013. Even back then the use of mapfiles in Hotspot was dated, so this is really good riddance with old rubbish.
>
> This code touches on central but not well understood parts of the Hotspot dynamic library, which has contributed to why this bug has stayed unresolved for so long. I will need to explain this fix in more detail than usually necessary. (Please bare with me if this gets long.) I also anticipate that not all solutions that I've picked will be accepted, and we'll have to discuss how to proceed. I think it is better to have actual concrete code to discuss around, rather than starting by an abstract discussion. To keep this description short, I will post the discussion as a comment to the PR.
>
> I have run this PR through tier 1-3 in our CI system. I have also carefully checked how the resulting dynamic library differs with this patch (not much; see discussion below). For build system changes, this is often the most relevant metric.
First some general notes on related build changes: This was the last place in the build system where mapfiles where used. It will now be possible to clean up a lot of this framework, but I will do that separately after this has been integrated. Also, Hotspot is now built much closer to the rest of the native libraries in the JDK, so there is potential for more unification (e.g. placing `--exclude-libs,ALL` in a common location). This too will be done separately.
On Windows, we still need to do the dance of finding symbols from the object files, and add them to a list of exported files (included by `-def:`). I decoupled this logic away from the old mapfile stuff, so we can safely delete the mapfile code later on. So what might look like new code in `CompileJvm.gmk` is actually just old code from `JvmMapfile.gmk` that I have cleaned up somewhat. These symbols are consumed by SA. It might be that we can limit the amount of symbols exported this way, or maybe that we can find another solution completely in SA, but that will have to be a future topic for research. For now, we keep the same exported symbols.
I have checked the resulting libjvm.so/jvm.dll using the `COMPARE_BUILD` functionality, which (among other things) analyzes differences between native libraries before and after a patch. This has verified that there is no change in the symbols of the Hotspot dynamic library on macOS/x64, macOS/aarch64 or Windows/x64. I have also gotten help from @MBaesken and @JoKern65 to confirmed that there is no effect on AIX (in fact, AIX never used the mapfile it created...). There are, however, a few minor changes on linux/x64 and linux/aarch64. I will discuss these below.
When I first started doing this conversion, I got a lot more differences.
First of all, the `-fvisibility=hidden` flag does not apply to assembly files, so the symbols marked `.global` in these files also needed to be marked `.hidden`. (On macOS, Apple's clang assembler uses the directive `.private_extern` instead.) The assembly files had some inconsistent whitespace (using tabs instead of spaces every once in a while), which my editor kept changing, so I gave up and fixed all of them. This makes the diff artificially larger; if someone objects to this I can revert the whitespace changes.
Secondly, it turned out that there were several symbols declared `JNIEXPORT` that were not included in the symbol list, and hence were not exported on Linux. In contrast to Windows, which only relies on `JNIEXPORT`, on Linux it was necessary to both use `JNIEXPORT` and declare the symbol in the symbol list to get it actually exported.
To be consistent with the old behavior, I have undefined `JNIEXPORT` in these files. It works to keep the output the same, but it does not look very nice. I suggest we either:
a) say we want to remove this `#undef` and actually export the functions annotated `JNIEXPORT`. This is what I would recommend. If so, let's keep the ugly undef for now, and I'll remove it in a follow-up bug. (I really would like not to change any behavior with this patch; it is intrusive enough as it is.)
b) say we really don't want to export these functions on Linux, only on Windows. In that case, we should probably replace `JNIEXPORT` with `FOO_EXPORT`, and define `FOO_EXPORT` to be `JNIEXPORT` on Windows, and blank on Linux.
This is a decision for the Hotspot team; let me know which solution you chose. (It can be different in different places, of course).
And thirdly, there seem to be a bug in gcc, which ignores the `-fvisibility=hidden` flag in certain circumstances involving templates. I could not pinpoint what conditions were necessary to trigger this bug, but in `accessBackend.cpp` I have manually added a `HIDDEN` attribute to a bunch of `arraycopy_conjoint` functions to keep them from being exported. It looks ugly; and we might be willing to accept that these functions are exported even though they should not be, to get rid of this. Or it might be that someone finds out if what is different with this declarations that trigger this bug, and constructs a work-around. (I gave up on it, though...)
About the changes on linux/x64 and linux/aarch64: I believe the new values are in some way more correct, but I also think the difference is insignificant. The difference is that the data (variable) symbols `__bss_start`, `_edata` and `_end`, and the text (function) symbols `_fini` and `_init` has changed from local to global. Afaik, these are symbols created by the linker. Also, when we used a mapfile, the symbol `SUNWprivate_1.1` that was part of the mapfile definition was included in libjvm.so, and this is no longer the case.
Finally, in the gtest libjvmo.so there are some additional differences as well. I did not really care about these, since this is only used for testing, but for the sake of completeness, here are the differences. They belong to two different categories.
Group 1 includes four symbols like `_Z9type_nameIiEPKcv`. These come from this definition:
template <typename T> const char* type_name();
in `test_parse_memory_size.cpp`, and is seemingly the same issue as with the `arraycopy_conjoint` functions in `accessBackend.cpp`. They have changed from local to global.
Group 2 includes symbols that seem to originate in the googletest library. They have changed
from local to global, but also to weak symbols. They match some different patterns:
* Seven symbols like `_ZNSt15_Sp_counted_ptrIPKN7testing8internal2REELN9__gnu_cxx12_Lock_policyE2EED2Ev`.
Demangled, these read `std::_Sp_counted_ptr<testing::internal::RE const*, (__gnu_cxx::_Lock_policy)2>`.
* One symbol `_ZN7testing15AssertionResultlsIA12_cEERS0_RKT_` (demangled: `testing::AssertionResult& testing::AssertionResult::operator<< <char [12]>(char const (&) [12])`)
* And finally, only on x64 (but not aarch64), one symbol `_ZN7testing4Test10HasFailureEv` (demangled: `testing::Test::HasFailure()`).
-------------
PR Comment: https://git.openjdk.org/jdk/pull/17955#issuecomment-1958337547
More information about the build-dev
mailing list