98 Commits

Author SHA1 Message Date
DingliZhang 2f0d089b25 RISC-V: Clean up vector register dispatch in MachSpillCopyNode::implementation
OpenJDK GHA Sanity Checks / Prepare the run (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-nopch (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-zero (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-minimal (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-optimized (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-static-libs (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-cross-compile (push) Has been cancelled
OpenJDK GHA Sanity Checks / alpine-linux-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / macos-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / docs (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-static (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-aarch64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / macos-aarch64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / windows-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / windows-aarch64 (push) Has been cancelled
2026-08-18 17:38:55 +08:00
Gui Cao 764e83c46c 8390441: RISC-V: Fix C2 stack-to-stack spill copies with large offsets
Reviewed-by: fyang, dzhang
2026-08-18 01:44:20 +00:00
David Holmes 92e236a361 8390493: Remove vmTestbase/nsk/jvmti/IterateOverReachableObjects/iterreachobj002/TestDescription.java from the ProblemList
Reviewed-by: liach
2026-08-18 01:16:16 +00:00
Dingli Zhang 4d812a6486 8390452: RISC-V: gc/shenandoah/TestSieveObjects.java fails with "assert(UseZba) failed: must be"
Reviewed-by: shade, fyang
2026-08-17 23:15:14 +00:00
Matias Saavedra Silva f3cf3e2036 8390484: Problem list appcds/aotCache/ tests
Reviewed-by: lmesnik, iklam
2026-08-17 23:08:25 +00:00
Shiv Shah 9139138393 8390429: Enable suspend001 jdb test to run with virtual threads
Reviewed-by: cjplummer, dholmes
2026-08-17 22:55:51 +00:00
Yunbo Zhang efd8ae1047 8378896: A make target "clean-microbenchmark", for micro development
Reviewed-by: erikj
2026-08-17 19:46:12 +00:00
Fairoz Matte 079d77cc05 8390184: Some typos in the jdk.jdi module
Reviewed-by: cjplummer
2026-08-17 18:52:46 +00:00
Matias Saavedra Silva 0d2320aea2 8368350: Do not support -XX:+AOTClassLinking for static CDS archive
Reviewed-by: iklam, lfoltan, asmehra
2026-08-17 18:48:56 +00:00
Jaikiran Pai f5a59340d9 8390202: Typos in the javadoc of various classes in jdk.sctp module
Reviewed-by: dfuchs
2026-08-17 16:44:33 +00:00
Ioi Lam c328739ac0 8390357: AOTMapTest.java fails --vmoptions:--enable-preview
Reviewed-by: thartmann, lfoltan
2026-08-17 16:29:59 +00:00
Ioi Lam 134c07f4fa 8390447: Update ProblemList-Xcomp.txt entries for 8388438
Reviewed-by: dholmes
2026-08-17 16:29:29 +00:00
Ashay Rane 3eefd7ab1b 8389829: (fs) Copying symbolic link fails in Developer Mode (win)
Reviewed-by: alanb
2026-08-17 16:20:45 +00:00
Ioi Lam 858880932a 8387494: ResolvedMethodName::vmtarget is not updated when class in AOT cache is redefined
Reviewed-by: kvn, asmehra
2026-08-17 16:17:08 +00:00
Dingli Zhang 4555cf2137 8390101: RISC-V: Use vmandn.mm for vector mask and-not
Reviewed-by: fyang, gcao
2026-08-17 08:33:47 +00:00
Marc Chevalier 1d3c7e247c 8252185: [Valhalla] Improve performance of identityHashCode for value objects
Reviewed-by: thartmann, fparain
2026-08-17 08:03:05 +00:00
Daniel Skantz 5962e8294d 8386580: Typing corrections and style improvements in x86 ML DSA/KEM/SHA3 stub code
Reviewed-by: adinn, semery, chagedorn
2026-08-17 06:33:22 +00:00
Guanqiang Han 5eaf42f6da 8389579: C2: Missed Ideal optimization opportunity in PhaseIterGVN for CompressBits and ExpandBits
Reviewed-by: mchevalier, thartmann
2026-08-17 06:25:31 +00:00
Prasanta Sadhukhan 3ef007ac23 8390296: Swing MultiUIDefaults#containsKey inconsistancy
Reviewed-by: azvegint, kizune
2026-08-17 05:30:35 +00:00
Prasanta Sadhukhan 157c49276b 8390183: Some typos in JavaDocs for the java.desktop module
Reviewed-by: azvegint, kizune
2026-08-17 05:29:58 +00:00
Sergey Bylokhov 88521b3587 8390249: Add missing @Override annotations in "javax.imageio.stream" package
Reviewed-by: psadhukhan, azvegint
2026-08-17 00:54:50 +00:00
Prasanta Sadhukhan 3d47518697 8387267: Editor for the last column in JTable is hard to activate after AUTO_RESIZE_LAST_COLUMN was configured
8388467: Test "api/javax_swing/interactive/JTableTests.html" JTable freezes during rapid column resize

Reviewed-by: angorya, kizune, jdv
2026-08-15 08:16:46 +00:00
Chuanqi Zang 2749a4c0b4 8389677: RISC-V: Prefer vmv.v.i to zero vector registers
Co-authored-by: Pengcheng Wang <wangpengcheng.pp@bytedance.com>
Reviewed-by: dzhang, fyang
2026-08-15 07:50:53 +00:00
Ioi Lam 982afa5d48 8388525: Disallow different module options between AOT training and assembly
Reviewed-by: asmehra, matsaave
2026-08-15 01:26:39 +00:00
Vladimir Kozlov 16bf2730aa 8390329: Obsolete AlwaysCompileLoopMethods VM flag
Reviewed-by: dholmes, mchevalier
2026-08-14 16:23:09 +00:00
Stefan Karlsson 782b49e89e 8378525: ZGC: Refactor ZBarrierSet to better fit with ZGC coding style
Reviewed-by: aboldtch, eosterlund
2026-08-14 12:33:34 +00:00
Jan Lahoda 88dfb74bbe 8389659: Cannot invoke "com.sun.tools.javac.code.Type.getTag()" because "type" is null on invalid LHS
Reviewed-by: mcimadamore
2026-08-14 10:27:16 +00:00
Jan Lahoda a0d9b0affd 8389987: null is accepted as synchronized lock
Reviewed-by: mcimadamore
2026-08-14 10:26:55 +00:00
Christian Hagedorn 9646856512 8387332: Template Framework: Add utility methods to build scopes
Reviewed-by: thartmann, mhaessig
2026-08-14 10:16:19 +00:00
Ashay Rane aa0fbef91a 8387792: Enable PAC-RET for VM code on Windows/ARM64
Reviewed-by: haosun, erikj
2026-08-13 22:21:44 +00:00
Patricio Chilano Mateo 993f7b35cf 8389187: -XX:+VerifyContinuations triggers assert(max_thawing_size() == calculated_max_size)
Co-authored-by: Tobias Hartmann <thartmann@openjdk.org>
Reviewed-by: fbredberg, fparain
2026-08-13 21:49:06 +00:00
Vicente Romero 844f1fea58 8389071: Javac crashes with OutOfMemoryError during Least Upper Bound (LUB) inference of highly entangled F-bounded generic classes
Reviewed-by: mcimadamore
2026-08-13 21:32:25 +00:00
Patricio Chilano Mateo 3efdba901c 8388596: Virtual-thread freeze asserts on MethodHandle frame with scalarized value argument
Co-authored-by: Tobias Hartmann <thartmann@openjdk.org>
Reviewed-by: fbredberg, fparain, coleenp
2026-08-13 20:17:27 +00:00
Fairoz Matte 4771360c9b 8389866: ZGC: Accepts an extremely negative ZAllocationSpikeTolerance value
Fix ZGC's handling of ZAllocationSpikeTolerance by rejecting invalid values.

Reviewed-by: stefank, tschatzl
2026-08-13 17:12:13 +00:00
Ioi Lam f9ee545b2e 8389293: Remove developer flag -XX:ArchiveHeapTestClass
Reviewed-by: kvn, dholmes
2026-08-13 16:02:41 +00:00
Aleksey Shipilev bc6d4fd10d 8390215: Shenandoah: Simplify GC logging by dropping unnecessary suffixes
Reviewed-by: wkemper, xpeng
2026-08-13 15:50:35 +00:00
Dušan Bálek 1f74b50bfa 8389868: Empty LocalVariableTable attribute is generated for an unused variable in clinit
Reviewed-by: liach, jlahoda
2026-08-13 15:03:23 +00:00
Suchismith Roy b8207347b8 8386510: AArch64: MacroAssembler constructor undefined behaviour
Reviewed-by: adinn, aph
2026-08-13 13:08:24 +00:00
Gui Cao 66a0483a94 8388458: RISC-V: Use LSB for conditional card mark in G1 post-write barrier
Co-authored-by: Dingli Zhang <dzhang@openjdk.org>
Reviewed-by: ayang, fyang, tschatzl
2026-08-13 12:52:12 +00:00
Ashay Rane 5a912628cd 8389209: Add sccache support to the build
Reviewed-by: erikj
2026-08-13 12:51:38 +00:00
Suchismith Roy 740621f198 8382604: Remove unused kscratch temp register from mask_opers_evex
Reviewed-by: galder, amitkumar
2026-08-13 12:38:27 +00:00
Aleksey Shipilev 0ffccaa083 8390122: Shenandoah: SBS::oop_load drops memory ordering decorators
Reviewed-by: wkemper, xpeng
2026-08-13 12:17:08 +00:00
Fredrik Bredberg 34dda4ecd8 8389325: Remove the UseObjectMonitorTable flag and related code
Reviewed-by: stefank, coleenp
2026-08-13 08:40:01 +00:00
Manuel Hässig 0a2e196bea 8390190: [IR-Framework] Integrate valhalla IR nodes into IRNode.java
Reviewed-by: thartmann, chagedorn, mchevalier
2026-08-13 08:33:01 +00:00
Matthias Baesken 3b1f2030f2 8390136: ResourceMark needed for external_name calls in continuationFreezeThaw.cpp
Reviewed-by: pchilanomate, shade
2026-08-13 08:25:32 +00:00
Volkan Yazici 48c84947b9 8387853: HttpServer unexpectedly closes the connection after first response to empty requests if "drainAmount <= 0"
Reviewed-by: jpai, dfuchs
2026-08-13 07:46:25 +00:00
Prasanta Sadhukhan d426d66b5e 8390042: Test "javax/swing/JToolBar/RightLeftOrientation.java" fails on macOS because two tool bar are not mirror images of each other for "Mac OS X" look and feel
Reviewed-by: kizune
2026-08-13 06:33:10 +00:00
David Holmes b86a56e118 8390261: ProblemList valhalla/valuetypes/NullRestrictedTest.java
Reviewed-by: iris, mikael
2026-08-13 03:44:49 +00:00
Jaikiran Pai e102078b9f 8371903: HttpClient: improve handling of HTTP/2 GOAWAY frames with error code
Co-authored-by: EunHyunsu <ehs208@naver.com>
Reviewed-by: dfuchs, vyazici
2026-08-13 01:22:15 +00:00
Alexey Semenyuk 70ca4da98e 8386893: add "#include <new>" to get defintion of "std::nothrow_t"
Reviewed-by: almatvee
2026-08-13 00:58:25 +00:00
David Holmes b545bc4e05 8390259: ProblemList runtime/valhalla/inlinetypes/NPEInPreviewTest.java
Reviewed-by: mikael
2026-08-12 22:13:35 +00:00
Matias Saavedra Silva ebce9ef9e7 8373348: Cache AdapterHandleEntry::_sig_cc field in AOTCache
Reviewed-by: asmehra, iklam
2026-08-12 21:05:43 +00:00
Matias Saavedra Silva 910c71ce2f 8389233: AOTMode=record asserts while archiving an initialized application value class
Co-authored-by: Ioi Lam <iklam@openjdk.org>
Reviewed-by: lmesnik, iklam, fparain
2026-08-12 16:49:58 +00:00
Claes Redestad 86d80bd392 8390113: JEP 401 integration breaks some pre-existing microbenchmarks
Reviewed-by: erikj, liach, jnorlinder
2026-08-12 13:59:26 +00:00
Johan Sjölen 8b81f8fbb8 8389538: StringUtils::string_match may underflow-read a buffer
Reviewed-by: dholmes, fparain
2026-08-12 12:28:58 +00:00
Aleksey Shipilev e1502b52f0 8390077: Rebalance tier1_compiler test groups
Reviewed-by: mhaessig, lmesnik
2026-08-12 08:04:06 +00:00
Quan Anh Mai 714b4f6bfd 8390186: [Valhalla] LoadNode::Value should check for ary->is_not_flat()
Reviewed-by: thartmann, chagedorn
2026-08-12 07:09:14 +00:00
Christian Hagedorn 75984f1302 8353624: C2: Re-enable malformed graph assert removed with JDK-8317998 to reduce noise
Reviewed-by: qamai, thartmann
2026-08-12 06:17:04 +00:00
Alan Bateman 4d4c0b4f41 8389671: (se) Blocking selection op in virtual thread does not keep spare alive beyond scheduler keep alive time (win)
Reviewed-by: jpai
2026-08-12 05:55:32 +00:00
Jatin Bhateja 241381ba70 8387213: Optimize Float16Vector.fma JIT sequence for x86 AVX512-FP16 targets
Reviewed-by: sviswanathan, vlivanov
2026-08-12 04:19:04 +00:00
Prasanta Sadhukhan 7be42518fe 8390104: Use correct bugid for test
Reviewed-by: kizune, serb
2026-08-12 02:31:36 +00:00
Yasumasa Suenaga 660d0aae3d 8390014: TestInstanceKlassSize.java and TestInstanceKlassSizeForInterface.java failed when --enable-preview was passed
Reviewed-by: phubner, cjplummer
2026-08-12 00:33:26 +00:00
Ioi Lam ade47e8030 8390132: Test runtime/cds/appcds/ClassPathAttrCircularReference.java "written dynamic archive" missing in output
Reviewed-by: kvn, lfoltan
2026-08-11 19:53:21 +00:00
Shiv Shah 911e50be4c 8355320: FileUtils.copyDirectory() mishandles an existing destination directory
Reviewed-by: lmesnik
2026-08-11 19:33:26 +00:00
Coleen Phillimore 1abe579042 8341120: NPE message can be wrong for null restricted fields
Reviewed-by: heidinga, fparain, liach
2026-08-11 18:27:05 +00:00
Valerie Peng 8a73ccfa9c 8390076: iList should be free'd after a failed C_GetInterfaceList() call in DEBUG mode
Reviewed-by: ayang, mbaesken
2026-08-11 18:23:34 +00:00
Vladimir Kozlov 1604ad70cc 8388417: Support VerifyOops for AOT caching stub and code
Reviewed-by: asmehra, iklam, adinn
2026-08-11 16:46:07 +00:00
Christoph Langer 99ece546ab 8389480: GenerateJLIClassesPluginTest.java and IncludeLocalesPluginTest.java tests in tools/jlink/plugins/ fail due to AccessDeniedExceptions on Windows
Reviewed-by: alanb
2026-08-11 16:07:06 +00:00
Ioi Lam 39392a489e 8389860: Remove CDS "optimized module handling" optimization
Reviewed-by: kvn, matsaave
2026-08-11 16:04:28 +00:00
Ashay Rane dcc4ac85d0 8390002: Windows AArch64 needs an additional yellow stack page (total 3)
Reviewed-by: iklam, aph, coleenp
2026-08-11 16:02:18 +00:00
Chen Liang b1467bd6af 8388374: Class-File API does not enforce required validation for null matches and empty PackageEntry names
Reviewed-by: asotona
2026-08-11 13:25:10 +00:00
Kuai Wei 80133d4dc7 8387812: Refine ArraysSupport.vectorizedMismatch to compare all elements
Reviewed-by: vlivanov, liach
2026-08-11 13:20:25 +00:00
Sorna Sarathi N 21c05fd3dd 8336666: Investigate why AIX needs more metaspace in test serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java
Reviewed-by: amitkumar, clanger, sspitsyn
2026-08-11 13:09:39 +00:00
Martin Doerr dbbfbc5f59 8387800: [lworld] PPC64 field flattening bugs in JEP 401
Reviewed-by: dbriemann, mbaesken, amitkumar
2026-08-11 11:35:29 +00:00
Aleksey Shipilev 1c5eca05ee 8390053: Shenandoah: Entry point is beyond 64K with lots of scalarized args
Reviewed-by: wkemper, kdnilsen
2026-08-11 11:28:59 +00:00
Dingli Zhang 52854620e4 8390033: Disable stringop-overflow in shenandoahHeap.cpp
Reviewed-by: erikj, shade
2026-08-11 10:56:36 +00:00
Guanqiang Han e9157bb2d5 8347266: C2: Verify that Node::Identity() doesn't return new nodes
Reviewed-by: mchevalier, chagedorn
2026-08-11 09:23:52 +00:00
Marc Chevalier be0f370e5b 8389914: C2: LoadNode::Ideal modifies the node but returns nullptr
Reviewed-by: qamai, thartmann
2026-08-11 09:00:44 +00:00
Thomas Stuefe cc939a54f1 8388017: [aix] Narrow klass encoding protection region should be protected in mmap mode
Reviewed-by: mbaesken, dbriemann
2026-08-11 08:43:50 +00:00
Matthias Baesken 94a288ae65 8348872: jabswitch.cpp: regEnable and regDeleteValue leak reallocated data buffer
Reviewed-by: prr, kizune
2026-08-11 07:40:14 +00:00
Tobias Hartmann 0afbe386ec 8388490: Assert in VectorUnboxNode::Ideal because value input is TOP
Co-authored-by: Christian Hagedorn <chagedorn@openjdk.org>
Reviewed-by: chagedorn, jbhateja, xgong
2026-08-11 07:35:46 +00:00
Volkan Yazici 652063d7ba 8384644: Document that HttpResponse::body can return null
Reviewed-by: jpai, dfuchs
2026-08-11 06:47:24 +00:00
Manuel Hässig 3ae762db82 8389936: Share the C2 stress infrastructure between compilers
Reviewed-by: chagedorn, mchevalier
2026-08-11 06:22:13 +00:00
Vladimir Kozlov 63ee524331 8389636: assert(_base == AryPtr) failed: Not an array pointer
Reviewed-by: chagedorn, dlong
2026-08-11 04:49:48 +00:00
Hai-May Chao b340e037e8 8380569: Update comments for X25519MLKEM768 per draft RFC in HybridProvider once spec becomes standardized
Reviewed-by: weijun
2026-08-11 01:35:55 +00:00
Aleksey Shipilev bc674c21af 8390081: [BACKOUT] Add the hotspot compiler testlibrary to the test-image
Reviewed-by: erikj, serb
2026-08-10 19:52:18 +00:00
Matias Saavedra Silva 77e09a3d6d 8389840: Verifier is not setting flagThisUninit when uninitializedThis is on the stack
Reviewed-by: liach, fparain, heidinga
2026-08-10 18:51:08 +00:00
Chen Liang 1c3df50209 8388343: Reevaluate the enable-preview in memory compilation from VM arguments
Reviewed-by: kvn, coleenp
2026-08-10 18:34:15 +00:00
Yunbo Zhang f332e84d9b 8388385: CDS dumping fails with circular JAR manifest Class-Path
Reviewed-by: iklam, matsaave
2026-08-10 18:26:39 +00:00
Aleksey Shipilev 7fd3f27741 8390069: compiler/codegen/ShiftByZero.java fails in release config
Reviewed-by: thartmann, epeter, mchevalier
2026-08-10 17:21:05 +00:00
Manuel Hässig b4a43ca56d 8380453: Add the hotspot compiler testlibrary to the test-image
Reviewed-by: erikj
2026-08-10 17:05:45 +00:00
Jaikiran Pai 1f1f460b3f 8383768: java/net/Socket/SocketReadInterruptTest.java failed with SocketTimeoutException: Read timed out
Reviewed-by: dfuchs
2026-08-10 15:32:07 +00:00
Robert Toyonaga edc9c7f08c 8331996: JFR: Add boolean check before loading event classes
Reviewed-by: alanb, stuefe
2026-08-10 13:22:06 +00:00
Thomas Schatzl 1a0ce5d6f4 8387973: CollectedHeap induced promotion failure handling should use Atomic
Reviewed-by: ayang, iwalulya
2026-08-10 12:30:57 +00:00
Timofei Pushkin 5c1ff40e29 8389966: Remove dangling bootstrap compile reason name
Reviewed-by: chagedorn, amitkumar
2026-08-10 11:16:22 +00:00
Daniel Skantz da75a9c979 8376296: ZGC: assert(can_align_up(size, alignment)) failed: precondition when setting -XX:MaxVirtMemFraction=1
Reviewed-by: stefank, aboldtch
2026-08-10 08:56:35 +00:00
Alexander Zvegintsev 0239ef4597 8389648: [TEST_BUG] java/awt/TextField/CaretPositionTest/CaretPositionTest.java fails in OL-9
Reviewed-by: prr, jdv
2026-08-10 08:42:44 +00:00
Marc Chevalier 4061f762d8 8389892: C2: VectorNode::Ideal modifies the node but returns nullptr
Reviewed-by: chagedorn, epeter
2026-08-10 07:41:59 +00:00
389 changed files with 10402 additions and 4597 deletions
+16 -5
View File
@@ -146,6 +146,7 @@ Performance</a>
<li><a href="#virus-checking" id="toc-virus-checking">Virus
Checking</a></li>
<li><a href="#ccache" id="toc-ccache">Ccache</a></li>
<li><a href="#sccache" id="toc-sccache">Sccache</a></li>
<li><a href="#precompiled-headers"
id="toc-precompiled-headers">Precompiled Headers</a></li>
<li><a href="#icecc-icecream" id="toc-icecc-icecream">Icecc /
@@ -365,11 +366,13 @@ free disk space is required.</p>
also possible to use <a href="#cross-compiling">cross-compiling</a>.</p>
<h4 id="branch-protection">Branch Protection</h4>
<p>In order to use Branch Protection features in the VM,
<code>--enable-branch-protection</code> must be used. This option
requires C++ compiler support (GCC 9.1.0+ or Clang 10+). The resulting
build can be run on both machines with and without support for branch
protection in hardware. Branch Protection is only supported for Linux
targets.</p>
<code>--enable-branch-protection</code> must be used. This option requires C++
compiler support for <code>-mbranch-protection=standard</code> in GCC 9.1.0+ or
Clang 10+ on Linux/AArch64 or for <code>/guard:signret</code> in Visual Studio
2019+ on Windows/ARM64. The resulting build can be run on both machines with and
without support for branch protection in hardware. Branch Protection is fully
supported for the Linux/AArch64 target and only partially supported for the
Windows/ARM64 targets.</p>
<h3 id="building-on-32-bit-arm">Building on 32-bit ARM</h3>
<p>This is not recommended. Instead, see the section on <a
href="#cross-compiling">Cross-compiling</a>.</p>
@@ -1814,6 +1817,14 @@ Using ccache can radically speed up compilation of native code if you
often rebuild the same sources. Your mileage may vary however, so we
recommend evaluating it for yourself. To enable it, make sure it's on
the path and configure with <code>--enable-ccache</code>.</p>
<h3 id="sccache">Sccache</h3>
<p>The JDK build supports building with sccache when using gcc, clang, or
Microsoft toolchains. To enable it, make sure the sccache binary is on the path
(or specify the path to the binary using the <code>SCCACHE</code> argument to
the configure script) and configure with <code>--enable-sccache</code>. To
optionally specify where sccache stores its cache files, use
<code>--with-sccache-dir</code>. Precompiled headers are disabled when sccache
is enabled.</p>
<h3 id="precompiled-headers">Precompiled Headers</h3>
<p>By default, the Hotspot build uses pre-compiled headers (PCH) on the
toolchains were it is properly supported (clang, gcc, and Visual
+14 -3
View File
@@ -171,9 +171,11 @@ possible to use [cross-compiling](#cross-compiling).
In order to use Branch Protection features in the VM,
`--enable-branch-protection` must be used. This option requires C++ compiler
support (GCC 9.1.0+ or Clang 10+). The resulting build can be run on both
machines with and without support for branch protection in hardware. Branch
Protection is only supported for Linux targets.
support for `-mbranch-protection=standard` in GCC 9.1.0+ or Clang 10+ on
Linux/AArch64 or for `/guard:signret` in Visual Studio 2019+ on Windows/ARM64.
The resulting build can be run on both machines with and without support for
branch protection in hardware. Branch Protection is fully supported for the
Linux/AArch64 target and only partially supported for the Windows/ARM64 target.
### Building on 32-bit ARM
@@ -1555,6 +1557,15 @@ the same sources. Your mileage may vary however, so we recommend evaluating it
for yourself. To enable it, make sure it's on the path and configure with
`--enable-ccache`.
### Sccache
The JDK build supports building with sccache when using gcc, clang, or Microsoft
toolchains. To enable it, make sure the sccache binary is on the path (or
specify the path to the binary using the `SCCACHE` argument to the configure
script) and configure with `--enable-sccache`. To optionally specify where
sccache stores its cache files, use `--with-sccache-dir`. Precompiled headers
are disabled when sccache is enabled.
### Precompiled Headers
By default, the Hotspot build uses pre-compiled headers (PCH) on the toolchains
+5 -1
View File
@@ -1420,6 +1420,9 @@ clean: $(CLEAN_DIR_TARGETS)
clean-docs:
$(call CleanDocs)
clean-microbenchmark:
$(call CleanMicrobenchmark)
clean-compile-commands:
$(call CleanMakeSupportDir,compile-commands)
@@ -1468,7 +1471,8 @@ dist-clean: clean
)
$(ECHO) Cleaned everything, you will have to re-run configure.
ALL_TARGETS += clean clean-docs clean-compile-commands dist-clean $(CLEAN_DIR_TARGETS) \
ALL_TARGETS += clean clean-docs clean-microbenchmark clean-compile-commands \
dist-clean $(CLEAN_DIR_TARGETS) \
$(CLEAN_SUPPORT_DIR_TARGETS) $(CLEAN_TEST_TARGETS) $(CLEAN_PHASE_TARGETS) \
$(CLEAN_MODULE_TARGETS) $(CLEAN_MODULE_PHASE_TARGETS)
+8
View File
@@ -65,6 +65,14 @@ define CleanDocs
@$(ECHO) " done"
endef
define CleanMicrobenchmark
@$(PRINTF) "Cleaning microbenchmark build artifacts ..."
@$(ECHO) "" $(LOG_DEBUG)
$(RM) -r $(SUPPORT_OUTPUTDIR)/test/micro
$(RM) -r $(TEST_IMAGE_DIR)/micro
@$(ECHO) " done"
endef
# Cleans the dir given as $1
define CleanDir
@$(PRINTF) "Cleaning %s build artifacts ..." "$(strip $1)"
+110 -1
View File
@@ -252,6 +252,109 @@ AC_DEFUN([BPERF_SETUP_CCACHE_USAGE],
fi
])
AC_DEFUN([BPERF_SETUP_SCCACHE],
[
# Check if sccache is available
SCCACHE_AVAILABLE=true
UTIL_LOOKUP_TOOLCHAIN_PROGS(SCCACHE, sccache)
AC_MSG_CHECKING([if sccache is available])
if test "x$TOOLCHAIN_TYPE" != "xgcc" && test "x$TOOLCHAIN_TYPE" != "xclang" && \
test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then
AC_MSG_RESULT([no, not supported for toolchain type $TOOLCHAIN_TYPE])
SCCACHE_AVAILABLE=false
elif test "x$SCCACHE" = "x"; then
AC_MSG_RESULT([no, sccache binary missing or not executable])
SCCACHE_AVAILABLE=false
else
AC_MSG_RESULT([yes])
fi
SCCACHE_STATUS=""
UTIL_ARG_ENABLE(NAME: sccache, DEFAULT: false, AVAILABLE: $SCCACHE_AVAILABLE,
DESC: [enable using sccache to speed up recompilations],
CHECKING_MSG: [if sccache is enabled],
IF_ENABLED: [
if test "x$CCACHE" != x; then
AC_MSG_ERROR([Cannot enable both ccache and sccache])
fi
# Versions of sccache before 0.10.0 can restore stale or incorrect
# dependency files for cached C/C++ compilations, breaking our build.
SCCACHE_VERSION=[`$SCCACHE --version | head -n1 | $CUT -d " " -f 2 | $TR -d '\r'`]
if test "x$SCCACHE_VERSION" = x; then
AC_MSG_ERROR([Could not determine sccache version])
fi
HAS_BAD_SCCACHE=[`$ECHO $SCCACHE_VERSION | \
$GREP -e '^0\.[0-9]\.' -e '^0\.[0-9]$'`]
if test "x$HAS_BAD_SCCACHE" != "x"; then
AC_MSG_ERROR([[sccache 0.10.0 or later is required, found $SCCACHE_VERSION]])
fi
SCCACHE_STATUS="Active ($SCCACHE_VERSION)"
],
IF_DISABLED: [
SCCACHE=""
])
AC_SUBST(SCCACHE)
AC_ARG_WITH([sccache-dir],
[AS_HELP_STRING([--with-sccache-dir],
[where to store sccache files @<:@~/.cache/sccache@:>@])])
if test "x$with_sccache_dir" != x; then
SCCACHE_DIR="$with_sccache_dir"
SCCACHE_DIR_FOR_SCCACHE="$SCCACHE_DIR"
# Ideally, we'd use `UTIL_FIXUP_PATH()`, but it expects the supplied path to
# already exist, which might not be true for the sccache directory during
# the configure step. As a workaround, we manually invoke fixpath.sh.
if test "x$OPENJDK_BUILD_OS" = "xwindows"; then
SCCACHE_DIR_FOR_SCCACHE=`$FIXPATH_BASE -m print "$SCCACHE_DIR_FOR_SCCACHE"`
fi
SET_SCCACHE_DIR="SCCACHE_DIR=$SCCACHE_DIR_FOR_SCCACHE"
if test "x$SCCACHE" = x; then
AC_MSG_WARN([--with-sccache-dir has no meaning when sccache is not enabled])
fi
fi
if test "x$SCCACHE" != x; then
BPERF_SETUP_SCCACHE_USAGE
fi
])
AC_DEFUN([BPERF_SETUP_SCCACHE_USAGE],
[
if test "x$SCCACHE" != x; then
if test "x$USE_PRECOMPILED_HEADER" = "xtrue"; then
if test "x$PRECOMPILED_HEADERS_EXPLICITLY_SET" = "xtrue"; then
AC_MSG_ERROR([Cannot use sccache with precompiled headers. Use --disable-precompiled-headers.])
else
AC_MSG_NOTICE([Disabling precompiled headers because sccache is enabled])
USE_PRECOMPILED_HEADER=false
fi
fi
# On Windows, the sccache binary must be launched through fixpath and the
# compiler argument passed to sccache must be the actual compiler
# (gcc/clang/cl) and not another fixpath invocation, otherwise sccache will
# try to execute fixpath as the compiler.
[ if [[ "$OPENJDK_BUILD_OS" = "windows" && "$SCCACHE" =~ ^"$FIXPATH " ]]; then ]
[ if [[ "$CC" =~ ^"$FIXPATH " ]]; then ]
CC="${CC#"$FIXPATH "}"
[ fi ]
[ if [[ "$CXX" =~ ^"$FIXPATH " ]]; then ]
CXX="${CXX#"$FIXPATH "}"
[ fi ]
[ fi ]
if test "x$SET_SCCACHE_DIR" != x; then
SCCACHE="$SET_SCCACHE_DIR $SCCACHE"
mkdir -p "$SCCACHE_DIR" > /dev/null 2>&1
fi
fi
])
################################################################################
#
# Runs icecc-create-env once and prints the error if it fails
@@ -372,7 +475,13 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS],
UTIL_ARG_ENABLE(NAME: precompiled-headers, DEFAULT: auto,
RESULT: USE_PRECOMPILED_HEADER, AVAILABLE: $PRECOMPILED_HEADERS_AVAILABLE,
DESC: [enable using precompiled headers when compiling C++])
DESC: [enable using precompiled headers when compiling C++],
IF_GIVEN: [
PRECOMPILED_HEADERS_EXPLICITLY_SET=true
],
IF_NOT_GIVEN: [
PRECOMPILED_HEADERS_EXPLICITLY_SET=false
])
AC_SUBST(USE_PRECOMPILED_HEADER)
])
+3
View File
@@ -293,6 +293,9 @@ BPERF_SETUP_PRECOMPILED_HEADERS
# Setup use of ccache, if available
BPERF_SETUP_CCACHE
# Setup use of sccache, if available
BPERF_SETUP_SCCACHE
################################################################################
#
# And now the finish...
+13 -3
View File
@@ -945,11 +945,21 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
[
# Is branch protection available?
BRANCH_PROTECTION_AVAILABLE=false
BRANCH_PROTECTION_FLAG="-mbranch-protection=standard"
BRANCH_PROTECTION_CFLAG=""
BRANCH_PROTECTION_ASFLAG=""
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_FLAG],
BRANCH_PROTECTION_CFLAG="-mbranch-protection=standard"
# The GCC/Clang assembler accepts the same flag as the compiler.
BRANCH_PROTECTION_ASFLAG="$BRANCH_PROTECTION_CFLAG"
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_CFLAG],
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
BRANCH_PROTECTION_CFLAG="/guard:signret"
# MSVC's assembler does not support branch protection flags, so
# BRANCH_PROTECTION_ASFLAG is intentionally left empty.
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_CFLAG],
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
fi
fi
@@ -957,5 +967,5 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false,
RESULT: BRANCH_PROTECTION_ENABLED, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
DESC: [enable branch protection when compiling C/C++],
IF_ENABLED: [BRANCH_PROTECTION_CFLAGS=$BRANCH_PROTECTION_FLAG])
IF_ENABLED: [BRANCH_PROTECTION_CFLAGS=$BRANCH_PROTECTION_CFLAG])
])
+1 -1
View File
@@ -211,7 +211,7 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS_CPU_DEP],
fi
if test "x$BRANCH_PROTECTION_ENABLED" = "xtrue"; then
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_FLAG"
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_ASFLAG"
fi
AC_SUBST($2JVM_ASFLAGS)
+3
View File
@@ -335,6 +335,9 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS],
if test "x$CCACHE_STATUS" != "x"; then
$ECHO "* ccache status: $CCACHE_STATUS"
fi
if test "x$SCCACHE_STATUS" != "x"; then
$ECHO "* sccache status: $SCCACHE_STATUS"
fi
$ECHO ""
if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then
+3 -2
View File
@@ -545,7 +545,7 @@ ADLC_LANGSTD_CXXFLAGS := @ADLC_LANGSTD_CXXFLAGS@
ADLC_LDFLAGS := @ADLC_LDFLAGS@
# Tools that potentially need to be cross compilation aware.
CC := @CCACHE@ @ICECC@ @CC@
CC := @SCCACHE@ @CCACHE@ @ICECC@ @CC@
# CFLAGS used to compile the jdk native libraries (C-code)
CFLAGS_JDKLIB := @CFLAGS_JDKLIB@
@@ -571,7 +571,7 @@ EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@
EXTRA_LDFLAGS := @EXTRA_LDFLAGS@
EXTRA_ASFLAGS := @EXTRA_ASFLAGS@
CXX := @CCACHE@ @ICECC@ @CXX@
CXX := @SCCACHE@ @CCACHE@ @ICECC@ @CXX@
CPP := @CPP@
@@ -740,6 +740,7 @@ RCFLAGS := @RCFLAGS@
AWK := @AWK@
BASENAME := @BASENAME@
CAT := @CAT@
SCCACHE := @SCCACHE@
CCACHE := @CCACHE@
# CD is going away, but remains to cater for legacy makefiles.
CD := cd
+2 -2
View File
@@ -148,8 +148,8 @@ endef
# BIN store classes here
# MODULE Name of module being compiled. If set, classes are put in BIN/MODULE.
# CLASSPATH a list of additional entries to set as classpath to javac
# INCLUDES myapp.foo means will only compile java files in myapp.foo or any of its sub-packages.
# EXCLUDES myapp.foo means will do not compile java files in myapp.foo or any of its sub-packages.
# INCLUDES myapp/foo means will only compile java files in myapp.foo or any of its sub-packages.
# EXCLUDES myapp/foo means will do not compile java files in myapp.foo or any of its sub-packages.
# COPY .prp means copy all prp files to the corresponding package in BIN.
# COPY_FILES myapp/foo/setting.txt means copy this file over to the package myapp/foo
# CLEAN .properties means copy and clean all properties file to the corresponding package in BIN.
+1
View File
@@ -210,6 +210,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
DISABLED_WARNINGS_gcc_postaloc.cpp := address, \
DISABLED_WARNINGS_gcc_safepointMechanism.cpp := stringop-overflow, \
DISABLED_WARNINGS_gcc_shenandoahGenerationalHeap.cpp := stringop-overflow, \
DISABLED_WARNINGS_gcc_shenandoahHeap.cpp := stringop-overflow, \
DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \
DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_synchronizer.cpp := stringop-overflow, \
+64 -30
View File
@@ -77,44 +77,74 @@ MICROBENCHMARK_MANIFEST := Build: $(FULL_VERSION)\n\
# jmh uses annotation processors to generate the benchmark jar and thus
# requires the use of -processor option during benchmark compilation.
MICROBENCHMARK_PREVIEW_PACKAGES := \
org/openjdk/bench/valhalla \
org/openjdk/bench/java/lang/stable
MICROBENCHMARK_JAVAC_FLAGS := \
--add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
--add-exports java.base/jdk.internal.event=ALL-UNNAMED \
--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
--add-exports java.base/jdk.internal.jimage=ALL-UNNAMED \
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
--add-exports java.base/jdk.internal.util=ALL-UNNAMED \
--add-exports java.base/jdk.internal.value=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED \
--add-exports java.base/sun.invoke.util=ALL-UNNAMED \
--add-exports java.base/sun.security.util=ALL-UNNAMED \
--add-exports java.base/sun.security.util.math=ALL-UNNAMED \
--add-exports java.base/sun.security.util.math.intpoly=ALL-UNNAMED \
-XDsuppressNotes \
-processor org.openjdk.jmh.generators.BenchmarkProcessor \
-s $(MICROBENCHMARK_GENSRC)
# For code built with --enable-preview we need to patch java.base
# to include preview classes not found in interim javac
MICROBENCHMARK_JAVAC_PREVIEW_FLAGS := \
$(MICROBENCHMARK_JAVAC_FLAGS) \
--enable-preview \
--patch-module java.base=$(SUPPORT_OUTPUTDIR)/preview/java.base
MICROBENCHMARK_JAVA_FLAGS := \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--add-modules jdk.unsupported \
--limit-modules java.management
MICROBENCHMARK_DISABLED_WARNINGS := restricted this-escape processing \
rawtypes removal cast serial preview unchecked deprecation \
dangling-doc-comments
# Build microbenchmark suite for the current JDK
# Need to patch java.base to include preview classes not found in interim javac
$(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK_PREVIEW, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
SMALL_JAVA := false, \
CLASSPATH := $(JMH_COMPILE_JARS), \
INCLUDES := $(MICROBENCHMARK_PREVIEW_PACKAGES), \
CREATE_API_DIGEST := true, \
DISABLED_WARNINGS := $(MICROBENCHMARK_DISABLED_WARNINGS), \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := $(MICROBENCHMARK_JAVAC_PREVIEW_FLAGS), \
JAVA_FLAGS := $(MICROBENCHMARK_JAVA_FLAGS), \
))
$(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
SMALL_JAVA := false, \
CLASSPATH := $(JMH_COMPILE_JARS), \
CREATE_API_DIGEST := true, \
DISABLED_WARNINGS := restricted this-escape processing rawtypes removal cast \
serial preview unchecked deprecation dangling-doc-comments, \
EXCLUDES := $(MICROBENCHMARK_PREVIEW_PACKAGES), \
DISABLED_WARNINGS := $(MICROBENCHMARK_DISABLED_WARNINGS), \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := \
--add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
--add-exports java.base/jdk.internal.event=ALL-UNNAMED \
--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
--add-exports java.base/jdk.internal.jimage=ALL-UNNAMED \
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
--add-exports java.base/jdk.internal.util=ALL-UNNAMED \
--add-exports java.base/jdk.internal.value=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED \
--add-exports java.base/sun.invoke.util=ALL-UNNAMED \
--add-exports java.base/sun.security.util=ALL-UNNAMED \
--add-exports java.base/sun.security.util.math=ALL-UNNAMED \
--add-exports java.base/sun.security.util.math.intpoly=ALL-UNNAMED \
--enable-preview \
--patch-module java.base=$(SUPPORT_OUTPUTDIR)/preview/java.base \
-XDsuppressNotes \
-processor org.openjdk.jmh.generators.BenchmarkProcessor \
-s $(MICROBENCHMARK_GENSRC), \
JAVA_FLAGS := \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--add-modules jdk.unsupported \
--enable-preview \
--limit-modules java.management, \
JAVAC_FLAGS := $(MICROBENCHMARK_JAVAC_FLAGS), \
JAVA_FLAGS := $(MICROBENCHMARK_JAVA_FLAGS), \
))
$(BUILD_JDK_MICROBENCHMARK_PREVIEW): $(JMH_COMPILE_JARS)
$(BUILD_JDK_MICROBENCHMARK): $(JMH_COMPILE_JARS)
# Unpacking dependencies for inclusion in the benchmark JARs
@@ -139,12 +169,16 @@ $(eval $(call SetupCopyFiles, COPY_JAXP_TEST_XML, \
# Create benchmarks JAR file with benchmarks for both the old and new JDK
$(eval $(call SetupJarArchive, BUILD_JDK_JAR, \
DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE) $(COPY_JAXP_TEST_XML), \
DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK_PREVIEW) \
$(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE) \
$(COPY_JAXP_TEST_XML), \
SRCS := $(MICROBENCHMARK_CLASSES) $(JMH_UNPACKED_DIR), \
BIN := $(MICROBENCHMARK_JAR_BIN), \
SUFFIXES := .*, \
EXCLUDE_FILES := _the.BUILD_JDK_MICROBENCHMARK_batch \
_the.BUILD_JDK_MICROBENCHMARK.vardeps _unpacked.marker, \
_the.BUILD_JDK_MICROBENCHMARK.vardeps _unpacked.marker \
_the.BUILD_JDK_MICROBENCHMARK_PREVIEW_batch \
_the.BUILD_JDK_MICROBENCHMARK_PREVIEW.vardeps, \
EXTRA_MANIFEST_ATTR := $(MICROBENCHMARK_MANIFEST), \
JARMAIN := org.openjdk.jmh.Main, \
JAR := $(MICROBENCHMARK_JAR), \
@@ -457,17 +457,18 @@ class Address {
Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);
Address(Register base, RegisterOrConstant index, extend ext = lsl()) {
Address(Register base, RegisterOrConstant index, extend ext = lsl(0)) {
if (index.is_register()) {
_mode = base_plus_offset_reg;
new (&_nonliteral) Nonliteral(base, index.as_register(), 0, ext);
} else {
guarantee(ext.option() == ext::uxtx, "should be");
assert(index.is_constant(), "should be");
assert(ext.shift() == 0, "must be");
_mode = base_plus_offset;
new (&_nonliteral) Nonliteral(base,
noreg,
index.as_constant() << ext.shift());
index.as_constant());
}
}
@@ -182,10 +182,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1,
// Finish fast lock unsuccessfully. MUST branch to with flag == NE
Label slow_path;
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(t1, obj, rscratch2);
@@ -245,60 +243,55 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1,
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
const ByteSize omc_obj_offset = OMCache::obj_offset();
if (!UseObjectMonitorTable) {
assert(t1_monitor == t1_mark, "should be the same here");
} else {
const Register t1_hash = t1;
Label monitor_found;
const Register t1_hash = t1;
Label monitor_found;
// Save the mark, we might need it to extract the hash.
mov(t3, t1_mark);
// Save the mark, we might need it to extract the hash.
mov(t3, t1_mark);
// Look for the monitor in the current thread's object monitor cache (omc).
// Look for the monitor in the current thread's object monitor cache (omc).
ldr(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
ldr(t2, Address(rthread, thr_omc_offset + omc_obj_offset));
cmp(obj, t2);
br(Assembler::EQ, monitor_found);
ldr(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
ldr(t2, Address(rthread, thr_omc_offset + omc_obj_offset));
cmp(obj, t2);
br(Assembler::EQ, monitor_found);
// Look for the monitor in the table.
// Look for the monitor in the table.
// Get the hash code.
ubfx(t1_hash, t3, markWord::hash_shift, markWord::hash_bits);
// Get the hash code.
ubfx(t1_hash, t3, markWord::hash_shift, markWord::hash_bits);
// Get the table and calculate the bucket's address
lea(t3, ExternalAddress(ObjectMonitorTable::current_table_address()));
ldr(t3, Address(t3));
ldr(t2, Address(t3, ObjectMonitorTable::table_capacity_mask_offset()));
ands(t1_hash, t1_hash, t2);
ldr(t3, Address(t3, ObjectMonitorTable::table_buckets_offset()));
// Get the table and calculate the bucket's address
lea(t3, ExternalAddress(ObjectMonitorTable::current_table_address()));
ldr(t3, Address(t3));
ldr(t2, Address(t3, ObjectMonitorTable::table_capacity_mask_offset()));
ands(t1_hash, t1_hash, t2);
ldr(t3, Address(t3, ObjectMonitorTable::table_buckets_offset()));
// Read the monitor from the bucket.
ldr(t1_monitor, Address(t3, t1_hash, Address::lsl(LogBytesPerWord)));
// Read the monitor from the bucket.
ldr(t1_monitor, Address(t3, t1_hash, Address::lsl(LogBytesPerWord)));
// Check if the monitor in the bucket is special (empty, tombstone or removed).
cmp(t1_monitor, (unsigned char)ObjectMonitorTable::SpecialPointerValues::below_is_special);
br(Assembler::LO, slow_path);
// Check if the monitor in the bucket is special (empty, tombstone or removed).
cmp(t1_monitor, (unsigned char)ObjectMonitorTable::SpecialPointerValues::below_is_special);
br(Assembler::LO, slow_path);
// Check if object matches.
ldr(t3, Address(t1_monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, t3, t3, t2, slow_path);
cmp(t3, obj);
br(Assembler::NE, slow_path);
// Check if object matches.
ldr(t3, Address(t1_monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, t3, t3, t2, slow_path);
cmp(t3, obj);
br(Assembler::NE, slow_path);
// Store the monitor in the current thread's object monitor cache (omc).
str(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
str(obj, Address(rthread, thr_omc_offset + omc_obj_offset));
// Store the monitor in the current thread's object monitor cache (omc).
str(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
str(obj, Address(rthread, thr_omc_offset + omc_obj_offset));
bind(monitor_found);
}
bind(monitor_found);
const Register t2_owner_addr = t2;
const Register t3_owner = t3;
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
const Address owner_address(t1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
const Address owner_address(t1_monitor, ObjectMonitor::owner_offset());
const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset());
Label monitor_locked;
@@ -318,10 +311,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1,
increment(recursions_address, 1);
bind(monitor_locked);
if (UseObjectMonitorTable) {
// Cache the monitor for unlock.
str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
// Cache the monitor for unlock.
str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
bind(locked);
@@ -388,7 +379,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, Register t1,
// Because we got here by popping (meaning we pushed in locked)
// there will be no monitor in the box. So we need to push back the obj
// so that the runtime can fix any potential anonymous owner.
tbnz(t1_mark, exact_log2(markWord::monitor_value), UseObjectMonitorTable ? push_and_slow_path : inflated);
tbnz(t1_mark, exact_log2(markWord::monitor_value), push_and_slow_path);
// Try to unlock. Transition lock bits 0b00 => 0b01
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea");
@@ -430,17 +421,10 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, Register t1,
const Register t1_monitor = t1;
if (!UseObjectMonitorTable) {
assert(t1_monitor == t1_mark, "should be the same here");
// Untag the monitor.
add(t1_monitor, t1_mark, -(int)markWord::monitor_value);
} else {
ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
cmp(t1_monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
br(Assembler::LO, slow_path);
}
ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
cmp(t1_monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
br(Assembler::LO, slow_path);
const Register t2_recursions = t2;
Label not_recursive;
@@ -3032,4 +3016,4 @@ void C2_MacroAssembler::sve_sdiv_short(FloatRegister dst_src1, FloatRegister src
sve_sdiv(src1, S, ptrue, vtmp2);
// Narrow the two INT result halves back to SHORT.
sve_uzp1(dst_src1, H, vtmp1, src1);
}
}
+2 -2
View File
@@ -805,8 +805,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
}
bool frame::was_augmented_on_entry(int& real_size) const {
assert(is_compiled_frame(), "");
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
assert(_cb != nullptr && _cb->is_nmethod(), "");
if (_cb->as_nmethod()->needs_stack_repair()) {
// The stack increment resides just below the saved FP on the stack and
// records the total frame size excluding the two words for saving FP and LR
// (see MacroAssembler::remove_frame).
@@ -23,6 +23,7 @@
*/
#include "classfile/classLoaderData.hpp"
#include "code/aotCodeCache.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
@@ -405,10 +406,22 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
}
void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
assert_different_registers(obj, tmp1, tmp2);
// Check if the oop is in the right area of memory
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, obj, tmp2);
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
__ ldr(tmp2, Address(tmp2));
__ andr(tmp1, obj, tmp2);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
__ ldr(tmp2, Address(tmp2));
} else
#endif
{
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, obj, tmp2);
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
}
// Compare tmp1 and tmp2. We don't use a compare
// instruction here because the flags register is live.
@@ -24,6 +24,7 @@
*
*/
#include "code/aotCodeCache.hpp"
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
#include "gc/shenandoah/mode/shenandoahMode.hpp"
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
@@ -213,13 +214,16 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
// Test for in-cset
if (is_strong) {
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(rscratch2, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
__ ldr(rscratch2, Address(rscratch2));
__ lea(rscratch1, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
__ ldrw(rscratch1, Address(rscratch1));
__ lsrv(rscratch1, r0, rscratch1);
} else {
} else
#endif
{
__ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr());
__ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint());
}
@@ -421,11 +425,22 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
}
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
assert_different_registers(obj, tmp1, tmp2);
// Check if the oop is in the right area of memory
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, obj, tmp2);
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
__ ldr(tmp2, Address(tmp2));
__ andr(tmp1, obj, tmp2);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
__ ldr(tmp2, Address(tmp2));
} else
#endif
{
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, obj, tmp2);
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
}
// Compare tmp1 and tmp2. We don't use a compare
// instruction here because the flags register is live.
__ eor(tmp1, tmp1, tmp2);
@@ -22,6 +22,7 @@
*/
#include "asm/macroAssembler.inline.hpp"
#include "code/aotCodeCache.hpp"
#include "code/codeBlob.hpp"
#include "code/vmreg.inline.hpp"
#include "gc/z/zAddress.hpp"
@@ -1351,6 +1352,7 @@ void ZBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembler* masm,
}
void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
assert_different_registers(obj, tmp1, tmp2);
// C1 calls verfy_oop in the middle of barriers, before they have been uncolored
// and after being colored. Therefore, we must deal with colored oops as well.
Label done;
@@ -1390,9 +1392,20 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
__ bind(check_zaddress);
// Check if the oop is in the right area of memory
__ mov(tmp1, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, tmp1, obj);
__ mov(obj, (intptr_t) Universe::verify_oop_bits());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(tmp1, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
__ ldr(tmp1, Address(tmp1));
__ andr(tmp1, tmp1, obj);
__ lea(obj, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
__ ldr(obj, Address(obj));
} else
#endif
{
__ mov(tmp1, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, tmp1, obj);
__ mov(obj, (intptr_t) Universe::verify_oop_bits());
}
__ cmp(tmp1, obj);
__ br(Assembler::NE, error);
+1 -1
View File
@@ -42,7 +42,7 @@ define_pd_global(size_t, CodeCacheSegmentSize, 64);
define_pd_global(uint, CodeEntryAlignment, 64);
define_pd_global(intx, OptoLoopAlignment, 16);
#define DEFAULT_STACK_YELLOW_PAGES (2)
#define DEFAULT_STACK_YELLOW_PAGES (NOT_WINDOWS(2) WINDOWS_ONLY(3))
#define DEFAULT_STACK_RED_PAGES (1)
// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
// stack if compiled for unix and LP64. To pass stack overflow tests we need
@@ -2025,7 +2025,15 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
ResourceMark rm;
stringStream ss;
ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line);
b = code_string(ss.as_string());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
// this will duplicate string to preserve it
b = AOTCodeCache::add_C_string(ss.as_string());
} else
#endif
{
b = code_string(ss.as_string());
}
}
BLOCK_COMMENT("verify_oop {");
@@ -2061,7 +2069,15 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
ResourceMark rm;
stringStream ss;
ss.print("verify_oop_addr: %s (%s:%d)", s, file, line);
b = code_string(ss.as_string());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
// this will duplicate string to preserve it
b = AOTCodeCache::add_C_string(ss.as_string());
} else
#endif
{
b = code_string(ss.as_string());
}
}
BLOCK_COMMENT("verify_oop_addr {");
@@ -2396,16 +2412,6 @@ void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label
void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int32_t test_bit, bool jmp_set, Label& jmp_label) {
// load mark word
ldr(temp_reg, Address(oop, oopDesc::mark_offset_in_bytes()));
if (!UseObjectMonitorTable) {
Label test_mark_word;
// check displaced
tst(temp_reg, markWord::unlocked_value);
br(Assembler::NE, test_mark_word);
// slow path use klass prototype
load_prototype_header(temp_reg, oop);
bind(test_mark_word);
}
andr(temp_reg, temp_reg, test_bit);
if (jmp_set) {
cbnz(temp_reg, jmp_label);
@@ -7885,10 +7891,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register t1, R
// instruction emitted as it is part of C1's null check semantics.
ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(t1, obj, rscratch1);
+2 -2
View File
@@ -505,8 +505,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
}
bool frame::was_augmented_on_entry(int& real_size) const {
assert(is_compiled_frame(), "");
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
assert(_cb != nullptr && _cb->is_nmethod(), "");
if (_cb->as_nmethod()->needs_stack_repair()) {
Unimplemented();
}
real_size = _cb->frame_size();
+1 -1
View File
@@ -2450,7 +2450,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register tmp1,
payload_address(value, value, tmp1, tmp2);
Register layout_info = field_offset;
lbz(tmp1, in_bytes(ResolvedFieldEntry::field_index_offset()), entry);
lhz(tmp1, in_bytes(ResolvedFieldEntry::field_index_offset()), entry);
ld(tmp2, in_bytes(ResolvedFieldEntry::field_holder_offset()), entry);
inline_layout_info(tmp2, tmp1, layout_info);
+1 -1
View File
@@ -99,7 +99,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->try_resolve_jobject_in_native(masm, Robj, R3_ARG1, R4_ARG2, Rtmp, slow);
__ srwi(Rtmp, R5_ARG3, jfieldIDWorkaround::offset_shift); // offset
__ srdi(Rtmp, R5_ARG3, jfieldIDWorkaround::offset_shift); // offset
assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
speculative_load_pclist[count] = __ pc(); // Used by the segfault handler
+56 -95
View File
@@ -2688,7 +2688,6 @@ void MacroAssembler::tlab_allocate(
void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register obj, Register box,
Register tmp1, Register tmp2, Register tmp3) {
assert_different_registers(obj, box, tmp1, tmp2, tmp3);
assert(UseObjectMonitorTable || tmp3 == noreg, "tmp3 not needed");
assert(flag == CR0, "bad condition register");
// Handle inflated monitor.
@@ -2698,11 +2697,9 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
// Finish fast lock unsuccessfully. MUST branch to with flag == EQ
Label slow_path;
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
li(tmp1, 0);
std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
li(tmp1, 0);
std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
@@ -2760,9 +2757,9 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
// mark contains the tagged ObjectMonitor*.
const uintptr_t monitor_tag = markWord::monitor_value;
const Register monitor = UseObjectMonitorTable ? tmp1 : noreg;
const Register monitor = tmp1;
const Register owner_addr = tmp2;
const Register thread_id = UseObjectMonitorTable ? tmp3 : tmp1;
const Register thread_id = tmp3;
// Offsets into the current thread's object monitor cache (omc).
const ByteSize thr_omc_offset = JavaThread::om_cache_offset();
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
@@ -2770,61 +2767,55 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
Label monitor_locked;
if (!UseObjectMonitorTable) {
// Compute owner address.
addi(owner_addr, mark, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag);
mark = noreg;
} else {
const Register tmp3_bucket = tmp3;
const Register tmp2_hash = tmp2;
Label monitor_found;
const Register tmp3_bucket = tmp3;
const Register tmp2_hash = tmp2;
Label monitor_found;
// Save the mark, we might need it to extract the hash.
mr(tmp2_hash, mark);
// Save the mark, we might need it to extract the hash.
mr(tmp2_hash, mark);
// Look for the monitor in the current thread's object monitor cache (omc).
// Look for the monitor in the current thread's object monitor cache (omc).
ld(R0, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
ld(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
cmpd(CR0, R0, obj);
beq(CR0, monitor_found);
ld(R0, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
ld(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
cmpd(CR0, R0, obj);
beq(CR0, monitor_found);
// Look for the monitor in the table.
// Look for the monitor in the table.
// Get the hash code.
srdi(tmp2_hash, tmp2_hash, markWord::hash_shift);
// Get the hash code.
srdi(tmp2_hash, tmp2_hash, markWord::hash_shift);
// Get the table and calculate the bucket's address
int simm16_rest = load_const_optimized(tmp3, ObjectMonitorTable::current_table_address(), R0, true);
ld_ptr(tmp3, simm16_rest, tmp3);
ld(tmp1, in_bytes(ObjectMonitorTable::table_capacity_mask_offset()), tmp3);
andr(tmp2_hash, tmp2_hash, tmp1);
ld(tmp3_bucket, in_bytes(ObjectMonitorTable::table_buckets_offset()), tmp3);
// Get the table and calculate the bucket's address
int simm16_rest = load_const_optimized(tmp3, ObjectMonitorTable::current_table_address(), R0, true);
ld_ptr(tmp3, simm16_rest, tmp3);
ld(tmp1, in_bytes(ObjectMonitorTable::table_capacity_mask_offset()), tmp3);
andr(tmp2_hash, tmp2_hash, tmp1);
ld(tmp3_bucket, in_bytes(ObjectMonitorTable::table_buckets_offset()), tmp3);
// Read the monitor from the bucket.
sldi(tmp2_hash, tmp2_hash, LogBytesPerWord);
ldx(monitor, tmp3_bucket, tmp2_hash);
// Read the monitor from the bucket.
sldi(tmp2_hash, tmp2_hash, LogBytesPerWord);
ldx(monitor, tmp3_bucket, tmp2_hash);
// Check if the monitor in the bucket is special (empty, tombstone or removed).
cmpldi(CR0, monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
blt(CR0, slow_path);
// Check if the monitor in the bucket is special (empty, tombstone or removed).
cmpldi(CR0, monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
blt(CR0, slow_path);
// Check if object matches.
ld(tmp3, in_bytes(ObjectMonitor::object_offset()), monitor);
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
cmpd(CR0, tmp3, obj);
bne(CR0, slow_path);
// Check if object matches.
ld(tmp3, in_bytes(ObjectMonitor::object_offset()), monitor);
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
cmpd(CR0, tmp3, obj);
bne(CR0, slow_path);
// Store the monitor in the current thread's object monitor cache (omc).
std(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
std(obj, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
// Store the monitor in the current thread's object monitor cache (omc).
std(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
std(obj, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
bind(monitor_found);
bind(monitor_found);
// Compute owner address.
addi(owner_addr, monitor, in_bytes(ObjectMonitor::owner_offset()));
}
// Compute owner address.
addi(owner_addr, monitor, in_bytes(ObjectMonitor::owner_offset()));
// Try to CAS owner (no owner => current thread's _monitor_owner_id).
assert_different_registers(thread_id, monitor, owner_addr, box, R0);
@@ -2843,23 +2834,14 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
bne(CR0, slow_path);
// Recursive.
if (!UseObjectMonitorTable) {
assert_different_registers(tmp1, owner_addr);
ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
addi(tmp1, tmp1, 1);
std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
} else {
assert_different_registers(tmp2, monitor);
ld(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
addi(tmp2, tmp2, 1);
std(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
}
assert_different_registers(tmp2, monitor);
ld(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
addi(tmp2, tmp2, 1);
std(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
bind(monitor_locked);
if (UseObjectMonitorTable) {
// Cache the monitor for unlock.
std(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
}
// Cache the monitor for unlock.
std(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
}
bind(locked);
@@ -2926,11 +2908,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
// Check for monitor (0b10).
ld(mark, oopDesc::mark_offset_in_bytes(), obj);
andi_(t, mark, markWord::monitor_value);
if (!UseObjectMonitorTable) {
bne(CR0, inflated);
} else {
bne(CR0, push_and_slow);
}
bne(CR0, push_and_slow);
#ifdef ASSERT
// Check header not unlocked (0b01).
@@ -2980,15 +2958,10 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
const Register monitor = mark;
const uintptr_t monitor_tag = markWord::monitor_value;
if (!UseObjectMonitorTable) {
// Untag the monitor.
subi(monitor, mark, monitor_tag);
} else {
ld(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
cmpldi(CR0, monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
blt(CR0, slow_path);
}
ld(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
cmpldi(CR0, monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
blt(CR0, slow_path);
const Register recursions = tmp2;
Label not_recursive;
@@ -3359,16 +3332,6 @@ void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int
Label& jmp_label, bool maybe_far) {
// load mark word
ld(temp_reg, oopDesc::mark_offset_in_bytes(), oop);
if (!UseObjectMonitorTable) {
Label test_mark_word;
// if unlocked bit is set we can directly use the mark word
andi_(R0, temp_reg, markWord::unlocked_value);
bne(CR0, test_mark_word);
// slow path use klass prototype
load_prototype_header(temp_reg, oop);
bind(test_mark_word);
}
andi_(R0, temp_reg, test_bit);
if (maybe_far) {
bc_far_optimized(jmp_set ? Assembler::bcondCRbiIs0 : Assembler::bcondCRbiIs1,
@@ -4907,11 +4870,9 @@ void MacroAssembler::fast_lock(Register box, Register obj, Register t1, Register
Label push;
const Register t = R0;
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
li(t, 0);
std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
li(t, 0);
std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(t1, obj);
+1 -18
View File
@@ -10985,24 +10985,7 @@ instruct partialSubtypeCheckConstSuper(rarg3RegP sub, rarg2RegP super_reg, immP
// inlined locking and unlocking
instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{
predicate(!UseObjectMonitorTable);
match(Set crx (FastLock oop box));
effect(TEMP tmp1, TEMP tmp2);
format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %}
ins_encode %{
__ fast_lock($crx$$CondRegister, $oop$$Register, $box$$Register,
$tmp1$$Register, $tmp2$$Register, noreg /*tmp3*/);
// If locking was successful, crx should indicate 'EQ'.
// The compiler generates a branch to the runtime call to
// _complete_monitor_locking_Java for the case where crx is 'NE'.
%}
ins_pipe(pipe_class_compare);
%}
instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{
predicate(UseObjectMonitorTable);
instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{
match(Set crx (FastLock oop box));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr1);
+1 -2
View File
@@ -2525,8 +2525,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// Try fastpath for locking.
// fast_lock kills r_temp_1, r_temp_2, r_temp_3.
Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg;
__ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg);
__ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
__ beq(CR0, locked);
// None of the above fast optimizations worked so we have to get into the
+4 -3
View File
@@ -2609,7 +2609,8 @@ void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch,
// Restore object pointer.
__ pop_ptr(R17_tos);
__ verify_oop(R17_tos);
} else {
}
if (Rcache.is_volatile()) {
// Cache is still needed to get class or obj.
__ load_field_entry(Rcache, Rscratch);
}
@@ -3322,7 +3323,7 @@ void TemplateTable::fast_storefield(TosState state) {
{
Label is_flat, done;
__ test_field_is_flat(Rflags, is_flat);
__ null_check_throw(Rclass_or_obj, -1, Rscratch);
__ null_check_throw(R17_tos, -1, Rscratch);
do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
__ b(done);
__ bind(is_flat);
@@ -3384,7 +3385,7 @@ void TemplateTable::fast_accessfield(TosState state) {
Label LisVolatile;
ByteSize cp_base_offset = ConstantPoolCache::base_offset();
const Register Rcache = R3_ARG1,
const Register Rcache = R31, // Needs to survive C call.
Rclass_or_obj = R17_tos,
Roffset = R22_tmp2,
Rflags = R23_tmp3,
@@ -84,10 +84,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box,
// Finish fast lock unsuccessfully. slow_path MUST branch to with flag != 0
Label slow_path;
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
@@ -149,61 +147,56 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box,
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
const ByteSize omc_obj_offset = OMCache::obj_offset();
if (!UseObjectMonitorTable) {
assert(tmp1_monitor == tmp1_mark, "should be the same here");
} else {
const Register tmp2_hash = tmp2;
const Register tmp3_bucket = tmp3;
Label monitor_found;
const Register tmp2_hash = tmp2;
const Register tmp3_bucket = tmp3;
Label monitor_found;
// Save the mark, we might need it to extract the hash.
mv(tmp2_hash, tmp1_mark);
// Save the mark, we might need it to extract the hash.
mv(tmp2_hash, tmp1_mark);
// Look for the monitor in the current thread's object monitor cache (omc).
// Look for the monitor in the current thread's object monitor cache (omc).
ld(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
ld(tmp4, Address(xthread, thr_omc_offset + omc_obj_offset));
beq(obj, tmp4, monitor_found);
ld(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
ld(tmp4, Address(xthread, thr_omc_offset + omc_obj_offset));
beq(obj, tmp4, monitor_found);
// Look for the monitor in the table.
// Look for the monitor in the table.
// Get the hash code.
srli(tmp2_hash, tmp2_hash, markWord::hash_shift);
// Get the hash code.
srli(tmp2_hash, tmp2_hash, markWord::hash_shift);
// Get the table and calculate the bucket's address.
la(tmp3_t, ExternalAddress(ObjectMonitorTable::current_table_address()));
ld(tmp3_t, Address(tmp3_t));
ld(tmp1, Address(tmp3_t, ObjectMonitorTable::table_capacity_mask_offset()));
andr(tmp2_hash, tmp2_hash, tmp1);
ld(tmp3_t, Address(tmp3_t, ObjectMonitorTable::table_buckets_offset()));
// Get the table and calculate the bucket's address.
la(tmp3_t, ExternalAddress(ObjectMonitorTable::current_table_address()));
ld(tmp3_t, Address(tmp3_t));
ld(tmp1, Address(tmp3_t, ObjectMonitorTable::table_capacity_mask_offset()));
andr(tmp2_hash, tmp2_hash, tmp1);
ld(tmp3_t, Address(tmp3_t, ObjectMonitorTable::table_buckets_offset()));
// Read the monitor from the bucket.
shadd(tmp3_bucket, tmp2_hash, tmp3_t, tmp4, LogBytesPerWord);
ld(tmp1_monitor, Address(tmp3_bucket));
// Read the monitor from the bucket.
shadd(tmp3_bucket, tmp2_hash, tmp3_t, tmp4, LogBytesPerWord);
ld(tmp1_monitor, Address(tmp3_bucket));
// Check if the monitor in the bucket is special (empty, tombstone or removed).
mv(tmp2, ObjectMonitorTable::SpecialPointerValues::below_is_special);
bltu(tmp1_monitor, tmp2, slow_path);
// Check if the monitor in the bucket is special (empty, tombstone or removed).
mv(tmp2, ObjectMonitorTable::SpecialPointerValues::below_is_special);
bltu(tmp1_monitor, tmp2, slow_path);
// Check if object matches.
ld(tmp3, Address(tmp1_monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
bne(tmp3, obj, slow_path);
// Check if object matches.
ld(tmp3, Address(tmp1_monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
bne(tmp3, obj, slow_path);
// Store the monitor in the current thread's object monitor cache (omc).
sd(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
sd(obj, Address(xthread, thr_omc_offset + omc_obj_offset));
// Store the monitor in the current thread's object monitor cache (omc).
sd(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
sd(obj, Address(xthread, thr_omc_offset + omc_obj_offset));
bind(monitor_found);
}
bind(monitor_found);
const Register tmp2_owner_addr = tmp2;
const Register tmp3_owner = tmp3;
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset());
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset());
Label monitor_locked;
@@ -224,10 +217,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box,
increment(recursions_address, 1, tmp2, tmp3);
bind(monitor_locked);
if (UseObjectMonitorTable) {
// Cache the monitor for unlock.
sd(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
// Cache the monitor for unlock.
sd(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
bind(locked);
@@ -300,7 +291,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box,
// there will be no monitor in the box. So we need to push back the obj
// so that the runtime can fix any potential anonymous owner.
test_bit(tmp3_t, tmp1_mark, exact_log2(markWord::monitor_value));
bnez(tmp3_t, UseObjectMonitorTable ? push_and_slow_path : inflated);
bnez(tmp3_t, push_and_slow_path);
// Try to unlock. Transition lock bits 0b00 => 0b01
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea");
@@ -344,16 +335,10 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box,
const Register tmp1_monitor = tmp1;
if (!UseObjectMonitorTable) {
assert(tmp1_monitor == tmp1_mark, "should be the same here");
// Untag the monitor.
subi(tmp1_monitor, tmp1_mark, (int)markWord::monitor_value);
} else {
ld(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// No valid pointer below alignof(ObjectMonitor*). Take the slow path.
mv(tmp3_t, alignof(ObjectMonitor*));
bltu(tmp1_monitor, tmp3_t, slow_path);
}
ld(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// No valid pointer below alignof(ObjectMonitor*). Take the slow path.
mv(tmp3_t, alignof(ObjectMonitor*));
bltu(tmp1_monitor, tmp3_t, slow_path);
const Register tmp2_recursions = tmp2;
Label not_recursive;
@@ -1852,7 +1837,7 @@ void C2_MacroAssembler::arrays_hashcode_v(Register ary, Register cnt, Register r
vsetvli(consumed, cnt, Assembler::e32, Assembler::m2);
vle32_v(v_coeffs, t1); // 31^^(stride - 1) ... 31^^0
vmv_v_x(v_sum, x0);
vmv_v_i(v_sum, 0);
bind(VEC_LOOP);
arrays_hashcode_elload_v(v_src, v_tmp, ary, eltype);
@@ -2617,7 +2602,7 @@ void C2_MacroAssembler::java_round_float_v(VectorRegister dst, VectorRegister sr
// replacing vfclass with feq as performance optimization
vmfeq_vv(v0, src, src);
// set dst = 0 in cases of NaN
vmv_v_x(dst, zr);
vmv_v_i(dst, 0);
// dst = (src + 0.5) rounded down towards negative infinity
vfadd_vf(dst, src, ftmp, Assembler::v0_t);
@@ -2641,7 +2626,7 @@ void C2_MacroAssembler::java_round_double_v(VectorRegister dst, VectorRegister s
// replacing vfclass with feq as performance optimization
vmfeq_vv(v0, src, src);
// set dst = 0 in cases of NaN
vmv_v_x(dst, zr);
vmv_v_i(dst, 0);
// dst = (src + 0.5) rounded down towards negative infinity
vfadd_vf(dst, src, ftmp, Assembler::v0_t);
@@ -2699,7 +2684,7 @@ void C2_MacroAssembler::clear_array_v(Register base, Register cnt) {
// making zero words
vsetvli(t0, cnt, Assembler::e64, Assembler::m4);
vxor_vv(v4, v4, v4);
vmv_v_i(v4, 0);
bind(loop);
vsetvli(t0, cnt, Assembler::e64, Assembler::m4);
@@ -3296,7 +3281,7 @@ void C2_MacroAssembler::integer_narrow_v(VectorRegister dst, BasicType dst_bt, u
#define VFCVT_SAFE(VFLOATCVT) \
void C2_MacroAssembler::VFLOATCVT##_safe(VectorRegister dst, VectorRegister src) { \
assert_different_registers(dst, src); \
vxor_vv(dst, dst, dst); \
vmv_v_i(dst, 0); \
vmfeq_vv(v0, src, src); \
VFLOATCVT(dst, src, Assembler::v0_t); \
}
+2 -2
View File
@@ -629,8 +629,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
}
bool frame::was_augmented_on_entry(int& real_size) const {
assert(is_compiled_frame(), "");
assert(!_cb->as_nmethod_or_null()->needs_stack_repair(), "unimplemented");
assert(_cb != nullptr && _cb->is_nmethod(), "");
assert(!_cb->as_nmethod()->needs_stack_repair(), "unimplemented");
real_size = _cb->frame_size();
return false;
}
@@ -118,13 +118,20 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
// Iterate from start card to end card (inclusive).
__ bind(loop);
if (UseCondCardMark) {
// All non-clean cards (dirty, to-cset, from-remset) have bit0 == 0.
static_assert((G1CardTable::g1_dirty_card & 1U) == 0
&& (G1CardTable::g1_to_cset_card & 1U) == 0
&& (G1CardTable::g1_from_remset_card & 1U) == 0,
"cards needing scan must have bit0 == 0");
// Clean card has bit0 == 1.
static_assert(((uint)G1CardTable::clean_card_val() & 1U) == 1,
"clean card must have bit0 == 1");
__ lbu(tmp, Address(start, 0));
static_assert((uint)G1CardTable::clean_card_val() == 0xff, "must be");
__ subi(tmp, tmp, G1CardTable::clean_card_val()); // Convert to clean_card_value() to a comparison
// against zero to avoid use of an extra temp.
__ bnez(tmp, next);
__ test_bit(tmp, tmp, 0); // test bit0: clean has bit0 == 1, non-clean has bit0 == 0
__ beqz(tmp, next); // skip store if already non-clean
}
// `sb zr` writes 0, which must be the dirty value.
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
__ sb(zr, Address(start, 0));
@@ -264,14 +271,23 @@ static void generate_post_barrier(MacroAssembler* masm,
Address card_table_address(xthread, G1ThreadLocalData::card_table_base_offset());
__ ld(tmp2, card_table_address); // tmp2 := card table base address
__ add(tmp1, tmp1, tmp2); // tmp1 := card address
if (UseCondCardMark) {
static_assert((uint)G1CardTable::clean_card_val() == 0xff, "must be");
// All non-clean cards (dirty, to-cset, from-remset) have bit0 == 0.
static_assert((G1CardTable::g1_dirty_card & 1U) == 0
&& (G1CardTable::g1_to_cset_card & 1U) == 0
&& (G1CardTable::g1_from_remset_card & 1U) == 0,
"cards needing scan must have bit0 == 0");
// Clean card has bit0 == 1.
static_assert(((uint)G1CardTable::clean_card_val() & 1U) == 1,
"clean card must have bit0 == 1");
__ lbu(tmp2, Address(tmp1, 0)); // tmp2 := card
__ subi(tmp2, tmp2, G1CardTable::clean_card_val()); // Convert to clean_card_value() to a comparison
// against zero to avoid use of an extra temp.
__ bnez(tmp2, done);
__ test_bit(tmp2, tmp2, 0); // test bit0: clean has bit0 == 1, non-clean has bit0 == 0
__ beqz(tmp2, done); // skip store if already non-clean
}
static_assert((uint)G1CardTable::dirty_card_val() == 0, "must be to use zr");
// `sb zr` writes 0, which must be the dirty value.
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
__ sb(zr, Address(tmp1, 0));
}
@@ -854,7 +854,7 @@ void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
// Save the result where needed. Narrow entries return narrowOop (32 bits)
// we need to zero the upper 32 bits of x10.
if (_narrow) {
__ zext_w(_obj, x10);
__ zext(_obj, x10, 32);
} else {
__ mv(_obj, x10);
}
+5 -17
View File
@@ -2182,7 +2182,7 @@ void MacroAssembler::vector_update_crc32(Register crc, Register buf, Register le
vsetivli(zr, N, Assembler::e32, Assembler::m1, Assembler::mu, Assembler::tu);
}
vmv_v_x(vcrc, zr);
vmv_v_i(vcrc, 0);
vmv_s_x(vcrc, crc);
// multiple of 64
@@ -2327,7 +2327,7 @@ void MacroAssembler::kernel_crc32_vclmul_fold_vectorsize_16(Register crc, Regist
vle64_v(v6, buf); addi(buf, buf, STEP);
vle64_v(v7, buf); addi(buf, buf, STEP);
vmv_v_x(v31, zr);
vmv_v_i(v31, 0);
vsetivli(zr, 1, Assembler::e32, Assembler::m1, Assembler::mu, Assembler::tu);
vmv_s_x(v31, crc);
vsetivli(zr, N, Assembler::e64, Assembler::m1, Assembler::mu, Assembler::tu);
@@ -2450,7 +2450,7 @@ void MacroAssembler::kernel_crc32_vclmul_fold_vectorsize_32(Register crc, Regist
// now, v1 should contains: 010101...
// initial crc
vmv_v_x(v24, zr);
vmv_v_i(v24, 0);
vsetivli(zr, 1, Assembler::e32, Assembler::m4, Assembler::mu, Assembler::tu);
vmv_s_x(v24, crc);
vsetivli(zr, N, Assembler::e64, Assembler::m4, Assembler::mu, Assembler::tu);
@@ -3765,16 +3765,6 @@ void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int
assert_different_registers(temp_reg, t0);
// load mark word
ld(temp_reg, Address(oop, oopDesc::mark_offset_in_bytes()));
if (!UseObjectMonitorTable) {
Label test_mark_word;
// check displaced
test_bit(t0, temp_reg, exact_log2(markWord::unlocked_value));
bnez(t0, test_mark_word);
// slow path use klass prototype
load_prototype_header(temp_reg, oop);
bind(test_mark_word);
}
andi(temp_reg, temp_reg, tst_bit);
if (jmp_set) {
bnez(temp_reg, jmp_label, /* is_far */ true);
@@ -7035,10 +7025,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register tmp1,
// instruction emitted as it is part of C1's null check semantics.
ld(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
+34 -11
View File
@@ -1553,9 +1553,34 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
int src_offset = ra_->reg2offset(src_lo);
int dst_offset = ra_->reg2offset(dst_lo);
if (bottom_type()->isa_vect() != nullptr) {
uint ireg = ideal_reg();
if (ireg == Op_VecA && masm) {
// Stack-to-stack copies use t0 for the value. Bail out if a destination
// address also needs t0 to materialize an offset outside the 12-bit range.
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
int last_dst_offset = dst_offset;
if (bottom_type()->isa_vect() != nullptr) {
if (!bottom_type()->isa_pvectmask()) {
assert(ideal_reg() == Op_VecA, "Must be");
int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
last_dst_offset += vector_reg_size_in_bytes - 8;
} else {
assert(ideal_reg() == Op_RegVectMask, "Must be");
int vmask_size_in_bytes = Matcher::scalable_predicate_reg_slots() * 32 / 8;
last_dst_offset += vmask_size_in_bytes - 4;
}
}
if (masm != nullptr && !Assembler::is_simm12(last_dst_offset)) {
// size() emits into a scratch buffer where recording a failure is not allowed.
if (!C->output()->in_scratch_emit_size()) {
C->record_method_not_compilable("unsupported large stack-to-stack spill copy");
}
return 0;
}
}
if (bottom_type()->isa_vect() != nullptr && masm != nullptr) {
if (!bottom_type()->isa_pvectmask()) {
assert(ideal_reg() == Op_VecA, "Must be");
int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
// stack to stack
@@ -1574,7 +1599,8 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
} else {
ShouldNotReachHere();
}
} else if (bottom_type()->isa_pvectmask() && masm) {
} else {
assert(ideal_reg() == Op_RegVectMask, "Must be");
int vmask_size_in_bytes = Matcher::scalable_predicate_reg_slots() * 32 / 8;
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
// stack to stack
@@ -1677,14 +1703,11 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
st->print("%s", Matcher::regName[dst_lo]);
}
if (bottom_type()->isa_vect() && !bottom_type()->isa_pvectmask()) {
int vsize = 0;
if (ideal_reg() == Op_VecA) {
vsize = Matcher::scalable_vector_reg_size(T_BYTE) * 8;
} else {
ShouldNotReachHere();
}
assert(ideal_reg() == Op_VecA, "Must be");
int vsize = Matcher::scalable_vector_reg_size(T_BYTE) * 8;
st->print("\t# vector spill size = %d", vsize);
} else if (ideal_reg() == Op_RegVectMask) {
} else if (bottom_type()->isa_pvectmask()) {
assert(ideal_reg() == Op_RegVectMask, "Must be");
assert(Matcher::supports_scalable_vector(), "bad register type for spill");
int vsize = Matcher::scalable_predicate_reg_slots() * 32;
st->print("\t# vmask spill size = %d", vsize);
+38 -17
View File
@@ -41,7 +41,7 @@ source %{
__ vsex_v(reg, base, sew, vm);
} else {
if (vm == Assembler::v0_t) {
__ vxor_vv(reg, reg, reg);
__ vmv_v_i(reg, 0);
}
__ vlex_v(reg, base, sew, vm);
}
@@ -241,7 +241,7 @@ instruct vstoremask(vReg dst, vRegMask_V0 v0, immI size) %{
format %{ "vstoremask $dst, V0 # elem size is $size byte[s]" %}
ins_encode %{
__ vsetvli_helper(T_BOOLEAN, Matcher::vector_length(this));
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vmerge_vim(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), 1);
%}
ins_pipe(pipe_slow);
@@ -4482,7 +4482,7 @@ instruct vmaskAllL(vRegMask dst, iRegL src) %{
// ------------------------------ Vector mask basic OPs ------------------------
// vector mask logical ops: and/or/xor
// vector mask logical ops: and/and-not/or/xor
instruct vmask_and(vRegMask dst, vRegMask src1, vRegMask src2) %{
match(Set dst (AndVMask src1 src2));
@@ -4497,6 +4497,32 @@ instruct vmask_and(vRegMask dst, vRegMask src1, vRegMask src2) %{
ins_pipe(pipe_slow);
%}
instruct vmask_and_notI(vRegMask dst, vRegMask src1, vRegMask src2, immI_M1 m1) %{
match(Set dst (AndVMask src1 (XorVMask src2 (MaskAll m1))));
format %{ "vmask_and_notI $dst, $src1, $src2" %}
ins_encode %{
BasicType bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vmandn_mm(as_VectorRegister($dst$$reg),
as_VectorRegister($src1$$reg),
as_VectorRegister($src2$$reg));
%}
ins_pipe(pipe_slow);
%}
instruct vmask_and_notL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) %{
match(Set dst (AndVMask src1 (XorVMask src2 (MaskAll m1))));
format %{ "vmask_and_notL $dst, $src1, $src2" %}
ins_encode %{
BasicType bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vmandn_mm(as_VectorRegister($dst$$reg),
as_VectorRegister($src1$$reg),
as_VectorRegister($src2$$reg));
%}
ins_pipe(pipe_slow);
%}
instruct vmask_or(vRegMask dst, vRegMask src1, vRegMask src2) %{
match(Set dst (OrVMask src1 src2));
format %{ "vmask_or $dst, $src1, $src2" %}
@@ -4809,7 +4835,7 @@ instruct vcvtFtoL(vReg dst, vReg src, vRegMask_V0 v0) %{
format %{ "vcvtFtoL $dst, $src" %}
ins_encode %{
__ vsetvli_helper(T_LONG, Matcher::vector_length(this));
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vsetvli_helper(T_FLOAT, Matcher::vector_length(this), Assembler::mf2);
__ vmfeq_vv(as_VectorRegister($v0$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg));
__ vfwcvt_rtz_x_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), Assembler::v0_t);
@@ -4842,7 +4868,7 @@ instruct vcvtDtoX_narrow(vReg dst, vReg src, vRegMask_V0 v0) %{
__ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this));
__ vmfeq_vv(as_VectorRegister($v0$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg));
__ vsetvli_helper(T_INT, Matcher::vector_length(this), Assembler::mf2);
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vfncvt_rtz_x_f_w(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), Assembler::v0_t);
BasicType bt = Matcher::vector_element_basic_type(this);
if (bt == T_BYTE || bt == T_SHORT) {
@@ -4903,7 +4929,7 @@ instruct reinterpretResize(vReg dst, vReg src) %{
"invalid vector length");
BasicType bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vsetvli_helper(T_BYTE, length_in_bytes_resize);
__ vmv_v_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg));
%}
@@ -4931,7 +4957,7 @@ instruct vmask_reinterpret_diff_esize(vRegMask dst, vRegMask_V0 src, vReg tmp) %
ins_encode %{
BasicType from_bt = Matcher::vector_element_basic_type(this, $src);
__ vsetvli_helper(from_bt, Matcher::vector_length(this, $src));
__ vxor_vv(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg));
__ vmv_v_i(as_VectorRegister($tmp$$reg), 0);
__ vmerge_vim(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), -1);
BasicType to_bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(to_bt, Matcher::vector_length(this));
@@ -4990,8 +5016,7 @@ instruct rearrange_masked(vReg dst, vReg src, vReg shuffle, vRegMask_V0 v0) %{
ins_encode %{
BasicType bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vrgather_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
as_VectorRegister($shuffle$$reg), Assembler::v0_t);
%}
@@ -5105,8 +5130,7 @@ instruct vcompress(vReg dst, vReg src, vRegMask_V0 v0) %{
ins_encode %{
BasicType bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vcompress_vm(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
as_VectorRegister($v0$$reg));
%}
@@ -5121,8 +5145,7 @@ instruct vexpand(vReg dst, vReg src, vRegMask_V0 v0, vReg tmp) %{
BasicType bt = Matcher::vector_element_basic_type(this);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ viota_m(as_VectorRegister($tmp$$reg), as_VectorRegister($v0$$reg));
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vrgather_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
as_VectorRegister($tmp$$reg), Assembler::v0_t);
%}
@@ -5383,8 +5406,7 @@ instruct gather_loadS_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, v
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew);
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vluxei32_v(as_VectorRegister($dst$$reg), as_Register($mem$$base),
as_VectorRegister($tmp$$reg), Assembler::v0_t);
%}
@@ -5402,8 +5424,7 @@ instruct gather_loadD_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, v
__ vsetvli_helper(bt, Matcher::vector_length(this));
__ vzext_vf2(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg));
__ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew);
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
as_VectorRegister($dst$$reg));
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
__ vluxei64_v(as_VectorRegister($dst$$reg), as_Register($mem$$base),
as_VectorRegister($tmp$$reg), Assembler::v0_t);
%}
+2 -2
View File
@@ -760,8 +760,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
}
bool frame::was_augmented_on_entry(int& real_size) const {
assert(is_compiled_frame(), "");
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
assert(_cb != nullptr && _cb->is_nmethod(), "");
if (_cb->as_nmethod()->needs_stack_repair()) {
Unimplemented();
}
real_size = _cb->frame_size();
+53 -84
View File
@@ -4265,15 +4265,6 @@ void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int
assert(test_bit <= 0xFFFF, "must fit in low 16 bits for z_tmll");
// Load mark word
z_lg(temp_reg, oopDesc::mark_offset_in_bytes(), oop);
if (!UseObjectMonitorTable) {
Label test_mark_word;
// If unlocked bit is set we can directly use the mark word
z_tmll(temp_reg, markWord::unlocked_value);
z_brnaz(test_mark_word);
// Slow path: use klass prototype
load_prototype_header(temp_reg, oop);
bind(test_mark_word);
}
z_tmll(temp_reg, test_bit);
// Use branch_optimized to handle both near and far branches automatically
branch_optimized(jmp_set ? Assembler::bcondNotAllZero : Assembler::bcondAllZero, jmp_label);
@@ -6357,11 +6348,9 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register temp1
// instruction emitted as it is part of C1's null check semantics.
z_lg(mark, Address(obj, mark_offset));
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())));
z_mvghi(om_cache_addr, 0);
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())));
z_mvghi(om_cache_addr, 0);
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(temp1, obj);
@@ -6506,10 +6495,8 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis
// Finish fast lock unsuccessfully. MUST branch to with flag == EQ
NearLabel slow_path;
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
@@ -6587,61 +6574,57 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
const ByteSize omc_obj_offset = OMCache::obj_offset();
if (!UseObjectMonitorTable) {
assert(tmp1_monitor == mark, "should be the same here");
} else {
const Register tmp1_bucket = tmp1;
const Register hash = Z_R0_scratch;
NearLabel monitor_found;
const Register tmp1_bucket = tmp1;
const Register hash = Z_R0_scratch;
NearLabel monitor_found;
// Save the mark, we might need it to extract the hash.
z_lgr(hash, mark);
// Save the mark, we might need it to extract the hash.
z_lgr(hash, mark);
// Look for the monitor in the current thread's object monitor cache (omc).
// Look for the monitor in the current thread's object monitor cache (omc).
z_lg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
z_cg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
z_bre(monitor_found);
z_lg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
z_cg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
z_bre(monitor_found);
// Get the hash code.
z_srlg(hash, hash, markWord::hash_shift);
// Get the hash code.
z_srlg(hash, hash, markWord::hash_shift);
// Get the table and calculate the bucket's address.
load_const_optimized(tmp2, ObjectMonitorTable::current_table_address());
z_lg(tmp2, Address(tmp2));
z_ng(hash, Address(tmp2, ObjectMonitorTable::table_capacity_mask_offset()));
z_lg(tmp1_bucket, Address(tmp2, ObjectMonitorTable::table_buckets_offset()));
z_sllg(hash, hash, LogBytesPerWord);
z_agr(tmp1_bucket, hash);
// Get the table and calculate the bucket's address.
load_const_optimized(tmp2, ObjectMonitorTable::current_table_address());
z_lg(tmp2, Address(tmp2));
z_ng(hash, Address(tmp2, ObjectMonitorTable::table_capacity_mask_offset()));
z_lg(tmp1_bucket, Address(tmp2, ObjectMonitorTable::table_buckets_offset()));
z_sllg(hash, hash, LogBytesPerWord);
z_agr(tmp1_bucket, hash);
// Read the monitor from the bucket.
z_lg(tmp1_monitor, Address(tmp1_bucket));
// Read the monitor from the bucket.
z_lg(tmp1_monitor, Address(tmp1_bucket));
// Check if the monitor in the bucket is special (empty, tombstone or removed).
z_clgfi(tmp1_monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
z_brl(slow_path);
// Check if the monitor in the bucket is special (empty, tombstone or removed).
z_clgfi(tmp1_monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
z_brl(slow_path);
// Check if object matches.
z_lg(tmp2, Address(tmp1_monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp2, tmp2, Z_R0_scratch, slow_path);
z_cgr(obj, tmp2);
z_brne(slow_path);
// Check if object matches.
z_lg(tmp2, Address(tmp1_monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp2, tmp2, Z_R0_scratch, slow_path);
z_cgr(obj, tmp2);
z_brne(slow_path);
// Store the monitor in the current thread's object monitor cache (omc).
z_stg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
z_stg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
// Store the monitor in the current thread's object monitor cache (omc).
z_stg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
z_stg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
bind(monitor_found);
bind(monitor_found);
}
NearLabel monitor_locked;
// lock the monitor
const Register zero = tmp2;
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset());
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset());
// Try to CAS owner (no owner => current thread's _monitor_owner_id).
// If csg succeeds then CR=EQ, otherwise, register zero is filled
@@ -6659,10 +6642,8 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis
z_agsi(recursions_address, 1ll);
bind(monitor_locked);
if (UseObjectMonitorTable) {
// Cache the monitor for unlock.
z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
}
// Cache the monitor for unlock.
z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// set the CC now
z_cgr(obj, obj);
}
@@ -6739,11 +6720,7 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg
// so that the runtime can fix any potential anonymous owner.
z_lg(mark, Address(obj, mark_offset));
z_tmll(mark, markWord::monitor_value);
if (!UseObjectMonitorTable) {
z_brnaz(inflated);
} else {
z_brnaz(push_and_slow_path);
}
z_brnaz(push_and_slow_path);
#ifdef ASSERT
// Check header not unlocked (0b01).
@@ -6802,25 +6779,20 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg
const Register tmp1_monitor = tmp1;
if (!UseObjectMonitorTable) {
assert(tmp1_monitor == mark, "should be the same here");
} else {
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
z_cghi(tmp1_monitor, alignof(ObjectMonitor*));
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
z_cghi(tmp1_monitor, alignof(ObjectMonitor*));
z_brl(slow_path);
}
z_brl(slow_path);
// mark contains the tagged ObjectMonitor*.
const Register monitor = mark;
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag};
const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag};
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset() - monitor_tag};
const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag};
const Address recursions_address{monitor, ObjectMonitor::recursions_offset()};
const Address succ_address{monitor, ObjectMonitor::succ_offset()};
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset()};
const Address owner_address{monitor, ObjectMonitor::owner_offset()};
NearLabel not_recursive;
const Register recursions = tmp2;
@@ -6856,9 +6828,6 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg
// Save the monitor pointer in the current thread, so we can try to
// reacquire the lock in SharedRuntime::monitor_exit_helper().
if (!UseObjectMonitorTable) {
z_xilf(monitor, markWord::monitor_value);
}
z_stg(monitor, Address(Z_thread, JavaThread::unlocked_inflated_monitor_offset()));
z_ltgr(obj, obj); // Set flag = NE
+6 -6
View File
@@ -8547,12 +8547,12 @@ void Assembler::vsqrtsh(XMMRegister dst, XMMRegister src) {
emit_int16(0x51, (0xC0 | encode));
}
void Assembler::vfmadd132sh(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
void Assembler::vfmadd231sh(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
assert(VM_Version::supports_avx512_fp16(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes);
emit_int16((unsigned char)0x99, (0xC0 | encode));
emit_int16((unsigned char)0xB9, (0xC0 | encode));
}
void Assembler::vpaddsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
@@ -17057,16 +17057,16 @@ void Assembler::evsqrtph(XMMRegister dst, Address src, int vector_len) {
emit_operand(dst, src, 0);
}
void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
void Assembler::evfmadd231ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_fp16(), "");
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes);
emit_int16(0x98, (0xC0 | encode));
emit_int16((unsigned char)0xB8, (0xC0 | encode));
}
void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) {
void Assembler::evfmadd231ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) {
assert(VM_Version::supports_avx512_fp16(), "");
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionMark im(this);
@@ -17074,7 +17074,7 @@ void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int
attributes.set_is_evex_instruction();
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes);
emit_int8(0x98);
emit_int8((unsigned char)0xB8);
emit_operand(dst, src, 0);
}
+3 -3
View File
@@ -2569,7 +2569,7 @@ private:
void vmulsh(XMMRegister dst, XMMRegister nds, XMMRegister src);
void vdivsh(XMMRegister dst, XMMRegister nds, XMMRegister src);
void vsqrtsh(XMMRegister dst, XMMRegister src);
void vfmadd132sh(XMMRegister dst, XMMRegister src1, XMMRegister src2);
void vfmadd231sh(XMMRegister dst, XMMRegister src1, XMMRegister src2);
// Saturating packed insturctions.
void vpaddsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
@@ -2757,8 +2757,8 @@ private:
void evminph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
void evmaxph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void evmaxph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
void evfmadd132ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
void evfmadd231ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void evfmadd231ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
void evsqrtph(XMMRegister dst, XMMRegister src1, int vector_len);
void evsqrtph(XMMRegister dst, Address src1, int vector_len);
+57 -82
View File
@@ -276,10 +276,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
// Finish fast lock unsuccessfully. MUST jump with ZF == 0
Label slow_path;
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(rax_reg, obj, t);
@@ -293,7 +291,7 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
Label push;
const Register top = UseObjectMonitorTable ? rax_reg : box;
const Register top = rax_reg;
// Load the mark.
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
@@ -320,10 +318,9 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
jcc(Assembler::notEqual, slow_path);
if (UseObjectMonitorTable) {
// Need to reload top, clobbered by CAS.
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
}
// Need to reload top, clobbered by CAS.
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
bind(push);
// After successful lock, push object on lock-stack.
movptr(Address(thread, top), obj);
@@ -340,63 +337,57 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
const ByteSize omc_obj_offset = OMCache::obj_offset();
if (!UseObjectMonitorTable) {
assert(mark == monitor, "should be the same here");
} else {
const Register hash = t;
Label monitor_found;
const Register hash = t;
Label monitor_found;
// Look for the monitor in the current thread's object monitor cache (omc).
// Look for the monitor in the current thread's object monitor cache (omc).
movptr(monitor, Address(thread, thr_omc_offset + omc_monitor_offset));
cmpptr(obj, Address(thread, thr_omc_offset + omc_obj_offset));
jccb(Assembler::equal, monitor_found);
movptr(monitor, Address(thread, thr_omc_offset + omc_monitor_offset));
cmpptr(obj, Address(thread, thr_omc_offset + omc_obj_offset));
jccb(Assembler::equal, monitor_found);
// Look for the monitor in the table.
// Look for the monitor in the table.
// Get the hash code.
movptr(hash, Address(obj, oopDesc::mark_offset_in_bytes()));
shrq(hash, markWord::hash_shift);
andq(hash, markWord::hash_mask);
// Get the hash code.
movptr(hash, Address(obj, oopDesc::mark_offset_in_bytes()));
shrq(hash, markWord::hash_shift);
andq(hash, markWord::hash_mask);
// Get the table and calculate the bucket's address.
lea(rax_reg, ExternalAddress(ObjectMonitorTable::current_table_address()));
movptr(rax_reg, Address(rax_reg));
andq(hash, Address(rax_reg, ObjectMonitorTable::table_capacity_mask_offset()));
movptr(rax_reg, Address(rax_reg, ObjectMonitorTable::table_buckets_offset()));
// Get the table and calculate the bucket's address.
lea(rax_reg, ExternalAddress(ObjectMonitorTable::current_table_address()));
movptr(rax_reg, Address(rax_reg));
andq(hash, Address(rax_reg, ObjectMonitorTable::table_capacity_mask_offset()));
movptr(rax_reg, Address(rax_reg, ObjectMonitorTable::table_buckets_offset()));
// Read the monitor from the bucket.
movptr(monitor, Address(rax_reg, hash, Address::times_ptr));
// Read the monitor from the bucket.
movptr(monitor, Address(rax_reg, hash, Address::times_ptr));
// Check if the monitor in the bucket is special (empty, tombstone or removed)
cmpptr(monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
jcc(Assembler::below, slow_path);
// Check if the monitor in the bucket is special (empty, tombstone or removed)
cmpptr(monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
jcc(Assembler::below, slow_path);
// Check if object matches.
movptr(rax_reg, Address(monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, rax_reg, rax_reg, slow_path);
cmpptr(rax_reg, obj);
jcc(Assembler::notEqual, slow_path);
// Check if object matches.
movptr(rax_reg, Address(monitor, ObjectMonitor::object_offset()));
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->try_peek_weak_handle_in_nmethod(this, rax_reg, rax_reg, slow_path);
cmpptr(rax_reg, obj);
jcc(Assembler::notEqual, slow_path);
// Store the monitor in the current thread's object monitor cache (omc).
movptr(Address(thread, thr_omc_offset + omc_monitor_offset), monitor);
movptr(Address(thread, thr_omc_offset + omc_obj_offset), obj);
// Store the monitor in the current thread's object monitor cache (omc).
movptr(Address(thread, thr_omc_offset + omc_monitor_offset), monitor);
movptr(Address(thread, thr_omc_offset + omc_obj_offset), obj);
bind(monitor_found);
}
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
const Address recursions_address(monitor, ObjectMonitor::recursions_offset() - monitor_tag);
const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag);
bind(monitor_found);
const Address recursions_address(monitor, ObjectMonitor::recursions_offset());
const Address owner_address(monitor, ObjectMonitor::owner_offset());
Label monitor_locked;
// Lock the monitor.
if (UseObjectMonitorTable) {
// Cache the monitor for unlock before trashing box. On failure to acquire
// the lock, the slow path will reset the entry accordingly (see CacheSetter).
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor);
}
// Cache the monitor for unlock before trashing box. On failure to acquire
// the lock, the slow path will reset the entry accordingly (see CacheSetter).
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor);
// Try to CAS owner (no owner => current thread's _monitor_owner_id).
xorptr(rax_reg, rax_reg);
@@ -481,7 +472,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
const Register mark = t;
const Register monitor = t;
const Register top = UseObjectMonitorTable ? t : reg_rax;
const Register top = t;
const Register box = reg_rax;
Label dummy;
@@ -499,11 +490,6 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
// Load top.
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
if (!UseObjectMonitorTable) {
// Prefetch mark.
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
}
// Check if obj is top of lock-stack.
cmpptr(obj, Address(thread, top, Address::times_1, -oopSize));
// Top of lock stack was not obj. Must be monitor.
@@ -519,10 +505,8 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
// We elide the monitor check, let the CAS fail instead.
if (UseObjectMonitorTable) {
// Load mark.
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
}
// Load mark.
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
// Try to unlock. Transition lock bits 0b00 => 0b01
movptr(reg_rax, mark);
@@ -545,9 +529,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
jcc(Assembler::notEqual, inflated_check_lock_stack);
stop("Fast Unlock lock on stack");
bind(check_done);
if (UseObjectMonitorTable) {
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
}
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
testptr(mark, markWord::monitor_value);
jcc(Assembler::notZero, inflated);
stop("Fast Unlock not monitor");
@@ -555,20 +537,16 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
bind(inflated);
if (!UseObjectMonitorTable) {
assert(mark == monitor, "should be the same here");
} else {
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
cmpptr(monitor, alignof(ObjectMonitor*));
jcc(Assembler::below, slow_path);
}
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag};
const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag};
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset() - monitor_tag};
const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag};
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
cmpptr(monitor, alignof(ObjectMonitor*));
jcc(Assembler::below, slow_path);
const Address recursions_address{monitor, ObjectMonitor::recursions_offset()};
const Address succ_address{monitor, ObjectMonitor::succ_offset()};
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset()};
const Address owner_address{monitor, ObjectMonitor::owner_offset()};
Label recursive;
@@ -593,9 +571,6 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
// Save the monitor pointer in the current thread, so we can try to
// reacquire the lock in SharedRuntime::monitor_exit_helper().
if (!UseObjectMonitorTable) {
andptr(monitor, ~(int32_t)markWord::monitor_value);
}
movptr(Address(thread, JavaThread::unlocked_inflated_monitor_offset()), monitor);
orl(t, 1); // Fast Unlock ZF = 0
+2 -2
View File
@@ -660,8 +660,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
}
bool frame::was_augmented_on_entry(int& real_size) const {
assert(is_compiled_frame(), "");
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
assert(_cb != nullptr && _cb->is_nmethod(), "");
if (_cb->as_nmethod()->needs_stack_repair()) {
// The stack increment resides just below the saved rbp on the stack
// and does not account for the return address and rbp (see MacroAssembler::remove_frame).
intptr_t* real_frame_size_addr = unextended_sp() + _cb->frame_size() - sender_sp_offset - 1;
@@ -24,6 +24,7 @@
#include "asm/macroAssembler.inline.hpp"
#include "classfile/classLoaderData.hpp"
#include "code/aotCodeCache.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
@@ -363,11 +364,23 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
}
void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
assert_different_registers(obj, tmp1, tmp2);
// Check if the oop is in the right area of memory
__ movptr(tmp1, obj);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
__ movptr(tmp2, Address(tmp2));
__ andptr(tmp1, tmp2);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
__ movptr(tmp2, Address(tmp2));
} else
#endif
{
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
}
__ cmpptr(tmp1, tmp2);
__ jcc(Assembler::notZero, error);
@@ -24,6 +24,7 @@
*
*/
#include "code/aotCodeCache.hpp"
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
#include "gc/shenandoah/mode/shenandoahMode.hpp"
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
@@ -263,6 +264,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
// Optimized cset-test
__ movptr(tmp1, dst);
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
assert_different_registers(tmp1, tmp2, rcx);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
@@ -272,7 +274,9 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
__ pop(rcx);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
__ movptr(tmp2, Address(tmp2));
} else {
} else
#endif
{
__ shrptr(tmp1, ShenandoahHeapRegion::region_size_bytes_shift_jint());
__ movptr(tmp2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
}
@@ -504,11 +508,23 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
}
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
assert_different_registers(obj, tmp1, tmp2);
// Check if the oop is in the right area of memory
__ movptr(tmp1, obj);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
__ movptr(tmp2, Address(tmp2));
__ andptr(tmp1, tmp2);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
__ movptr(tmp2, Address(tmp2));
} else
#endif
{
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
}
__ cmpptr(tmp1, tmp2);
__ jcc(Assembler::notZero, L_error);
@@ -839,7 +855,8 @@ void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
// If buffer is already full, go slow.
__ movptr(tmp, index);
__ subptr(tmp, wordSize);
__ jccb(Assembler::below, L_pop_and_slow);
// VerifyOops adds code for decoded oop and needs long jump here
__ jcc(Assembler::below, L_pop_and_slow);
__ movptr(index, tmp);
__ addptr(tmp, buffer);
@@ -22,6 +22,7 @@
*/
#include "asm/macroAssembler.inline.hpp"
#include "code/aotCodeCache.hpp"
#include "code/codeBlob.hpp"
#include "code/vmreg.inline.hpp"
#include "compiler/compileTask.hpp"
@@ -1501,8 +1502,11 @@ void ZBarrierSetAssembler::retrieve_reloc_addresses(address start, address end,
entries.append(nullptr);
}
// Add indirection for AOT code patching
address ZPointerLoadShiftTableAddr = (address)&ZPointerLoadShiftTable;
void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
assert_different_registers(obj, tmp1, tmp2);
// C1 calls verfy_oop in the middle of barriers, before they have been uncolored
// and after being colored. Therefore, we must deal with colored oops as well.
Label done;
@@ -1533,8 +1537,10 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
__ andq(tmp1, tmp2);
__ shrq(tmp1, ZPointerRemappedShift);
__ andq(tmp1, (1 << ZPointerRemappedBits) - 1);
__ lea(tmp2, ExternalAddress((address)&ZPointerLoadShiftTable));
// This code is not critical - it is used only for VerifyOops in debug VM.
// Use inderection by defult without AOT specific code.
__ lea(tmp2, ExternalAddress((address)&ZPointerLoadShiftTableAddr));
__ movptr(tmp2, Address(tmp2));
// Uncolor presumed zpointer
assert(obj != rcx, "bad choice of register");
if (rcx != tmp1 && rcx != tmp2) {
@@ -1558,9 +1564,20 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
__ bind(check_zaddress);
// Check if the oop is in the right area of memory
__ movptr(tmp1, obj);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump()) {
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
__ movptr(tmp2, Address(tmp2));
__ andptr(tmp1, tmp2);
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
__ movptr(tmp2, Address(tmp2));
} else
#endif
{
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
}
__ cmpptr(tmp1, tmp2);
__ jcc(Assembler::notZero, error);
+20 -18
View File
@@ -2444,18 +2444,6 @@ void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label
void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int32_t test_bit, bool jmp_set, Label& jmp_label) {
// load mark word
movptr(temp_reg, Address(oop, oopDesc::mark_offset_in_bytes()));
if (!UseObjectMonitorTable) {
Label test_mark_word;
// check displaced
testl(temp_reg, markWord::unlocked_value);
jccb(Assembler::notZero, test_mark_word);
// slow path use klass prototype
push(rscratch1);
load_prototype_header(temp_reg, oop, rscratch1);
pop(rscratch1);
bind(test_mark_word);
}
testl(temp_reg, test_bit);
jcc((jmp_set) ? Assembler::notZero : Assembler::zero, jmp_label);
}
@@ -4912,7 +4900,15 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
ResourceMark rm;
stringStream ss;
ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line);
b = code_string(ss.as_string());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
// this will duplicate string to preserve it
b = AOTCodeCache::add_C_string(ss.as_string());
} else
#endif
{
b = code_string(ss.as_string());
}
}
AddressLiteral buffer((address) b, external_word_Relocation::spec_for_immediate());
pushptr(buffer.addr(), rscratch1);
@@ -5177,7 +5173,15 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
ResourceMark rm;
stringStream ss;
ss.print("verify_oop_addr: %s (%s:%d)", s, file, line);
b = code_string(ss.as_string());
#if INCLUDE_CDS
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
// this will duplicate string to preserve it
b = AOTCodeCache::add_C_string(ss.as_string());
} else
#endif
{
b = code_string(ss.as_string());
}
}
AddressLiteral buffer((address) b, external_word_Relocation::spec_for_immediate());
pushptr(buffer.addr(), rscratch1);
@@ -10595,10 +10599,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register reg_r
// instruction emitted as it is part of C1's null check semantics.
movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes()));
if (UseObjectMonitorTable) {
// Clear cache in case fast locking succeeds or we need to take the slow-path.
movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0);
}
// Clear cache in case fast locking succeeds or we need to take the slow-path.
movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0);
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, obj, rscratch1);
+1 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,12 +59,6 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas
__ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
if (!UseObjectMonitorTable) {
// check if monitor
__ testptr(result, markWord::monitor_value);
__ jcc(Assembler::notZero, slowCase);
}
// get hash
// Read the header and build a mask to get its hash field.
// Depend on hash_mask being at most 32 bits and avoid the use of hash_mask_in_place
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, Intel Corporation. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -254,7 +254,7 @@ static auto whole_shuffle(Register scratch, KRegister mergeMask1, KRegister merg
// swap the second operand (zetas) since the odd slots contain the same number
// as the corresponding even one. This is indicated by input2NeedsShuffle=false)
//
// The registers to be multiplied are in input1[] and inputs2[]. The results go
// The registers to be multiplied are in input1[] and input2[]. The results go
// into output[]. Two scratch[] register arrays are expected. input1[] can
// overlap with either output[] or scratch1[]
// - If AVX512, all register arrays are of length 4
@@ -279,7 +279,7 @@ static auto whole_montMul(XMMRegister montQInvModR, XMMRegister dilithium_q,
// If so, use output:
const XMMRegister* scratch = scratch1 == input1 ? output: scratch1;
// scratch = input1_even * intput2_even
// scratch = input1_even * input2_even
for (int i = 0; i < regCnt; i++) {
__ vpmuldq(scratch[i], input1[i], input2[i], vector_len);
}
@@ -308,7 +308,7 @@ static auto whole_montMul(XMMRegister montQInvModR, XMMRegister dilithium_q,
}
}
// scratch1 = input1_even*intput2_even
// scratch1 = input1_even*input2_even
for (int i = 0; i < regCnt; i++) {
__ vpmuldq(scratch1[i], input1[i], input2[i], vector_len);
}
@@ -423,7 +423,7 @@ static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen,
// products will be added to and subtracted from the other half of the
// coefficients. In each level we just shuffle the coefficients that need to
// be multiplied by the zetas in one set, the rest to another set of vector
// registers, then redistribute the addition/substraction results.
// registers, then redistribute the addition/subtraction results.
// For levels 0 and 1 the zetas are not different within the 4 xmm registers
// that we would use for them, so we use only one register.
@@ -649,7 +649,7 @@ static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen,
}
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -898,7 +898,7 @@ static address generate_dilithiumAlmostInverseNtt_avx(StubGenerator *stubgen,
}
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -993,7 +993,7 @@ static address generate_dilithiumNttMult_avx(StubGenerator *stubgen,
__ jcc(Assembler::notEqual, L_loop);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -1002,7 +1002,7 @@ static address generate_dilithiumNttMult_avx(StubGenerator *stubgen,
return start;
}
// Dilithium Motgomery multiply an array by a constant.
// Dilithium Montgomery multiply an array by a constant.
// Implements
// static int implDilithiumMontMulByConstant(int[] coeffs, int constant) {}
//
@@ -1089,7 +1089,7 @@ static address generate_dilithiumMontMulByConstant_avx(StubGenerator *stubgen,
__ jcc(Assembler::notEqual, L_loop);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -1357,7 +1357,7 @@ static address generate_dilithiumDecomposePoly_avx(StubGenerator *stubgen,
__ jcc(Assembler::notEqual, L_loop);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -349,11 +349,13 @@ static void store4regs(Register address, int offset, int sourceRegs[],
}
}
// In all 3 invocations of this function we use the same registers:
// xmm0-xmm7 for the input and the result,
// xmm8-xmm15 as scratch registers and
// xmm16-xmm17 for the constants,
// so we don't pass register arguments.
// This stub helper vectorizes the reduction in implKyberBarrettReduceJava.
// In all invocations of this function we use the same registers:
// Input: xmm0-xmm7 (signed short coefficients)
// xmm16: Barrett multiplier
// xmm17: q
// Scratch: xmm8-xmm15
// Output: xmm0-xmm7 (reduced coefficients each in [0, q])
static void barrettReduce(MacroAssembler *_masm) {
for (int i = 0; i < 8; i++) {
__ evpmulhw(xmm(i + 8), k0, xmm(i), xmm16, false, Assembler::AVX_512bit);
@@ -490,7 +492,7 @@ address generate_kyberNtt_avx512(StubGenerator *stubgen,
store4regs(coeffs, 256, xmm4_7, _masm);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -621,7 +623,7 @@ address generate_kyberInverseNtt_avx512(StubGenerator *stubgen,
store4regs(coeffs, 256, xmm12_15, _masm);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -771,7 +773,7 @@ address generate_kyberNttMult_avx512(StubGenerator *stubgen,
__ pop_ppx(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -824,7 +826,7 @@ address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen,
store4regs(result, 256, xmm4_7, _masm);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -886,7 +888,7 @@ address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen,
store4regs(result, 256, xmm4_7, _masm);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -975,7 +977,7 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen,
__ jcc(Assembler::greater, VBMILoop);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -1051,7 +1053,7 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen,
__ jcc(Assembler::greater, Loop);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -1096,7 +1098,7 @@ address generate_kyberBarrettReduce_avx512(StubGenerator *stubgen,
store4regs(coeffs, 256, xmm4_7, _masm);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
__ ret(0);
// record the stub entry and end
@@ -628,7 +628,7 @@ static address generate_sha3_implCompress_avx512(StubId stub_id,
// (2) - a lot of shuffles are inevitable, since there are not enough registers.
// To save some shuffles, column1-column3 and column2-4 are placed into
// the same 128-bit register. Column 0 is also grouped (by rows).
// This means the SHA3 state fits into 12.5 regisers, leaving 3 registers as
// This means the SHA3 state fits into 12.5 registers, leaving 3 registers as
// temporaries. This is mostly sufficient, except for the Theta step, where we
// have to buy two slots on the stack
static address generate_sha3_implCompress_avx2(StubId stub_id,
@@ -693,7 +693,7 @@ static address generate_sha3_implCompress_avx2(StubId stub_id,
__ subptr(rsp, reg_size*2);
// Registers for memory load
// Notice the careful 'missalignment' of pairs.
// Notice the careful 'misalignment' of pairs.
// This helps XOR for all blocksizes
XMMRegister a0a1, _a2, a3a4;
XMMRegister a5a6, a7a8, _a9;
+16 -15
View File
@@ -24809,12 +24809,11 @@ instruct long_to_mask_evex(kReg dst, rRegL src) %{
ins_pipe( pipe_slow );
%}
instruct mask_opers_evex(kReg dst, kReg src1, kReg src2, kReg kscratch) %{
instruct mask_opers_evex(kReg dst, kReg src1, kReg src2) %{
match(Set dst (AndVMask src1 src2));
match(Set dst (OrVMask src1 src2));
match(Set dst (XorVMask src1 src2));
effect(TEMP kscratch);
format %{ "mask_opers_evex $dst, $src1, $src2\t! using $kscratch as TEMP" %}
format %{ "mask_opers_evex $dst, $src1, $src2" %}
ins_encode %{
const MachNode* mask1 = static_cast<const MachNode*>(this->in(this->operand_index($src1)));
const MachNode* mask2 = static_cast<const MachNode*>(this->in(this->operand_index($src2)));
@@ -25247,11 +25246,10 @@ instruct scalar_minmax_HF_reg(regF dst, regF src1, regF src2, kReg ktmp, regF xt
instruct scalar_fma_HF_reg(regF dst, regF src1, regF src2)
%{
match(Set dst (FmaHF src2 (Binary dst src1)));
effect(DEF dst);
format %{ "scalar_fma_fp16 $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %}
match(Set dst (FmaHF dst (Binary src1 src2)));
format %{ "scalar_fma_fp16 $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %}
ins_encode %{
__ vfmadd132sh($dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister);
__ vfmadd231sh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
@@ -25270,6 +25268,7 @@ instruct vector_sqrt_HF_reg(vec dst, vec src)
instruct vector_sqrt_HF_mem(vec dst, memory src)
%{
predicate(Matcher::vector_length_in_bytes(n) > 8);
match(Set dst (SqrtVHF (VectorReinterpret (LoadVector src))));
format %{ "vector_sqrt_fp16_mem $dst, $src" %}
ins_encode %{
@@ -25297,6 +25296,7 @@ instruct vector_binOps_HF_reg(vec dst, vec src1, vec src2)
instruct vector_binOps_HF_mem(vec dst, vec src1, memory src2)
%{
predicate(Matcher::vector_length_in_bytes(n) > 8);
match(Set dst (AddVHF src1 (VectorReinterpret (LoadVector src2))));
match(Set dst (DivVHF src1 (VectorReinterpret (LoadVector src2))));
match(Set dst (MulVHF src1 (VectorReinterpret (LoadVector src2))));
@@ -25312,29 +25312,30 @@ instruct vector_binOps_HF_mem(vec dst, vec src1, memory src2)
instruct vector_fma_HF_reg(vec dst, vec src1, vec src2)
%{
match(Set dst (FmaVHF src2 (Binary dst src1)));
format %{ "vector_fma_fp16 $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %}
match(Set dst (FmaVHF dst (Binary src1 src2)));
format %{ "vector_fma_fp16 $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %}
ins_encode %{
int vlen_enc = vector_length_encoding(this);
__ evfmadd132ph($dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister, vlen_enc);
__ evfmadd231ph($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct vector_fma_HF_mem(vec dst, memory src1, vec src2)
instruct vector_fma_HF_mem(vec dst, vec src1, memory src2)
%{
match(Set dst (FmaVHF src2 (Binary dst (VectorReinterpret (LoadVector src1)))));
format %{ "vector_fma_fp16_mem $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %}
predicate(Matcher::vector_length_in_bytes(n) > 8);
match(Set dst (FmaVHF dst (Binary src1 (VectorReinterpret (LoadVector src2)))));
format %{ "vector_fma_fp16_mem $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %}
ins_encode %{
int vlen_enc = vector_length_encoding(this);
__ evfmadd132ph($dst$$XMMRegister, $src2$$XMMRegister, $src1$$Address, vlen_enc);
__ evfmadd231ph($dst$$XMMRegister, $src1$$XMMRegister, $src2$$Address, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct vector_minmax_HF_mem_avx10_2(vec dst, vec src1, memory src2)
%{
predicate(VM_Version::supports_avx10_2());
predicate(VM_Version::supports_avx10_2() && Matcher::vector_length_in_bytes(n) > 8);
match(Set dst (MinVHF src1 (VectorReinterpret (LoadVector src2))));
match(Set dst (MaxVHF src1 (VectorReinterpret (LoadVector src2))));
format %{ "vector_min_max_fp16_mem $dst, $src1, $src2" %}
+5 -1
View File
@@ -1897,7 +1897,11 @@ static bool checked_mprotect(char* addr, size_t size, int prot) {
}
}
assert(rc == true, "mprotect failed.");
if (!rc) {
// Reporting success via mprotect but failing to mprotect is a symptom of calling mprotect
// on SystemV-memory. It should not happen for mmap-mode.
assert(!g_multipage_support.can_use_64K_mmap_pages, "Should only happen in old-style shmat mode");
}
return rc;
}
+16
View File
@@ -79,6 +79,9 @@
#include "utilities/population_count.hpp"
#include "utilities/vmError.hpp"
#include "windbghelp.hpp"
#if defined(_M_ARM64)
#include CPU_HEADER(pauth)
#endif
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
@@ -6637,6 +6640,19 @@ bool os::win32::platform_print_native_stack(outputStream* st, const void* contex
int count = 0;
address lastpc_internal = 0;
while (count++ < StackPrintLimit) {
#if defined(_M_ARM64)
// On Windows/ARM64, when the CPU is using authenticated pointers, return
// addresses are signed. Unfortunately, `StackWalk64()` does not strip the
// pointer signature, so we need to do this ourself. Since stripping the
// signature is an idempotent operation, we don't need to guard this call
// based on whether pointer authentication is enabled.
address original = (address)stk.AddrPC.Offset;
address stripped = pauth_strip_pointer(original);
stk.AddrPC.Offset = (DWORD64)(uintptr_t)stripped;
// We updated the stack frame's PC, so keep the context's PC in sync.
ctx.Pc = stk.AddrPC.Offset;
#endif
intptr_t* sp = (intptr_t*)stk.AddrStack.Offset;
intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp!
address pc = (address)stk.AddrPC.Offset;
@@ -0,0 +1,47 @@
;
; Copyright (c) 2026, Microsoft and/or its affiliates. All rights reserved.
; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
;
; This code is free software; you can redistribute it and/or modify it
; under the terms of the GNU General Public License version 2 only, as
; published by the Free Software Foundation.
;
; This code is distributed in the hope that it will be useful, but WITHOUT
; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
; version 2 for more details (a copy is included in the LICENSE file that
; accompanied this code).
;
; You should have received a copy of the GNU General Public License version
; 2 along with this work; if not, write to the Free Software Foundation,
; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
;
; Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
; or visit www.oracle.com if you need additional information or have any
; questions.
;
; Remove the AArch64 pointer signature from the pointer argument
;
; Both XPACI and XPACLRI can get the job done, with XPACI being more
; convenient since it can work with any general purpose register. However,
; unlike XPACI, XPACLRI can be encoded using hint instructions, thus letting
; us compile this function using older compilers.
;
; Since XPACLRI implicitly uses the link register (x30) and we instead want
; to remove the signature from the function argument (in x0), we temporarily
; save x30 before restoring it at the end.
ALIGN 4
EXPORT pauth_drop_signature_win_arm64
AREA pauth_text, CODE
pauth_drop_signature_win_arm64
mov x9, x30
mov x30, x0
hint #7
mov x0, x30
mov x30, x9
ret
END
@@ -28,9 +28,10 @@
// OS specific Support for ROP Protection in VM code.
// For more details on PAC see pauth_aarch64.hpp.
extern "C" address pauth_drop_signature_win_arm64(address p);
inline address pauth_strip_pointer(address ptr) {
// No PAC support in windows as of yet.
return ptr;
return pauth_drop_signature_win_arm64(ptr);
}
inline address pauth_sign_return_address(address ret_addr) {
+3 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
#include "compiler/compilationMemoryStatistic.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compiler_globals.hpp"
#include "compiler/compilerDefinitions.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/compileTask.hpp"
#include "memory/resourceArea.hpp"
@@ -556,6 +557,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
, _directive(directive)
, _env(env)
, _log(env->log())
, _stress(_directive, _log, compiler_c1)
, _method(method)
, _osr_bci(osr_bci)
, _hir(nullptr)
+3
View File
@@ -31,6 +31,7 @@
#include "compiler/compiler_globals.hpp"
#include "compiler/compilerDefinitions.inline.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/stress.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -70,6 +71,7 @@ class Compilation: public StackObj {
DirectiveSet* _directive;
ciEnv* _env;
CompileLog* _log;
Stress _stress;
ciMethod* _method;
int _osr_bci;
IR* _hir;
@@ -138,6 +140,7 @@ class Compilation: public StackObj {
DirectiveSet* directive() const { return _directive; }
CompileLog* log() const { return _log; }
AbstractCompiler* compiler() const { return _compiler; }
Stress& stress() { return _stress; }
bool has_exception_handlers() const { return _has_exception_handlers; }
bool has_fpu_code() const { return _has_fpu_code; }
bool has_unsafe_access() const { return _has_unsafe_access; }
@@ -36,7 +36,7 @@
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
DEBUG_ONLY(InstanceKlass* _aot_init_class = nullptr;)
DEBUG_ONLY(InstanceKlass* _aot_init_test_class = nullptr;)
bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
@@ -65,10 +65,10 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
//
// Check that no user code is executed during the assembly phase. Otherwise the user
// code may introduce undesirable environment dependencies into the heap image.
// If any of these two flags are set, we allow user code to be executed
// If AOTInitTestClass is set, we allow user code to be executed
// in the assembly phase. Note that these flags are strictly for the purpose
// of testing HotSpot and are not available in product builds.
if (AOTInitTestClass == nullptr && ArchiveHeapTestClass == nullptr) {
if (AOTInitTestClass == nullptr) {
if (ik->defined_by_boot_loader()) {
// We allow boot classes to be AOT-initialized, except for classes from
// -Xbootclasspath (cp index >= 1) be AOT-initialized, as such classes may be
@@ -258,7 +258,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
}
#ifdef ASSERT
if (ik == _aot_init_class) {
if (ik == _aot_init_test_class) {
return true;
}
#endif
@@ -356,12 +356,12 @@ void AOTClassInitializer::init_test_class(TRAPS) {
vm_exit_during_initialization("Invalid name for AOTInitTestClass", AOTInitTestClass);
}
_aot_init_class = InstanceKlass::cast(k);
_aot_init_class->initialize(CHECK);
_aot_init_test_class = InstanceKlass::cast(k);
_aot_init_test_class->initialize(CHECK);
}
}
bool AOTClassInitializer::has_test_class() {
return _aot_init_class != nullptr;
return _aot_init_test_class != nullptr;
}
#endif
+73 -50
View File
@@ -98,6 +98,7 @@ public:
int current() const { return _current; }
bool is_empty() const { return _array.length() == 0; }
int size() const { return _array.length(); }
};
class BootCpClassLocationStream : public ClassLocationStream {
@@ -435,7 +436,7 @@ bool AOTClassLocation::check(const char* runtime_path, bool has_aot_linked_class
}
}
log_info(class, path)("ok");
log_info(class, path)("ok (file size and timestamp have not changed)");
return true;
}
@@ -633,7 +634,7 @@ void AOTClassLocationConfig::add_class_location(JavaThread* current, GrowableCla
// other via cpattr.
bool found_duplicate = false;
for (int i = boot_cp_start_index(); i < tmp_array.length(); i++) {
if (strcmp(tmp_array.at(i)->path(), libname) == 0) {
if (os::same_files(tmp_array.at(i)->path(), libname)) {
found_duplicate = true;
break;
}
@@ -760,7 +761,7 @@ bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_a
LogTarget(Info, class, path) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
ls.print("Checking %s classpath", which);
ls.print("Checking %s classpath from index [%d]", which, index_start);
ls.print_cr("%s", use_lcp_match ? " (with longest common prefix substitution)" : "");
ls.print("- expected : '");
print_dumptime_classpath(ls, index_start, index_end, use_lcp_match, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len);
@@ -832,68 +833,94 @@ bool AOTClassLocationConfig::check_paths_existence(ClassLocationStream& runtime_
return exist;
}
bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, int index_start, int index_end,
ClassLocationStream& runtime_css,
bool* has_extra_module_paths) const {
if (index_start >= index_end && runtime_css.is_empty()) { // nothing to check
return true;
}
bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, bool has_full_module_graph,
ModulePathClassLocationStream& runtime_module_css) const {
const int index_start = module_path_start_index();
const int index_end = module_path_end_index();
ResourceMark rm;
LogTarget(Info, class, path) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
ls.print_cr("Checking module paths");
ls.print_cr("Checking module paths from index [%d]", index_start);
ls.print("- expected : '");
print_dumptime_classpath(ls, index_start, index_end, false, 0, nullptr, 0);
ls.print_cr("'");
ls.print("- actual : '");
runtime_css.print(&ls);
runtime_module_css.print(&ls);
ls.print_cr("'");
}
// Make sure all the dumptime module paths exist and are unchanged
// All JAR files in the dumptime module paths must exist and must be unchanged,
// or else we have a "hard" failure, as we can no longer guarantee that archived
// classes from the module paths remain unchanged at runtime.
for (int i = index_start; i < index_end; i++) {
const AOTClassLocation* cs = class_location_at(i);
const char* dumptime_path = cs->path();
assert(!cs->from_cpattr(), "not applicable for module path");
log_info(class, path)("Checking '%s' %s", dumptime_path, cs->file_type_string());
log_info(class, path)("Checking [%d] '%s' %s", i, dumptime_path, cs->file_type_string());
if (!cs->check(dumptime_path, has_aot_linked_classes)) {
return false;
}
}
// We allow runtime_css to be a superset of the module paths specified in dumptime. E.g.,
// Dumptime: A:C
// Runtime: A:B:C
runtime_css.start();
for (int i = index_start; i < index_end; i++) {
const AOTClassLocation* cs = class_location_at(i);
const char* dumptime_path = cs->path();
while (true) {
if (!runtime_css.has_next()) {
aot_log_warning(aot)("module path has fewer elements than expected");
*has_extra_module_paths = true;
return true;
if (!check_module_paths_exact_match(runtime_module_css)) {
if (CDSConfig::new_aot_flags_used()) {
// New AOT workflow requires an exact match for --module-paths.
return false;
} else {
// For classical CDS, we have a "soft" failure if the runtime module paths are
// not an exact match with the dumptime module paths:
// Classes from the module path will not be loaded if they are
// rejected by SystemDictionary::is_shared_class_visible().
if (has_full_module_graph) {
CDSConfig::disable_full_module_graph();
AOTMetaspace::report_loading_error("full module graph: disabled because extra module path(s) are specified");
}
// Both this->class_locations() and runtime_css are alphabetically sorted. Skip
// items in runtime_css until we see dumptime_path.
const char* runtime_path = runtime_css.get_next();
if (!os::same_files(dumptime_path, runtime_path)) {
*has_extra_module_paths = true;
return true;
} else {
break;
if (CDSConfig::is_dumping_dynamic_archive() && num_module_paths() > 0) {
CDSConfig::disable_dumping_dynamic_archive();
aot_log_warning(aot)("Dynamic archiving is disabled because base layer archive has a different module path");
}
}
}
if (runtime_css.has_next()) {
*has_extra_module_paths = true;
return true;
}
bool AOTClassLocationConfig::check_module_paths_exact_match(ModulePathClassLocationStream& runtime_module_css) const {
if (runtime_module_css.has_non_jar_modules()) {
AOTMetaspace::report_loading_error("module path contains sub-directories or non-JAR files (incompatible with full module graph)");
return false;
}
const int index_start = module_path_start_index();
const int index_end = module_path_end_index();
runtime_module_css.start();
for (int i = index_start; i < index_end; i++) {
const AOTClassLocation* cs = class_location_at(i);
const char* dumptime_path = cs->path();
if (!runtime_module_css.has_next()) {
AOTMetaspace::report_loading_error("module path has fewer elements (%d) than expected (%d)", runtime_module_css.size(), num_module_paths());
return false;
}
const char* runtime_path = runtime_module_css.get_next();
// Both dumptime and runtime module paths are alphabetically sorted, so we just need to
// compare each element at the same position.
if (!os::same_files(dumptime_path, runtime_path)) {
AOTMetaspace::report_loading_error("module path at [%d] is different: expected %s actual %s",
i, dumptime_path, runtime_path);
return false;
}
}
if (runtime_module_css.has_next()) {
AOTMetaspace::report_loading_error("module path has more elements (%d) than expected (%d)", runtime_module_css.size(), num_module_paths());
return false;
}
return true;
@@ -967,12 +994,13 @@ bool AOTClassLocationConfig::need_lcp_match_helper(int start, int end, ClassLoca
return true;
}
bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_linked_classes, bool* has_extra_module_paths) const {
bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_linked_classes, bool has_full_module_graph) const {
ResourceMark rm;
AllClassLocationStreams all_css;
log_locations(cache_filename, /*is_write=*/false);
// (1) Check JRT modules image
const char* jrt = ClassLoader::get_jrt_entry()->name();
log_info(class, path)("Checking [0] (modules image)");
bool success = class_location_at(0)->check(jrt, has_aot_linked_classes);
@@ -980,13 +1008,9 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l
if (!success) {
return false;
}
if (class_locations()->length() == 1) {
if ((module_path_start_index() >= module_path_end_index()) && Arguments::get_property("jdk.module.path") != nullptr) {
*has_extra_module_paths = true;
} else {
*has_extra_module_paths = false;
}
} else {
{
// (2) Check boot/app classpath
bool use_lcp_match = need_lcp_match(all_css);
const char* runtime_lcp;
size_t runtime_lcp_len;
@@ -1011,11 +1035,10 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l
log_info(class, path)("Archived app classpath validation: %s", success ? "passed" : "failed");
}
// (3) Check module paths
if (success) {
success = check_module_paths(has_aot_linked_classes, module_path_start_index(), module_path_end_index(),
all_css.module_path(), has_extra_module_paths);
log_info(class, path)("Archived module path validation: %s%s", success ? "passed" : "failed",
(*has_extra_module_paths) ? " (extra module paths found)" : "");
success = check_module_paths(has_aot_linked_classes, has_full_module_graph, all_css.module_path());
log_info(class, path)("Archived module path validation: %s", success ? "passed" : "failed");
}
if (runtime_lcp_len > 0) {
@@ -1033,7 +1056,7 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l
if (CDSConfig::is_dumping_final_static_archive()) {
aot_log_error(aot)("class path and/or module path are not compatible with the "
"ones specified when the AOTConfiguration file was recorded%s", hint_msg);
vm_exit_during_initialization("Unable to use create AOT cache.", nullptr);
AOTMetaspace::unrecoverable_writing_error("Unable to use create AOT cache.");
} else {
aot_log_error(aot)("%s%s", mismatch_msg, hint_msg);
AOTMetaspace::unrecoverable_loading_error();
+5 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
class AllClassLocationStreams;
class ClassLocationStream;
class ClassPathZipEntry;
class ModulePathClassLocationStream;
class LogStream;
// An AOTClassLocation is a location where the application is configured to load Java classes
@@ -164,8 +165,8 @@ class AOTClassLocationConfig : public CHeapObj<mtClassShared> {
bool check_classpaths(bool is_boot_classpath, bool has_aot_linked_classes,
int index_start, int index_end, ClassLocationStream& runtime_css,
bool use_lcp_match, const char* runtime_lcp, size_t runtime_lcp_len) const;
bool check_module_paths(bool has_aot_linked_classes, int index_start, int index_end, ClassLocationStream& runtime_css,
bool* has_extra_module_paths) const;
bool check_module_paths(bool has_aot_linked_classes, bool has_full_module_graph, ModulePathClassLocationStream& runtime_module_css) const;
bool check_module_paths_exact_match(ModulePathClassLocationStream& runtime_module_css) const;
bool file_exists(const char* filename) const;
bool check_paths_existence(ClassLocationStream& runtime_css) const;
@@ -270,7 +271,7 @@ public:
AOTClassLocationConfig* write_to_archive() const;
// Functions used only during runtime
bool validate(const char* cache_filename, bool has_aot_linked_classes, bool* has_extra_module_paths) const;
bool validate(const char* cache_filename, bool has_aot_linked_classes, bool has_full_module_graph) const;
bool is_valid_classpath_index(int classpath_index, InstanceKlass* ik);
@@ -85,6 +85,9 @@ void AOTLinkedClassBulkLoader::preload_classes_impl(TRAPS) {
initiate_loading(THREAD, "app", h_system_loader, table->boot2());
initiate_loading(THREAD, "app", h_system_loader, table->platform());
preload_classes_in_table(table->app(), "app", h_system_loader, CHECK);
// Do this after all boot/platform/app classes are loaded, but before bytecode execution.
HeapShared::load_cached_resolved_methods();
}
void AOTLinkedClassBulkLoader::preload_classes_in_table(Array<InstanceKlass*>* classes,
+7 -5
View File
@@ -117,7 +117,6 @@ void* AOTMetaspace::_aot_metaspace_static_top = nullptr;
intx AOTMetaspace::_relocation_delta;
char* AOTMetaspace::_requested_base_address;
Array<Method*>* AOTMetaspace::_archived_method_handle_intrinsics = nullptr;
bool AOTMetaspace::_use_optimized_module_handling = true;
int volatile AOTMetaspace::_preimage_static_archive_dumped = 0;
FileMapInfo* AOTMetaspace::_output_mapinfo = nullptr;
@@ -1192,8 +1191,8 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS
AOTReferenceObjSupport::initialize(CHECK);
AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK);
} else {
log_info(aot)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling");
CDSConfig::stop_using_optimized_module_handling();
log_info(aot)("Not dumping heap, disable full module graph");
CDSConfig::disable_full_module_graph();
}
#endif
@@ -1467,6 +1466,7 @@ bool AOTMetaspace::in_aot_cache_static_region(void* p) {
// - There's an error that indicates that the archive(s) files were corrupt or otherwise damaged.
// - When -XX:+RequireSharedSpaces is specified, AND the JVM cannot load the archive(s) due
// to version or classpath mismatch.
[[noreturn]]
void AOTMetaspace::unrecoverable_loading_error(const char* message) {
report_loading_error("%s", message);
@@ -1477,6 +1477,7 @@ void AOTMetaspace::unrecoverable_loading_error(const char* message) {
} else {
vm_exit_during_initialization("Unable to use shared archive. Unrecoverable archive loading error (run with -Xlog:aot,cds for details)", message);
}
ShouldNotReachHere();
}
void AOTMetaspace::report_loading_error(const char* format, ...) {
@@ -1512,15 +1513,17 @@ void AOTMetaspace::report_loading_error(const char* format, ...) {
// This function is called when the JVM is unable to write the specified CDS archive due to an
// unrecoverable error.
[[noreturn]]
void AOTMetaspace::unrecoverable_writing_error(const char* message) {
writing_error(message);
vm_direct_exit(1);
ShouldNotReachHere();
}
// This function is called when the JVM is unable to write the specified CDS archive due to a
// an error. The error will be propagated
void AOTMetaspace::writing_error(const char* message) {
aot_log_error(aot)("An error has occurred while writing the shared archive file.");
aot_log_error(aot)("An error has occurred while writing the %s.", CDSConfig::type_of_archive_being_written());
if (message != nullptr) {
aot_log_error(aot)("%s", message);
}
@@ -1853,7 +1856,6 @@ MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMap
}
}
#endif // INCLUDE_CLASS_SPACE
log_info(aot)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
log_info(aot)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
} else {
unmap_archive(static_mapinfo);
+2 -7
View File
@@ -58,7 +58,6 @@ class AOTMetaspace : AllStatic {
static void* _aot_metaspace_static_top;
static intx _relocation_delta;
static char* _requested_base_address;
static bool _use_optimized_module_handling;
static Array<Method*>* _archived_method_handle_intrinsics;
static int volatile _preimage_static_archive_dumped;
static FileMapInfo* _output_mapinfo;
@@ -120,9 +119,9 @@ public:
static bool preimage_static_archive_dumped() NOT_CDS_RETURN_(false);
static void unrecoverable_loading_error(const char* message = "unrecoverable error");
[[noreturn]] static void unrecoverable_loading_error(const char* message = "unrecoverable error");
static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0);
static void unrecoverable_writing_error(const char* message = nullptr);
[[noreturn]] static void unrecoverable_writing_error(const char* message = nullptr);
static void writing_error(const char* message = nullptr);
static void make_method_handle_intrinsics_shareable() NOT_CDS_RETURN;
@@ -184,10 +183,6 @@ public:
return is_windows;
}
// Can we skip some expensive operations related to modules?
static bool use_optimized_module_handling() { return NOT_CDS(false) CDS_ONLY(_use_optimized_module_handling); }
static void disable_optimized_module_handling() { _use_optimized_module_handling = false; }
// Check if the supplied shared base address can be used as the encoding base.
static bool shared_base_valid(char* shared_base);
+20 -14
View File
@@ -48,7 +48,6 @@ bool CDSConfig::_is_dumping_static_archive = false;
bool CDSConfig::_is_dumping_preimage_static_archive = false;
bool CDSConfig::_is_dumping_final_static_archive = false;
bool CDSConfig::_is_dumping_dynamic_archive = false;
bool CDSConfig::_is_using_optimized_module_handling = true;
bool CDSConfig::_is_dumping_full_module_graph = true;
bool CDSConfig::_is_using_full_module_graph = true;
bool CDSConfig::_has_aot_linked_classes = false;
@@ -325,8 +324,8 @@ void CDSConfig::ergo_init_classic_archive_paths() {
void CDSConfig::check_internal_module_property(const char* key, const char* value) {
if (Arguments::is_incompatible_cds_internal_module_property(key)) {
stop_using_optimized_module_handling();
aot_log_info(aot)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
disable_full_module_graph();
aot_log_info(aot)("full mmodule graph: disabled due to incompatible property: %s=%s", key, value);
}
}
@@ -580,9 +579,8 @@ void CDSConfig::check_aotmode_record() {
_is_dumping_static_archive = true;
_is_dumping_preimage_static_archive = true;
// At VM exit, the module graph may be contaminated with program states.
// At the end of the training run, the module graph may be contaminated with program states.
// We will rebuild the module graph when dumping the CDS final image.
_is_using_optimized_module_handling = false;
_is_using_full_module_graph = false;
_is_dumping_full_module_graph = false;
}
@@ -769,11 +767,20 @@ void CDSConfig::setup_compiler_args() {
void CDSConfig::prepare_for_dumping() {
assert(CDSConfig::is_dumping_archive(), "sanity");
if (is_dumping_classic_static_archive() && AOTClassLinking) {
if (FLAG_IS_CMDLINE(AOTClassLinking)) {
log_warning(cds)("AOTClassLinking is not supported for classic CDS archive");
}
FLAG_SET_ERGO(AOTClassLinking, false);
FLAG_SET_ERGO(AOTInvokeDynamicLinking, false);
}
if (is_dumping_dynamic_archive() && AOTClassLinking) {
if (FLAG_IS_CMDLINE(AOTClassLinking)) {
log_warning(cds)("AOTClassLinking is not supported for dynamic CDS archive");
}
FLAG_SET_ERGO(AOTClassLinking, false);
FLAG_SET_ERGO(AOTInvokeDynamicLinking, false);
}
if (is_dumping_dynamic_archive() && !is_using_archive()) {
@@ -863,13 +870,6 @@ bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
}
}
void CDSConfig::stop_using_optimized_module_handling() {
_is_using_optimized_module_handling = false;
_is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling()
_is_using_full_module_graph = false; // This requires is_using_optimized_module_handling()
}
CDSConfig::DumperThreadMark::DumperThreadMark(JavaThread* current) {
assert(_dumper_thread == nullptr, "sanity");
_dumper_thread = current;
@@ -958,7 +958,7 @@ bool CDSConfig::is_preserving_verification_constraints() {
} else if (is_dumping_final_static_archive()) { // writing AOT cache
return is_dumping_aot_linked_classes();
} else if (is_dumping_classic_static_archive()) {
return is_dumping_aot_linked_classes();
return false;
} else {
return false;
}
@@ -1018,6 +1018,12 @@ bool CDSConfig::is_using_klass_subgraphs() {
!CDSConfig::is_dumping_final_static_archive());
}
// Prevent the JVM from dumping or using the archived full module graph
void CDSConfig::disable_full_module_graph() {
_is_dumping_full_module_graph = false;
_is_using_full_module_graph = false;
}
bool CDSConfig::is_using_full_module_graph() {
if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
return true;
@@ -1058,7 +1064,7 @@ void CDSConfig::stop_using_full_module_graph(const char* reason) {
}
bool CDSConfig::is_dumping_aot_linked_classes() {
if (is_dumping_classic_static_archive() || is_dumping_final_static_archive()) {
if (is_dumping_final_static_archive()) {
// FMG is required to guarantee that all cached boot/platform/app classes
// are visible in the production run, so they can be unconditionally
// loaded during VM bootstrap.
+2 -6
View File
@@ -38,7 +38,6 @@ class CDSConfig : public AllStatic {
static bool _is_dumping_preimage_static_archive;
static bool _is_dumping_final_static_archive;
static bool _is_dumping_dynamic_archive;
static bool _is_using_optimized_module_handling;
static bool _is_dumping_full_module_graph;
static bool _is_using_full_module_graph;
static bool _has_aot_linked_classes;
@@ -156,10 +155,6 @@ public:
// This is *Legacy* optimization for lambdas before JEP 483. May be removed in the future.
static bool is_dumping_lambdas_in_legacy_mode() NOT_CDS_RETURN_(false);
// optimized_module_handling -- can we skip some expensive operations related to modules?
static bool is_using_optimized_module_handling() { return CDS_ONLY(_is_using_optimized_module_handling) NOT_CDS(false); }
static void stop_using_optimized_module_handling() NOT_CDS_RETURN;
static bool is_logging_lambda_form_invokers() NOT_CDS_RETURN_(false);
static bool is_dumping_regenerated_lambdaform_invokers() NOT_CDS_RETURN_(false);
@@ -194,9 +189,10 @@ public:
static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false);
// full_module_graph (requires optimized_module_handling)
// full_module_graph (jdk.internal.module.ArchivedBootLayer::archivedBootLayer)
static bool is_dumping_full_module_graph() { return CDS_ONLY(_is_dumping_full_module_graph) NOT_CDS(false); }
static bool is_using_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
static void disable_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN;
static void stop_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
static void stop_using_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
+1 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,11 +65,6 @@
"Average number of symbols per bucket in shared table") \
range(2, 246) \
\
develop(ccstr, ArchiveHeapTestClass, nullptr, \
"For JVM internal testing only. The static field named " \
"\"archivedObjects\" of the specified class is stored in the " \
"CDS archive heap") \
\
develop(ccstr, AOTInitTestClass, nullptr, \
"For JVM internal testing only. The specified class is stored " \
"in the initialized state in the AOT cache ") \
+2
View File
@@ -66,9 +66,11 @@
// the virtual printing functions in AnyObj).
using GrowableArray_ModuleEntry_ptr = GrowableArray<ModuleEntry*>;
using GrowableArray_SigEntry = GrowableArray<SigEntry>;
#define DEBUG_CPP_VTABLE_TYPES_DO(f) \
f(GrowableArray_ModuleEntry_ptr) \
f(GrowableArray_SigEntry) \
#endif
+9 -21
View File
@@ -311,7 +311,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_type_profile_casts = TypeProfileCasts;
_spec_trap_limit_extra_entries = SpecTrapLimitExtraEntries;
_max_heap_size = MaxHeapSize;
_use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
_aot_class_linking_value = AOTClassLinking;
_has_aot_linked_classes = CDSConfig::is_dumping_aot_linked_classes();
_has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
@@ -396,7 +395,6 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- _rw_ptrmap_start_pos: %zu", _rw_ptrmap_start_pos);
st->print_cr("- _ro_ptrmap_start_pos: %zu", _ro_ptrmap_start_pos);
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
st->print_cr("- has_valhalla_patched_classes %d", _has_valhalla_patched_classes);
_must_match.print(st);
@@ -407,8 +405,8 @@ bool FileMapInfo::validate_class_location() {
assert(CDSConfig::is_using_archive(), "runtime only");
AOTClassLocationConfig* config = header()->class_location_config();
bool has_extra_module_paths = false;
if (!config->validate(full_path(), header()->has_aot_linked_classes(), &has_extra_module_paths)) {
if (!config->validate(full_path(), header()->has_aot_linked_classes(), header()->has_full_module_graph())) {
if (PrintSharedArchiveAndExit) {
AOTMetaspace::set_archive_loading_failed();
return true;
@@ -417,11 +415,6 @@ bool FileMapInfo::validate_class_location() {
}
}
if (header()->has_full_module_graph() && has_extra_module_paths) {
CDSConfig::stop_using_optimized_module_handling();
AOTMetaspace::report_loading_error("optimized module handling: disabled because extra module path(s) are specified");
}
if (CDSConfig::is_dumping_dynamic_archive()) {
// Only support dynamic dumping with the usage of the default CDS archive
// or a simple base archive.
@@ -432,13 +425,6 @@ bool FileMapInfo::validate_class_location() {
aot_log_warning(aot)(
"Dynamic archiving is disabled because base layer archive has appended boot classpath");
}
if (config->num_module_paths() > 0) {
if (has_extra_module_paths) {
CDSConfig::disable_dumping_dynamic_archive();
aot_log_warning(aot)(
"Dynamic archiving is disabled because base layer archive has a different module path");
}
}
}
#if INCLUDE_JVMTI
@@ -1872,6 +1858,13 @@ bool FileMapInfo::validate_aot_class_linking() {
#endif
}
if (CDSConfig::is_dumping_final_static_archive() && header()->aot_class_linking_value() && !CDSConfig::is_dumping_aot_linked_classes()) {
ResourceMark rm;
const char* msg = err_msg("AOT class linking was enabled in training run but has been disabled%s",
(CDSConfig::is_dumping_full_module_graph() ? "" : " due to incompatible module options"));
AOTMetaspace::unrecoverable_writing_error(msg);
}
return true;
}
@@ -2056,11 +2049,6 @@ bool FileMapHeader::validate() {
return false;
}
if (!_use_optimized_module_handling && !CDSConfig::is_dumping_final_static_archive()) {
CDSConfig::stop_using_optimized_module_handling();
aot_log_info(aot)("optimized module handling: disabled because archive was created without optimized module handling");
}
if (is_static()) {
// Only the static archive can contain the full module graph.
if (!_has_full_module_graph) {
-3
View File
@@ -173,9 +173,6 @@ private:
bool _has_platform_or_app_classes; // Archive contains app or platform classes
char* _requested_base_address; // Archive relocation is not necessary if we map with this base address.
char* _mapped_base_address; // Actual base address where archive is mapped.
bool _use_optimized_module_handling;// No module-relation VM options were specified, so we can skip
// some expensive operations.
bool _has_aot_linked_classes; // Was the CDS archive created with -XX:+AOTClassLinking
bool _aot_class_linking_value; // The value of the AOTClassLinking variable when this archive was created
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
+58 -181
View File
@@ -35,7 +35,7 @@
#include "cds/aotStreamedHeapLoader.hpp"
#include "cds/aotStreamedHeapWriter.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveUtils.hpp"
#include "cds/archiveUtils.inline.hpp"
#include "cds/cds_globals.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/cdsEnumKlass.hpp"
@@ -67,6 +67,7 @@
#include "oops/oopHandle.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/resolvedMethodTable.hpp"
#include "runtime/arguments.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/globals_extension.hpp"
@@ -105,14 +106,6 @@ size_t HeapShared::_alloc_size[HeapShared::ALLOC_STAT_SLOTS];
size_t HeapShared::_total_obj_count;
size_t HeapShared::_total_obj_size;
#ifndef PRODUCT
#define ARCHIVE_TEST_FIELD_NAME "archivedObjects"
static Array<char>* _archived_ArchiveHeapTestClass = nullptr;
static const char* _test_class_name = nullptr;
static Klass* _test_class = nullptr;
static const ArchivedKlassSubGraphInfoRecord* _test_class_record = nullptr;
#endif
#ifdef ASSERT
// All classes that have at least one instance in the cached heap.
static ArchivableKlassTable* _dumptime_classes_with_cached_oops = nullptr;
@@ -142,9 +135,6 @@ static ArchivableStaticFieldInfo archive_subgraph_entry_fields[] = {
{ARCHIVED_BOOT_LAYER_CLASS, ARCHIVED_BOOT_LAYER_FIELD},
{"java/lang/Module$ArchivedData", "archivedData"},
#ifndef PRODUCT
{nullptr, nullptr}, // Extra slot for -XX:ArchiveHeapTestClass
#endif
{nullptr, nullptr},
};
@@ -153,6 +143,8 @@ ArchivedKlassSubGraphInfoRecord* HeapShared::_run_time_special_subgraph;
GrowableArrayCHeap<oop, mtClassShared>* HeapShared::_pending_roots = nullptr;
OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1];
MetaspaceObjToOopHandleTable* HeapShared::_scratch_objects_table = nullptr;
static GrowableArray<int>* _dumptime_resolved_methods = nullptr;
static Array<int>* _runtime_resolved_methods = nullptr;
static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], InstanceKlass* ik) {
for (int i = 0; fields[i].valid(); i++) {
@@ -651,6 +643,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra
m = RegeneratedClasses::maybe_get_regenerated_object(m);
InstanceKlass* method_holder = m->method_holder();
AOTArtifactFinder::add_cached_class(method_holder);
_dumptime_resolved_methods->append(HeapShared::append_root(obj));
}
}
}
@@ -723,6 +716,7 @@ void HeapShared::remove_scratch_resolved_references(ConstantPool* src) {
void HeapShared::init_dumping() {
_scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable();
_dumptime_resolved_methods = new (mtClassShared) GrowableArray<int>(100, mtClassShared);
_pending_roots = new GrowableArrayCHeap<oop, mtClassShared>(500);
_pending_roots->append(nullptr); // root index 0 represents a null oop
DEBUG_ONLY(_dumptime_classes_with_cached_oops = new (mtClassShared)ArchivableKlassTable());
@@ -823,6 +817,7 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
oop orig_mirror;
if (RegeneratedClasses::is_regenerated_object(ik)) {
assert(!ik->is_inline_klass(), "not supported");
InstanceKlass* orig_ik = RegeneratedClasses::get_original_object(ik);
precond(orig_ik->is_initialized());
orig_mirror = orig_ik->java_mirror();
@@ -892,6 +887,16 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
assert(success, "sanity");
}
if (ik->is_inline_klass()) {
InlineKlass* ilk = InlineKlass::cast(ik);
if (ilk->supports_nullable_layouts()) {
oop null_reset_value = ilk->null_reset_value();
m->obj_field_put(ilk->null_reset_value_offset(), null_reset_value);
bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, null_reset_value);
assert(success, "sanity");
}
}
if (log_is_enabled(Debug, aot, init)) {
ResourceMark rm;
log_debug(aot, init)("copied %3d field(s) in aot-initialized mirror %s%s%s", nfields, ik->external_name(),
@@ -922,14 +927,6 @@ void HeapShared::copy_java_mirror(oop orig_mirror, oop scratch_m) {
if (k != nullptr && k->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->is_inline_klass() && ik->is_initialized()) {
// Only concrete value classes need the null_reset field
InlineKlass* ilk = InlineKlass::cast(k);
if (ilk->supports_nullable_layouts()) {
scratch_m->obj_field_put(ilk->null_reset_value_offset(), ilk->null_reset_value());
}
}
if (ik->has_acmp_maps_offset()) {
int maps_offset = ik->acmp_maps_offset();
oop maps = orig_mirror->obj_field(maps_offset);
@@ -1032,6 +1029,10 @@ void HeapShared::write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeap
delete _pending_roots;
_pending_roots = nullptr;
_runtime_resolved_methods = ArchiveUtils::archive_array(_dumptime_resolved_methods);
delete _dumptime_resolved_methods;
_dumptime_resolved_methods = nullptr;
make_archived_object_cache_gc_safe();
}
@@ -1144,8 +1145,13 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
} else if (orig_k->is_objArray_klass()) {
Klass* abk = ObjArrayKlass::cast(orig_k)->bottom_klass();
if (abk->is_instance_klass()) {
assert(InstanceKlass::cast(abk)->defined_by_boot_loader(),
"must be boot class");
if (!AOTClassInitializer::has_test_class()) {
// Without `-XX:AOTInitTestClass`, no Java code outside of the boot loader will
// be executed in the AOT assembly phase, so we can't have an initialized class
// outside of the boot loader.
assert(InstanceKlass::cast(abk)->defined_by_boot_loader(),
"must be boot class");
}
check_allowed_klass(InstanceKlass::cast(ObjArrayKlass::cast(orig_k)->bottom_klass()));
}
if (orig_k == Universe::objectArrayKlass()) {
@@ -1196,19 +1202,9 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) {
}
}
#ifndef PRODUCT
if (!ik->module()->is_named() && ik->package() == nullptr && ArchiveHeapTestClass != nullptr) {
// This class is loaded by ArchiveHeapTestClass
return;
}
const char* testcls_msg = ", or a test class in an unnamed package of an unnamed module";
#else
const char* testcls_msg = "";
#endif
ResourceMark rm;
log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s%s",
ik->external_name(), lambda_msg, testcls_msg);
log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s",
ik->external_name(), lambda_msg);
AOTMetaspace::unrecoverable_writing_error();
}
@@ -1318,34 +1314,35 @@ void HeapShared::write_subgraph_info_table() {
d_table->iterate(&copy);
writer.dump(&_run_time_subgraph_info_table, "subgraphs");
#ifndef PRODUCT
if (ArchiveHeapTestClass != nullptr) {
size_t len = strlen(ArchiveHeapTestClass) + 1;
Array<char>* array = ArchiveBuilder::new_ro_array<char>((int)len);
strncpy(array->adr_at(0), ArchiveHeapTestClass, len);
_archived_ArchiveHeapTestClass = array;
}
#endif
if (log_is_enabled(Info, aot, heap)) {
print_stats();
}
}
void HeapShared::serialize_tables(SerializeClosure* soc) {
#ifndef PRODUCT
soc->do_ptr(&_archived_ArchiveHeapTestClass);
if (soc->reading() && _archived_ArchiveHeapTestClass != nullptr) {
_test_class_name = _archived_ArchiveHeapTestClass->adr_at(0);
setup_test_class(_test_class_name);
}
#endif
_run_time_subgraph_info_table.serialize_header(soc);
soc->do_ptr(&_run_time_special_subgraph);
soc->do_ptr(&_runtime_resolved_methods);
DEBUG_ONLY(soc->do_ptr(&_runtime_classes_with_cached_oops));
}
void HeapShared::load_cached_resolved_methods() {
precond(CDSConfig::is_using_aot_linked_classes());
if (_runtime_resolved_methods != nullptr) {
JavaThread* current = JavaThread::current();
HandleMark hm(current);
for (int i = 0; i < _runtime_resolved_methods->length(); i++) {
int root_index = _runtime_resolved_methods->at(i);
Handle mem_name(current, get_root(root_index, /*clear=*/true));
Method* method = java_lang_invoke_ResolvedMethodName::vmtarget(mem_name());
InstanceKlass* holder = method->method_holder();
holder->set_has_resolved_methods();
oop o = ResolvedMethodTable::add_method(method, mem_name);
precond(o == mem_name());
}
}
}
static void verify_the_heap(Klass* k, const char* which) {
if (VerifyArchivedFields > 0) {
ResourceMark rm;
@@ -1471,13 +1468,13 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k
}
if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") &&
!CDSConfig::is_using_optimized_module_handling() &&
!CDSConfig::is_using_full_module_graph() &&
// archive was created with --module-path
AOTClassLocationConfig::runtime()->num_module_paths() > 0) {
// ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path.
// Thus, it might contain references to modules that do not exist at runtime. We cannot use it.
log_info(aot, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d",
BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()),
log_info(aot, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_full_module_graph=%s num_module_paths=%d",
BOOL_TO_STR(CDSConfig::is_using_full_module_graph()),
AOTClassLocationConfig::runtime()->num_module_paths());
return;
}
@@ -1509,13 +1506,6 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(k);
const ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
#ifndef PRODUCT
if (_test_class_name != nullptr && k->name()->equals(_test_class_name) && record != nullptr) {
_test_class = k;
_test_class_record = record;
}
#endif
// Initialize from archived data. Currently this is done only
// during VM initialization time. No lock is needed.
if (record == nullptr) {
@@ -2140,18 +2130,6 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
ResourceMark rm; // for stringStream::as_string() etc.
#ifndef PRODUCT
bool is_test_class = (ArchiveHeapTestClass != nullptr) && (strcmp(info->klass_name, ArchiveHeapTestClass) == 0);
const char* test_class_name = ArchiveHeapTestClass;
#else
bool is_test_class = false;
const char* test_class_name = ""; // avoid C++ printf checks warnings.
#endif
if (is_test_class) {
log_warning(aot)("Loading ArchiveHeapTestClass %s ...", test_class_name);
}
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
@@ -2170,35 +2148,15 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
assert(InstanceKlass::cast(ik)->defined_by_boot_loader(),
"Only support boot classes");
if (is_test_class) {
if (ik->module()->is_named()) {
// We don't want ArchiveHeapTestClass to be abused to easily load/initialize arbitrary
// core-lib classes. You need to at least append to the bootclasspath.
stringStream st;
st.print("ArchiveHeapTestClass %s is not in unnamed module", test_class_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
}
if (ik->package() != nullptr) {
// This restriction makes HeapShared::is_a_test_class_in_unnamed_module() easy.
stringStream st;
st.print("ArchiveHeapTestClass %s is not in unnamed package", test_class_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
}
} else {
if (ik->module()->name() != vmSymbols::java_base()) {
// We don't want to deal with cases when a module is unavailable at runtime.
// FUTURE -- load from archived heap only when module graph has not changed
// between dump and runtime.
stringStream st;
st.print("%s is not in java.base module", info->klass_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
}
if (ik->module()->name() != vmSymbols::java_base()) {
// We don't want to deal with cases when a module is unavailable at runtime.
// FUTURE -- load from archived heap only when module graph has not changed
// between dump and runtime.
stringStream st;
st.print("%s is not in java.base module", info->klass_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
}
if (is_test_class) {
log_warning(aot)("Initializing ArchiveHeapTestClass %s ...", test_class_name);
}
ik->initialize(CHECK);
ArchivableStaticFieldFinder finder(ik, field_name);
@@ -2222,89 +2180,8 @@ void HeapShared::init_subgraph_entry_fields(TRAPS) {
}
}
#ifndef PRODUCT
void HeapShared::setup_test_class(const char* test_class_name) {
ArchivableStaticFieldInfo* p = archive_subgraph_entry_fields;
int num_slots = sizeof(archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
assert(p[num_slots - 2].klass_name == nullptr, "must have empty slot that's patched below");
assert(p[num_slots - 1].klass_name == nullptr, "must have empty slot that marks the end of the list");
if (test_class_name != nullptr) {
p[num_slots - 2].klass_name = test_class_name;
p[num_slots - 2].field_name = ARCHIVE_TEST_FIELD_NAME;
}
}
// See if ik is one of the test classes that are pulled in by -XX:ArchiveHeapTestClass
// during runtime. This may be called before the module system is initialized so
// we cannot rely on InstanceKlass::module(), etc.
bool HeapShared::is_a_test_class_in_unnamed_module(Klass* ik) {
if (_test_class != nullptr) {
if (ik == _test_class) {
return true;
}
Array<Klass*>* klasses = _test_class_record->subgraph_object_klasses();
if (klasses == nullptr) {
return false;
}
for (int i = 0; i < klasses->length(); i++) {
Klass* k = klasses->at(i);
if (k == ik) {
Symbol* name;
if (k->is_instance_klass()) {
name = InstanceKlass::cast(k)->name();
} else if (k->is_objArray_klass()) {
Klass* bk = ObjArrayKlass::cast(k)->bottom_klass();
if (!bk->is_instance_klass()) {
return false;
}
name = bk->name();
} else {
return false;
}
// See KlassSubGraphInfo::check_allowed_klass() - we only allow test classes
// to be:
// (A) java.base classes (which must not be in the unnamed module)
// (B) test classes which must be in the unnamed package of the unnamed module.
// So if we see a '/' character in the class name, it must be in (A);
// otherwise it must be in (B).
if (name->index_of_at(0, "/", 1) >= 0) {
return false; // (A)
}
return true; // (B)
}
}
}
return false;
}
void HeapShared::initialize_test_class_from_archive(JavaThread* current) {
Klass* k = _test_class;
if (k != nullptr && is_archived_heap_in_use()) {
JavaThread* THREAD = current;
ExceptionMark em(THREAD);
const ArchivedKlassSubGraphInfoRecord* record =
resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/false, THREAD);
// The _test_class is in the unnamed module, so it can't call CDS.initializeFromArchive()
// from its <clinit> method. So we set up its "archivedObjects" field first, before
// calling its <clinit>. This is not strictly clean, but it's a convenient way to write unit
// test cases (see test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java).
if (record != nullptr) {
init_archived_fields_for(k, record);
}
resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/true, THREAD);
}
}
#endif
void HeapShared::init_for_dumping(TRAPS) {
if (CDSConfig::is_dumping_heap()) {
setup_test_class(ArchiveHeapTestClass);
init_subgraph_entry_fields(CHECK);
}
}
+1 -6
View File
@@ -442,7 +442,6 @@ private:
// Run-time only
static void clear_root(int index);
static void get_segment_indexes(int index, int& segment_index, int& internal_index);
static void setup_test_class(const char* test_class_name) PRODUCT_RETURN;
#endif // INCLUDE_CDS_JAVA_HEAP
public:
@@ -468,11 +467,7 @@ private:
static void init_heap_writer() NOT_CDS_JAVA_HEAP_RETURN;
static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
#ifndef PRODUCT
static bool is_a_test_class_in_unnamed_module(Klass* ik) NOT_CDS_JAVA_HEAP_RETURN_(false);
static void initialize_test_class_from_archive(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
#endif
static void load_cached_resolved_methods() NOT_CDS_JAVA_HEAP_RETURN;
static void initialize_java_lang_invoke(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void init_classes_for_special_subgraph(Handle loader, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
+7
View File
@@ -235,6 +235,13 @@ ciConstant ciInstance::field_value_by_offset(int field_offset) {
return field_value(field);
}
intptr_t ciInstance::hash() const {
VM_ENTRY_MARK;
oop obj = get_oop();
markWord mark = obj->mark();
if (mark.is_marked()) return markWord::no_hash;
return mark.hash();
}
// ------------------------------------------------------------------
// ciInstance::print_impl
//
+2
View File
@@ -67,6 +67,8 @@ public:
// Constant value of a field at the specified offset.
ciConstant field_value_by_offset(int field_offset);
intptr_t hash() const;
ciKlass* java_lang_Class_klass();
char* java_lang_String_str(char* buf, size_t buflen);
};
+22
View File
@@ -698,6 +698,28 @@ bool ciInstanceKlass::has_object_fields() const {
);
}
int ciInstanceKlass::number_of_nonoop_entries_in_acmp_map() const {
VM_ENTRY_MARK;
return get_instanceKlass()->acmp_maps_array()->at(0);
}
int ciInstanceKlass::number_of_oop_entries_in_acmp_map() const {
VM_ENTRY_MARK;
const Array<int>* acmp_maps = get_instanceKlass()->acmp_maps_array();
int number_of_nonoop_entries = acmp_maps->at(0);
return acmp_maps->length() - number_of_nonoop_entries * 2 - 1;
}
AcmpMapSegment ciInstanceKlass::get_nonoop_segment_of_acmp_map(int i) const {
VM_ENTRY_MARK;
const Array<int>* acmp_maps = get_instanceKlass()->acmp_maps_array();
#ifdef ASSERT
int number_of_nonoop_entries = acmp_maps->at(0);
assert(0 <= i && i < number_of_nonoop_entries, "illegal index, should be in range [0, %d)", number_of_nonoop_entries);
#endif
int offset = acmp_maps->at(2 * i + 1);
int size = acmp_maps->at(2 * i + 2);
return AcmpMapSegment(offset, size);
}
bool ciInstanceKlass::compute_has_trusted_loader() {
ASSERT_IN_VM;
oop loader_oop = loader();
+5
View File
@@ -29,6 +29,7 @@
#include "ci/ciFlags.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciSymbol.hpp"
#include "classfile/classFileParser.hpp"
#include "oops/instanceKlass.hpp"
// ciInstanceKlass
@@ -262,6 +263,10 @@ public:
return _nonstatic_fields->at(i);
}
int number_of_oop_entries_in_acmp_map() const;
int number_of_nonoop_entries_in_acmp_map() const;
AcmpMapSegment get_nonoop_segment_of_acmp_map(int i) const;
ciInstanceKlass* unique_concrete_subklass();
bool has_finalizable_subclass();
@@ -5483,6 +5483,34 @@ void ClassFileParser::set_fast_acmp_members(InlineKlass* vk) const {
#endif // VM_LITTLE_ENDIAN
}
// See the declarations of _fast_hashcode_offset and _fast_hashcode_shift in InlineKlass::Members
// for details about the fast path logic, and the meaning of these values.
void ClassFileParser::set_fast_hashcode_members(InlineKlass* vk) const {
if (_layout_info->_oop_acmp_map->length() > 0) { // Oops are not allowed in the fast path
return;
}
if (_layout_info->_nonoop_acmp_map->length() >= 2) { // We handle at most one segment...
return;
}
if (_layout_info->_nonoop_acmp_map->length() == 0) {
vk->set_fast_hashcode_offset(0);
vk->set_fast_hashcode_shift(0);
return;
}
assert(_layout_info->_nonoop_acmp_map->length() == 1, "trivially");
int piece_size = _layout_info->_nonoop_acmp_map->at(0)._size;
if (piece_size != 1 && piece_size != 2 && piece_size != 4 && piece_size != 8) { // ...and it must have a convenient size
return;
}
int piece_start = _layout_info->_nonoop_acmp_map->at(0)._offset;
vk->set_fast_hashcode_offset(piece_start - (BytesPerLong - piece_size));
vk->set_fast_hashcode_shift(BitsPerByte * (BytesPerLong - piece_size));
}
void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
bool changed_by_loadhook,
const ClassInstanceInfo& cl_inst_info,
@@ -5722,6 +5750,10 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
set_fast_acmp_members(vk);
}
if (UseHashcodeFastPath) {
set_fast_hashcode_members(vk);
}
vk->initialize_calling_convention(CHECK);
}
@@ -543,6 +543,7 @@ class ClassFileParser {
void create_acmp_maps(InstanceKlass* ik, TRAPS);
void set_fast_acmp_members(InlineKlass* vk) const;
void set_fast_hashcode_members(InlineKlass* vk) const;
public:
ClassFileParser(ClassFileStream* stream,
+1 -12
View File
@@ -617,18 +617,7 @@ void ModuleEntryTable::patch_javabase_entries(JavaThread* current, Handle module
for (int i = 0; i < list_length; i++) {
Klass* k = list->at(i);
assert(k->is_klass(), "List should only hold classes");
#ifndef PRODUCT
if (HeapShared::is_a_test_class_in_unnamed_module(k)) {
// We allow -XX:ArchiveHeapTestClass to archive additional classes
// into the CDS heap, but these must be in the unnamed module.
ModuleEntry* unnamed_module = ClassLoaderData::the_null_class_loader_data()->unnamed_module();
Handle unnamed_module_handle(current, unnamed_module->module_oop());
java_lang_Class::fixup_module_field(k, unnamed_module_handle);
} else
#endif
{
java_lang_Class::fixup_module_field(k, module_handle);
}
java_lang_Class::fixup_module_field(k, module_handle);
k->class_loader_data()->dec_keep_alive_ref_count();
}
+46 -17
View File
@@ -587,29 +587,59 @@ Modules::ArchivedProperty& Modules::archived_prop(size_t i) {
void Modules::ArchivedProperty::runtime_check() const {
ResourceMark rm;
const char* runtime_value = get_flattened_value();
const char* old_value = _archived_value;
const char* new_value = get_flattened_value();
aot_log_info(aot)("archived module property %s: %s", _prop,
_archived_value != nullptr ? _archived_value : "(null)");
old_value != nullptr ? old_value : "(null)");
bool disable = false;
if (runtime_value == nullptr) {
if (_archived_value != nullptr) {
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value);
disable = true;
bool mismatch = false;
const char* old_label1;
const char* old_label2;
const char* new_label1;
const char* new_label2;
if (CDSConfig::is_dumping_final_static_archive()) {
old_label1 = "in AOTConfiguration";
old_label2 = ", AOTConfiguration =";
new_label1 = "for current JVM";
new_label2 = "current =";
} else if (CDSConfig::new_aot_flags_used()) {
old_label1 = "in AOTCache";
old_label2 = ", AOTCache =";
new_label1 = "for current JVM";
new_label2 = "current =";
} else {
old_label1 = "during dump time";
old_label2 = " dump time";
new_label1 = "during runtime";
new_label2 = "runtime";
}
if (new_value == nullptr) {
if (old_value != nullptr) {
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified %s but not %s",
_prop, old_value, old_label1, new_label1);
mismatch = true;
}
} else {
if (_archived_value == nullptr) {
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value);
disable = true;
} else if (strcmp(runtime_value, _archived_value) != 0) {
AOTMetaspace::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value);
disable = true;
if (old_value == nullptr) {
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified %s but not %s",
_prop, new_value, new_label1, old_label1);
mismatch = true;
} else if (strcmp(new_value, old_value) != 0) {
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s %s%s %s",
_prop, new_label2, new_value, old_label2, old_value);
mismatch = true;
}
}
if (disable) {
AOTMetaspace::report_loading_error("Disabling optimized module handling");
CDSConfig::stop_using_optimized_module_handling();
if (mismatch) {
AOTMetaspace::report_loading_error("Disabling full module graph");
CDSConfig::disable_full_module_graph();
if (CDSConfig::is_dumping_final_static_archive()) {
AOTMetaspace::unrecoverable_writing_error("mismatched module options");
}
}
}
@@ -686,7 +716,6 @@ void Modules::serialize_archived_module_info(SerializeClosure* soc) {
archived_prop(i).serialize(soc);
}
if (soc->reading()) {
aot_log_info(aot)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
aot_log_info(aot)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
}
}
@@ -293,6 +293,11 @@ class StackMapFrame : public ResourceObj {
"Operand stack overflow");
return;
}
if (type.is_uninitialized_this()) {
_flags |= FLAG_THIS_UNINIT;
}
_stack[_stack_size++] = type;
}
+35 -13
View File
@@ -181,6 +181,15 @@ StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream,
// There's no stackmap table present. Frame count and size are 0.
_frame_count = 0;
}
VerificationType* locals = init_frame->locals();
_uninit_in_prev_frame_locals = false;
for (int i = 0; i < init_frame->locals_size(); i++) {
if (locals[i].is_uninitialized_this()) {
_uninit_in_prev_frame_locals = true;
break;
}
}
}
int32_t StackMapReader::chop(
@@ -200,7 +209,8 @@ int32_t StackMapReader::chop(
#define CHECK_NT CHECK_(VerificationType::bogus_type())
VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) {
VerificationType StackMapReader::parse_verification_type(u1* flags, bool parsing_locals, TRAPS) {
assert(flags != nullptr, "must be initialized");
u1 tag = _stream->get_u1(CHECK_NT);
if (tag < (u1)ITEM_UninitializedThis) {
return VerificationType::from_tag(tag);
@@ -218,8 +228,12 @@ VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) {
return VerificationType::reference_type(klass_name);
}
if (tag == ITEM_UninitializedThis) {
if (flags != nullptr) {
*flags |= FLAG_THIS_UNINIT;
*flags |= FLAG_THIS_UNINIT;
// An uninitializedThis in the locals array can sometimes be preserved
// between frames while uninitializedThis in the stack cannot as the stack
// is cleared. Chop and Full frames need special handling.
if (parsing_locals) {
_uninit_in_prev_frame_locals = true;
}
return VerificationType::uninitialized_this_type();
}
@@ -326,8 +340,11 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
offset = _prev_frame->offset() + frame_type + 1;
locals = _prev_frame->locals();
}
u1 flags = (u1)_uninit_in_prev_frame_locals;
frame = new StackMapFrame(
offset, _prev_frame->flags(), _prev_frame->locals_size(), 0,
offset, flags, _prev_frame->locals_size(), 0,
_max_locals, _max_stack, locals, nullptr,
_assert_unset_fields_buffer, _verifier);
if (_first && locals != nullptr) {
@@ -352,7 +369,8 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, VerificationType, 2);
u2 stack_size = 1;
stack[0] = parse_verification_type(nullptr, CHECK_VERIFY_(_verifier, nullptr));
u1 flags = _uninit_in_prev_frame_locals;
stack[0] = parse_verification_type(&flags, false /*parsing_locals*/, CHECK_VERIFY_(_verifier, nullptr));
if (stack[0].is_category2()) {
stack[1] = stack[0].to_category2_2nd();
stack_size = 2;
@@ -360,7 +378,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
check_verification_type_array_size(
stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr));
frame = new StackMapFrame(
offset, _prev_frame->flags(), _prev_frame->locals_size(), stack_size,
offset, flags, _prev_frame->locals_size(), stack_size,
_max_locals, _max_stack, locals, stack,
_assert_unset_fields_buffer, _verifier);
if (_first && locals != nullptr) {
@@ -394,7 +412,8 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, VerificationType, 2);
u2 stack_size = 1;
stack[0] = parse_verification_type(nullptr, CHECK_VERIFY_(_verifier, nullptr));
u1 flags = _uninit_in_prev_frame_locals;
stack[0] = parse_verification_type(&flags, false /*parsing_locals*/, CHECK_VERIFY_(_verifier, nullptr));
if (stack[0].is_category2()) {
stack[1] = stack[0].to_category2_2nd();
stack_size = 2;
@@ -402,7 +421,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
check_verification_type_array_size(
stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr));
frame = new StackMapFrame(
offset, _prev_frame->flags(), _prev_frame->locals_size(), stack_size,
offset, flags, _prev_frame->locals_size(), stack_size,
_max_locals, _max_stack, locals, stack,
_assert_unset_fields_buffer, _verifier);
if (_first && locals != nullptr) {
@@ -418,7 +437,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
int length = _prev_frame->locals_size();
int chops = SAME_FRAME_EXTENDED - frame_type;
int new_length = length;
u1 flags = _prev_frame->flags();
u1 flags = (u1)_uninit_in_prev_frame_locals;
assert(chops == 0 || (frame_type >= CHOP_FRAME_START && frame_type <= CHOP_FRAME_END), "should be");
if (chops != 0) {
new_length = chop(locals, length, chops);
@@ -426,9 +445,11 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
new_length, _max_locals, CHECK_VERIFY_(_verifier, nullptr));
// Recompute flags since uninitializedThis could have been chopped.
flags = 0;
_uninit_in_prev_frame_locals = false;
for (int i=0; i<new_length; i++) {
if (locals[i].is_uninitialized_this()) {
flags |= FLAG_THIS_UNINIT;
_uninit_in_prev_frame_locals = true;
break;
}
}
@@ -465,9 +486,9 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
for (int i = 0; i < _prev_frame->locals_size(); i++) {
locals[i] = pre_locals[i];
}
u1 flags = _prev_frame->flags();
u1 flags = (u1)_uninit_in_prev_frame_locals;
for (int i = 0; i < appends; i++) {
locals[real_length] = parse_verification_type(&flags, CHECK_NULL);
locals[real_length] = parse_verification_type(&flags, true /*parsing_locals*/, CHECK_NULL);
if (locals[real_length].is_category2()) {
locals[real_length + 1] = locals[real_length].to_category2_2nd();
++real_length;
@@ -491,6 +512,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
if (frame_type == FULL_FRAME) {
// full_frame
u1 flags = 0;
_uninit_in_prev_frame_locals = false;
u2 locals_size = _stream->get_u2(CHECK_NULL);
int real_locals_size = 0;
if (locals_size > 0) {
@@ -498,7 +520,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
THREAD, VerificationType, locals_size*2);
}
for (int i = 0; i < locals_size; i++) {
locals[real_locals_size] = parse_verification_type(&flags, CHECK_NULL);
locals[real_locals_size] = parse_verification_type(&flags, true /*parsing_locals*/, CHECK_NULL);
if (locals[real_locals_size].is_category2()) {
locals[real_locals_size + 1] =
locals[real_locals_size].to_category2_2nd();
@@ -516,7 +538,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
THREAD, VerificationType, stack_size*2);
}
for (int i = 0; i < stack_size; i++) {
stack[real_stack_size] = parse_verification_type(nullptr, CHECK_NULL);
stack[real_stack_size] = parse_verification_type(&flags, false /*parsing_locals*/, CHECK_NULL);
if (stack[real_stack_size].is_category2()) {
stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd();
++real_stack_size;
@@ -134,11 +134,17 @@ class StackMapReader : StackObj {
// Check if reading first entry
bool _first;
// We track whether an uninitializedThis was in the previous frame's
// locals independently of the flags parameter as most StackMapTable
// frames reuse the same locals as the previous frame. Chop and
// Full frames need to handle this specially.
bool _uninit_in_prev_frame_locals;
StackMapFrame* next_helper(TRAPS);
void check_offset(StackMapFrame* frame);
void check_size(TRAPS);
int32_t chop(VerificationType* locals, int32_t length, int32_t chops);
VerificationType parse_verification_type(u1* flags, TRAPS);
VerificationType parse_verification_type(u1* flags, bool parsing_locals, TRAPS);
void check_verification_type_array_size(
int32_t size, int32_t max_size, TRAPS) {
if (size < 0 || size > max_size) {
@@ -979,7 +979,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
// (2) Check if we are loading into the same module from the same location as in dump time.
if (CDSConfig::is_using_optimized_module_handling()) {
if (CDSConfig::is_using_full_module_graph()) {
// Class visibility has not changed between dump time and run time, so a class
// that was visible (and thus archived) during dump time is always visible during runtime.
assert(SystemDictionary::is_shared_class_visible_impl(class_name, ik, pkg_entry, class_loader),
@@ -1003,7 +1003,7 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name,
// has restricted the classes can be loaded at this step to be only:
// [1] cs->is_modules_image(): classes in java.base, or,
// [2] HeapShared::is_a_test_class_in_unnamed_module(ik): classes in bootstrap/unnamed module
assert(cl->is_modules_image() || HeapShared::is_a_test_class_in_unnamed_module(ik),
assert(cl->is_modules_image(),
"only these classes can be loaded before the module system is initialized");
assert(class_loader.is_null(), "sanity");
return true;
+1 -1
View File
@@ -473,7 +473,7 @@ class methodHandle;
\
do_class(jdk_internal_util_ArraysSupport, "jdk/internal/util/ArraysSupport") \
do_intrinsic(_vectorizedMismatch, jdk_internal_util_ArraysSupport, vectorizedMismatch_name, vectorizedMismatch_signature, F_S)\
do_name(vectorizedMismatch_name, "vectorizedMismatch") \
do_name(vectorizedMismatch_name, "vectorizedMismatchInternal") \
do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \
\
/* java/lang/ref/Reference */ \
+82 -91
View File
@@ -215,17 +215,9 @@ void AOTCodeCache::initialize() {
return; // AOTCache must be specified to dump and use AOT code
}
if (VerifyOops) {
// Disable AOT stub caching when VerifyOops flag is on.
// Verify oops code generated a lot of C strings which overflow
// AOT C string table (which has fixed size).
// AOT C string table will be reworked later to handle such cases.
log_info(aot, codecache, init)("AOT Stub Caching is not supported with VerifyOops.");
FLAG_SET_ERGO(AOTStubCaching, false);
if (InlineTypePassFieldsAsArgs) {
log_info(aot, codecache, init)("AOT Adapter Caching is not supported with VerifyOops + InlineTypePassFieldsAsArgs.");
FLAG_SET_ERGO(AOTAdapterCaching, false);
}
if (VerifyOops && InlineTypePassFieldsAsArgs) {
log_info(aot, codecache, init)("AOT Adapter Caching is not supported with VerifyOops + InlineTypePassFieldsAsArgs.");
FLAG_SET_ERGO(AOTAdapterCaching, false);
}
bool is_dumping = false;
@@ -304,6 +296,8 @@ void AOTCodeCache::init2() {
// Read strings
opened_cache->load_strings();
} else if (opened_cache->for_dump()) {
init_C_strings_caching();
}
// initialize aot runtime constants as appropriate to this runtime
AOTRuntimeConstants::initialize_from_runtime();
@@ -367,7 +361,6 @@ AOTCodeCache::AOTCodeCache(bool is_dumping, bool is_using) :
_load_entries(nullptr),
_search_entries(nullptr),
_store_entries(nullptr),
_C_strings_buf(nullptr),
_store_entries_cnt(0)
{
// Read header at the begining of cache
@@ -1873,7 +1866,7 @@ void AOTCodeReader::read_dbg_strings(DbgStrings& dbg_strings) {
// integer ranges defined by the following positive base and max
// values i.e. [_extrs_base, _extrs_base + _extrs_max -1],
// [_stubs_base, _stubs_base + _stubs_max -1], [_c_str_base,
// _c_str_base + _c_str_max -1],
// _c_str_base + _C_strings_count],
#define _extrs_max 500
#define _stubs_max static_cast<int>(EntryId::NUM_ENTRYIDS)
@@ -1933,6 +1926,8 @@ void AOTCodeAddressTable::init_extrs() {
ADD_EXTERNAL_ADDRESS(Thread::current); // used by call_stub
ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_StackOverflowError);
ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_delayed_StackOverflowError);
ADD_EXTERNAL_ADDRESS(StubRoutines::verify_oop_count_addr()); // used by generate_verify_oop()
ADD_EXTERNAL_ADDRESS(StubRoutines::verify_oop_subroutine_entry_address());
if (InlineTypeReturnedAsFields) {
ADD_EXTERNAL_ADDRESS(SharedRuntime::store_inline_type_fields_to_buf);
}
@@ -2150,9 +2145,10 @@ void AOTCodeAddressTable::init_extrs() {
ADD_EXTERNAL_ADDRESS(ZPointerVectorStoreGoodMask);
#if defined(AMD64)
ADD_EXTERNAL_ADDRESS(&ZPointerLoadShift);
ADD_EXTERNAL_ADDRESS(&ZPointerLoadShiftTable);
#endif
extern address ZPointerLoadShiftTableAddr;
ADD_EXTERNAL_ADDRESS(&ZPointerLoadShiftTableAddr);
#endif
#endif // INCLUDE_ZGC
#ifndef ZERO
#if defined(AMD64) || defined(AARCH64) || defined(RISCV64)
ADD_EXTERNAL_ADDRESS(MacroAssembler::debug64);
@@ -2237,64 +2233,68 @@ void AOTCodeAddressTable::set_stubgen_stubs_complete() {
}
#ifdef PRODUCT
#define MAX_STR_COUNT 200
#define INITIAL_STR_CACHE_SIZE 200
#else
#define MAX_STR_COUNT 2000
#define INITIAL_STR_CACHE_SIZE 2000
#endif
#define _c_str_max MAX_STR_COUNT
static const int _c_str_base = _all_max;
static const char* _C_strings_in[MAX_STR_COUNT] = {nullptr}; // Incoming strings
static const char* _C_strings[MAX_STR_COUNT] = {nullptr}; // Our duplicates
static GrowableArray<const char*>* _C_strings = nullptr; // Cached duplicates
static GrowableArray<int>* _C_strings_id = nullptr; // id corresponding to index in _C_strings[]
static GrowableArray<int>* _C_strings_ix = nullptr; // index in _C_strings[] corresponding to id
static const char** _cached_C_strings = nullptr;
static int _C_strings_count = 0;
static int _C_strings_s[MAX_STR_COUNT] = {0};
static int _C_strings_id[MAX_STR_COUNT] = {0};
static int _C_strings_used = 0;
void AOTCodeCache::init_C_strings_caching() {
assert(_C_strings == nullptr, "Initialize only once");
// Allocate arrays in C heap
_C_strings = new(mtCode) GrowableArray<const char*>(INITIAL_STR_CACHE_SIZE, 0, nullptr, mtCode);
_C_strings_id = new(mtCode) GrowableArray<int>(INITIAL_STR_CACHE_SIZE, 0, -1, mtCode);
_C_strings_ix = new(mtCode) GrowableArray<int>(INITIAL_STR_CACHE_SIZE, 0, -1, mtCode);
}
void AOTCodeCache::load_strings() {
uint strings_count = _load_header->strings_count();
uint strings_count = _load_header->strings_count();
if (strings_count == 0) {
return;
}
if (strings_count > MAX_STR_COUNT) {
fatal("Invalid strings_count loaded from AOT Code Cache: %d > MAX_STR_COUNT [%d]", strings_count, MAX_STR_COUNT);
return;
}
uint strings_offset = _load_header->strings_offset();
// First is the array of cached strings length
uint* string_lengths = (uint*)addr(strings_offset);
strings_offset += (strings_count * sizeof(uint));
uint strings_size = _load_header->entries_offset() - strings_offset;
// We have to keep cached strings longer than _cache buffer
// because they are refernced from compiled code which may
// still be executed on VM exit after _cache is freed.
char* p = NEW_C_HEAP_ARRAY(char, strings_size+1, mtCode);
memcpy(p, addr(strings_offset), strings_size);
_C_strings_buf = p;
// We don't need to duplcate strings from AOT cache to C heap
// because we don't remove AOT code cache anymore.
_cached_C_strings = NEW_C_HEAP_ARRAY(const char*, strings_count, mtCode);
char* start = (char*)addr(strings_offset);
char* p = start;
for (uint i = 0; i < strings_count; i++) {
_C_strings[i] = p;
_cached_C_strings[i] = p;
uint len = string_lengths[i];
_C_strings_s[i] = i;
_C_strings_id[i] = i;
log_trace(aot, codecache, stringtable)("load_strings: _C_strings[%d] " INTPTR_FORMAT " '%s'", i, p2i(p), p);
p += len;
}
assert((uint)(p - _C_strings_buf) <= strings_size, "(" INTPTR_FORMAT " - " INTPTR_FORMAT ") = %d > %d ", p2i(p), p2i(_C_strings_buf), (uint)(p - _C_strings_buf), strings_size);
uint strings_size = _load_header->entries_offset() - strings_offset;
assert((uint)(p - start) <= strings_size, "(" INTPTR_FORMAT " - " INTPTR_FORMAT ") = %d > %d ", p2i(p), p2i(start), (uint)(p - start), strings_size);
_C_strings_count = strings_count;
_C_strings_used = strings_count;
log_debug(aot, codecache, init)(" Loaded %d C strings of total length %d at offset %d from AOT Code Cache", _C_strings_count, strings_size, strings_offset);
}
int AOTCodeCache::store_strings() {
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
if (_C_strings_used > 0) {
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
uint offset = _write_position;
uint length = 0;
uint* lengths = (uint *)reserve_bytes(sizeof(uint) * _C_strings_used);
if (lengths == nullptr) {
return -1;
}
// Write strings into AOT cache in `id` order.
for (int i = 0; i < _C_strings_used; i++) {
const char* str = _C_strings[_C_strings_s[i]];
const char* str = _C_strings->at(_C_strings_ix->at(i));
log_trace(aot, codecache, stringtable)("store_strings: _C_strings[%d] " INTPTR_FORMAT " '%s'", i, p2i(str), str);
uint len = (uint)strlen(str) + 1;
length += len;
@@ -2306,7 +2306,7 @@ int AOTCodeCache::store_strings() {
}
}
log_debug(aot, codecache, exit)(" Wrote %d C strings of total length %d at offset %d to AOT Code Cache",
_C_strings_used, length, offset);
_C_strings_used, length, offset);
}
return _C_strings_used;
}
@@ -2315,57 +2315,50 @@ const char* AOTCodeCache::add_C_string(const char* str) {
if (is_on_for_dump() && str != nullptr) {
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
AOTCodeAddressTable* table = addr_table();
if (table != nullptr) {
return table->add_C_string(str);
}
assert(table != nullptr, "should be initialized already");
return table->add_C_string(str);
}
return str;
}
// Identical C strings get the same ID
const char* AOTCodeAddressTable::add_C_string(const char* str) {
if (_extrs_complete || initializing_extrs) {
// Check previous strings address
for (int i = 0; i < _C_strings_count; i++) {
if (_C_strings_in[i] == str) {
return _C_strings[i]; // Found previous one - return our duplicate
} else if (strcmp(_C_strings[i], str) == 0) {
return _C_strings[i];
}
}
// Add new one
if (_C_strings_count < MAX_STR_COUNT) {
// Passed in string can be freed and used space become inaccessible.
// Keep original address but duplicate string for future compare.
_C_strings_id[_C_strings_count] = -1; // Init
_C_strings_in[_C_strings_count] = str;
const char* dup = os::strdup(str);
_C_strings[_C_strings_count++] = dup;
log_trace(aot, codecache, stringtable)("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup);
assert_lock_strong(AOTCodeCStrings_lock);
for (int i = 0; i < _C_strings_count; i++) {
const char* dup = _C_strings->at(i);
if (strcmp(dup, str) == 0) {
return dup;
} else {
assert(false, "Number of C strings >= MAX_STR_COUNT");
}
}
return str;
// Add one new string.
// Passed in string can be freed and used space become inaccessible.
// Duplicate string for future compare.
const char* dup = os::strdup(str);
_C_strings->at_put_grow(_C_strings_count, dup);
_C_strings_id->at_put_grow(_C_strings_count, -1);
log_trace(aot, codecache, stringtable)("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup);
_C_strings_count++;
return dup;
}
int AOTCodeAddressTable::id_for_C_string(address str) {
assert(AOTCodeCache::is_on_for_dump(), "should be called only during AOT code cache dump");
if (str == nullptr) {
return BAD_ADDRESS_ID;
}
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
for (int i = 0; i < _C_strings_count; i++) {
if (_C_strings[i] == (const char*)str) { // found
int id = _C_strings_id[i];
if (_C_strings->at(i) == (const char*)str) { // found
int id = _C_strings_id->at(i);
if (id >= 0) {
assert(id < _C_strings_used, "%d >= %d", id , _C_strings_used);
return id; // Found recorded
}
log_trace(aot, codecache, stringtable)("id_for_C_string: _C_strings[%d ==> %d] " INTPTR_FORMAT " '%s'", i, _C_strings_used, p2i(str), str);
// Not found in recorded, add new
id = _C_strings_used++;
_C_strings_s[id] = i;
_C_strings_id[i] = id;
_C_strings_ix->at_put_grow(id, i);
_C_strings_id->at_put_grow(i, id);
log_trace(aot, codecache, stringtable)("id_for_C_string: _C_strings[%d ==> %d] " INTPTR_FORMAT " '%s'", i, id, p2i(str), str);
return id;
}
}
@@ -2373,8 +2366,10 @@ int AOTCodeAddressTable::id_for_C_string(address str) {
}
address AOTCodeAddressTable::address_for_C_string(int idx) {
assert(idx < _C_strings_count, "sanity");
return (address)_C_strings[idx];
assert(AOTCodeCache::is_on_for_use(), "should be called only when loading from AOT code cache");
assert((uint)idx < (uint)_C_strings_count, " %d >= %d", idx, _C_strings_count);
precond(_cached_C_strings != nullptr);
return (address)_cached_C_strings[idx];
}
static int search_address(address addr, address* table, uint length) {
@@ -2391,23 +2386,23 @@ address AOTCodeAddressTable::address_for_id(int idx) {
if (idx == -1) {
return (address)-1;
}
uint id = (uint)idx;
// special case for symbols based relative to os::init
if (id > (_c_str_base + _c_str_max)) {
return (address)os::init + idx;
}
if (idx < 0) {
fatal("Incorrect id %d for AOT Code Cache addresses table", id);
if (idx >= (_c_str_base + _C_strings_count)) {
fatal("recorded id: %d > recorded count %d", idx, (_c_str_base + _C_strings_count));
return nullptr;
}
if (idx < 0) {
fatal("Incorrect id %d for AOT Code Cache addresses table", idx);
return nullptr;
}
uint id = (uint)idx;
// no need to compare unsigned id against 0
if (/* id >= _extrs_base && */ id < _extrs_length) {
if (id < _extrs_length) {
return _extrs_addr[id - _extrs_base];
}
if (id >= _stubs_base && id < _c_str_base) {
return _stubs_addr[id - _stubs_base];
}
if (id >= _c_str_base && id < (_c_str_base + (uint)_C_strings_count)) {
if (id >= _c_str_base && id < (uint)(_c_str_base + _C_strings_count)) {
return address_for_C_string(id - _c_str_base);
}
fatal("Incorrect id %d for AOT Code Cache addresses table", id);
@@ -2454,19 +2449,11 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB
char* func_name = NEW_RESOURCE_ARRAY(char, buflen);
int offset = 0;
if (os::dll_address_to_function_name(addr, func_name, buflen, &offset)) {
if (offset > 0) {
// Could be address of C string
uint dist = (uint)pointer_delta(addr, (address)os::init, 1);
log_debug(aot, codecache)("Address " INTPTR_FORMAT " (offset %d) for runtime target '%s' is missing in AOT Code Cache addresses table",
p2i(addr), dist, (const char*)addr);
assert(dist > (uint)(_all_max + MAX_STR_COUNT), "change encoding of distance");
return dist;
}
#ifdef ASSERT
reloc.print_current_on(tty);
code_blob->print_on(tty);
code_blob->print_code_on(tty);
assert(false, "Address " INTPTR_FORMAT " for runtime target '%s+%d' is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset);
assert(false, "Address " INTPTR_FORMAT " for runtime target <%s+%d>/('%s') is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset, (const char*)addr);
#endif
} else {
#ifdef ASSERT
@@ -2512,12 +2499,16 @@ void AOTRuntimeConstants::initialize_from_runtime() {
_aot_runtime_constants._card_table_base = card_table_base;
_aot_runtime_constants._grain_shift = grain_shift;
_aot_runtime_constants._cset_base = cset_base;
_aot_runtime_constants._verify_oop_mask = Universe::verify_oop_mask();
_aot_runtime_constants._verify_oop_bits = Universe::verify_oop_bits();
}
address AOTRuntimeConstants::_field_addresses_list[] = {
((address)&_aot_runtime_constants._card_table_base),
((address)&_aot_runtime_constants._grain_shift),
((address)&_aot_runtime_constants._cset_base),
((address)&_aot_runtime_constants._verify_oop_mask),
((address)&_aot_runtime_constants._verify_oop_bits),
nullptr
};
+9 -1
View File
@@ -304,6 +304,7 @@ public:
do_var(bool, UseVectorizedMismatchIntrinsic) \
do_var(bool, InlineTypeReturnedAsFields) \
do_var(bool, VMContinuations) \
do_var(bool, VerifyOops) \
do_fun(int, CompressedKlassPointers_shift, CompressedKlassPointers::shift()) \
do_fun(bool, JavaAssertions_systemClassDefault, JavaAssertions::systemClassDefault()) \
do_fun(bool, JavaAssertions_userClassDefault, JavaAssertions::userClassDefault()) \
@@ -464,7 +465,6 @@ private:
AOTCodeEntry* _load_entries; // Used when reading cache
uint* _search_entries; // sorted by ID table [id, index]
AOTCodeEntry* _store_entries; // Used when writing cache
const char* _C_strings_buf; // Loaded buffer for _C_strings[] table
uint _store_entries_cnt;
static AOTCodeCache* open_for_use();
@@ -498,6 +498,7 @@ public:
uint load_size() const { return _load_size; }
uint write_position() const { return _write_position; }
static void init_C_strings_caching();
void load_strings();
int store_strings();
@@ -683,6 +684,9 @@ class AOTRuntimeConstants {
address _card_table_base;
uint _grain_shift;
address _cset_base;
uintptr_t _verify_oop_mask;
uintptr_t _verify_oop_bits;
static address _field_addresses_list[];
static AOTRuntimeConstants _aot_runtime_constants;
// private constructor for unique singleton
@@ -699,6 +703,8 @@ class AOTRuntimeConstants {
static address card_table_base_address();
static address grain_shift_address() { return (address)&_aot_runtime_constants._grain_shift; }
static address cset_base_address() { return (address)&_aot_runtime_constants._cset_base; }
static address verify_oop_mask_address() { return (address)&_aot_runtime_constants._verify_oop_mask; }
static address verify_oop_bits_address() { return (address)&_aot_runtime_constants._verify_oop_bits; }
static address* field_addresses_list() {
return _field_addresses_list;
}
@@ -707,6 +713,8 @@ class AOTRuntimeConstants {
static address card_table_base_address() { return nullptr; }
static address grain_shift_address() { return nullptr; }
static address cset_base_address() { return nullptr; }
static address verify_oop_mask_address() { return nullptr; }
static address verify_oop_bits_address() { return nullptr; }
static address* field_addresses_list() { return nullptr; }
#endif
};
@@ -79,8 +79,7 @@ bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level)
if (m->has_compiled_code()) return false; // already compiled
if (!can_be_compiled(m, comp_level)) return false;
return !UseInterpreter || // must compile all methods
(AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods
return !UseInterpreter; // must compile all methods
}
void CompilationPolicy::maybe_compile_early(const methodHandle& m, TRAPS) {
+2 -2
View File
@@ -1744,7 +1744,7 @@ void CompileBroker::compiler_thread_loop() {
// Never compile a method if breakpoints are present in it
if (method()->number_of_breakpoints() == 0) {
// Compile the method.
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
if (UseCompiler && CompileBroker::should_compile_new_jobs()) {
invoke_compiler_on_method(task);
thread->start_idle_timer();
} else {
@@ -2152,7 +2152,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
*/
void CompileBroker::handle_full_code_cache(CodeBlobType code_blob_type) {
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
if (UseCompiler) {
if (xtty != nullptr) {
stringStream s;
// Dump code cache state into a buffer before locking the tty,
@@ -369,7 +369,6 @@ public:
static void disable_compilation_forever() {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
AtomicAccess::xchg(&_should_compile_new_jobs, jint(shutdown_compilation));
}
+3 -3
View File
@@ -59,7 +59,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
Reason_Tiered, // Tiered-policy
Reason_Replay, // ciReplay
Reason_Whitebox, // Whitebox API
Reason_MustBeCompiled, // Used for -Xcomp or AlwaysCompileLoopMethods (see CompilationPolicy::must_be_compiled())
Reason_MustBeCompiled, // Used for -Xcomp (see CompilationPolicy::must_be_compiled())
Reason_Count
};
@@ -71,9 +71,9 @@ class CompileTask : public CHeapObj<mtCompiler> {
"tiered",
"replay",
"whitebox",
"must_be_compiled",
"bootstrap"
"must_be_compiled"
};
STATIC_ASSERT(ARRAY_SIZE(reason_names) == Reason_Count);
return reason_names[compile_reason];
}
@@ -383,6 +383,12 @@
"If compilation is stopped with an error, capture diagnostic " \
"information at the bailout point") \
\
product(uint, StressSeed, 0, DIAGNOSTIC, \
"Seed for randomized stress testing (if unset, a random one is " \
"generated). The seed is recorded in the compilation log, if " \
"available.") \
range(0, max_juint) \
\
// end of COMPILER_FLAGS
DECLARE_FLAGS(COMPILER_FLAGS)
+111
View File
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "compiler/compileLog.hpp"
#include "compiler/compiler_globals.hpp"
#include "compiler/compilerDefinitions.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/stress.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/os.hpp"
#include "utilities/ticks.hpp"
#ifdef COMPILER2
#include "opto/c2_globals.hpp"
#endif // COMPILER
static bool should_initialize_stress_seed(CompilerType comp) {
switch (comp) {
#ifdef COMPILER1
case compiler_c1:
return false;
#endif // COMPILER1
#ifdef COMPILER2
case compiler_c2:
return StressLCM || StressGCM || StressIGVN || StressCCP ||
StressIncrementalInlining || StressMacroExpansion ||
StressMacroElimination || StressUnstableIfTraps ||
StressBailout || StressLoopPeeling || StressCountedLoop ||
StressEliminateAllocations;
#endif // COMPILER2
default:
assert(comp != compiler_none && comp != compiler_number_of_types, "expected valid compiler");
return false;
}
}
Stress::Stress(DirectiveSet* directives, CompileLog* log, CompilerType comp) {
if (!should_initialize_stress_seed(comp)) {
_stress_seed = 0;
return;
}
if (FLAG_IS_DEFAULT(StressSeed) || (FLAG_IS_ERGO(StressSeed) && directives->RepeatCompilationOption)) {
_stress_seed = static_cast<uint>(Ticks::now().nanoseconds());
FLAG_SET_ERGO(StressSeed, _stress_seed);
} else {
_stress_seed = StressSeed;
}
if (log != nullptr) {
log->elem("stress_test seed='%u'", _stress_seed);
}
}
uint Stress::random() {
_stress_seed = os::next_random(_stress_seed);
return _stress_seed;
}
const uint RANDOMIZED_DOMAIN_POW = 29;
const uint RANDOMIZED_DOMAIN = 1 << RANDOMIZED_DOMAIN_POW;
const uint RANDOMIZED_DOMAIN_MASK = (1 << (RANDOMIZED_DOMAIN_POW + 1)) - 1;
// This method can be called an arbitrary number of times, with the current count
// as the argument. The logic allows for selecting a single candidate from the
// running list of candidates as follows:
// int count = 0;
// Cand* selected = null;
// while(cand = cand->next()) {
// if (randomized_select(++count)) {
// selected = cand;
// }
// }
//
// Including the count equalizes the chances any candidate is "selected".
// This is useful when we don't have the complete list of candidates to choose
// from uniformly. In this case, we need to adjust the randomicity of the
// selection, or else we will end up biasing the selection towards the latter
// candidates.
//
// A quick back-of-the-envelope calculation shows that for the list of n candidates
// the equal probability for the candidate to persist as "best" as can be
// achieved by replacing it with "next" k-th candidate with the probability
// of 1/k. It can be easily shown that by the end of the run, the
// probability for any candidate has converged to 1/n, thus giving the
// uniform distribution among all the candidates.
//
// We don't care about the domain size as long as (RANDOMIZED_DOMAIN / count) is large.
bool Stress::randomized_select(uint count) {
return (random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count);
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_COMPILER_STRESS_HPP
#define SHARE_COMPILER_STRESS_HPP
#include "compiler/compileLog.hpp"
#include "compiler/compilerDefinitions.hpp"
#include "compiler/compilerDirectives.hpp"
#include "memory/allocation.hpp"
class Stress : public StackObj {
private:
uint _stress_seed;
public:
Stress(DirectiveSet* directives, CompileLog* log, CompilerType comp);
uint random();
bool randomized_select(uint count);
};
#endif // SHARE_COMPILER_STRESS_HPP
+17 -22
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -282,6 +282,8 @@ CollectedHeap::CollectedHeap() :
_last_whole_heap_examined_time_ns(os::javaTimeNanos()),
_total_collections(0),
_total_full_collections(0),
NOT_PRODUCT(_promotion_failure_alot_count(0) COMMA)
NOT_PRODUCT(_promotion_failure_alot_gc_number(0) COMMA)
_vmthread_cpu_time(0),
_gc_cause(GCCause::_no_gc),
_gc_lastcause(GCCause::_no_gc)
@@ -299,9 +301,6 @@ CollectedHeap::CollectedHeap() :
_filler_array_max_size = align_object_size(filler_array_hdr_size() +
max_len / elements_per_word);
NOT_PRODUCT(_promotion_failure_alot_count = 0;)
NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;)
if (UsePerfData) {
EXCEPTION_MARK;
@@ -622,35 +621,31 @@ size_t CollectedHeap::bootstrap_max_memory() const {
#ifndef PRODUCT
bool CollectedHeap::promotion_should_fail(volatile size_t* count) {
// Access to count is not atomic; the value does not have to be exact.
bool CollectedHeap::promotion_should_fail() {
// Access to count is not atomic in any way - we can loose updates, overwrite never counts, etc;
// the value does not have to be exact.
if (PromotionFailureALot) {
const size_t gc_num = total_collections();
const size_t elapsed_gcs = gc_num - _promotion_failure_alot_gc_number;
const size_t elapsed_gcs = gc_num - _promotion_failure_alot_gc_number.load_relaxed();
if (elapsed_gcs >= PromotionFailureALotInterval) {
// Test for unsigned arithmetic wrap-around.
if (++*count >= PromotionFailureALotCount) {
*count = 0;
// To avoid the base (x86-)costs for atomic RMW operations, use explicit load/store_relaxed() operations.
uintx new_count = _promotion_failure_alot_count.load_relaxed() + 1;
if (new_count >= PromotionFailureALotCount) {
_promotion_failure_alot_count.store_relaxed(0);
return true;
} else {
_promotion_failure_alot_count.store_relaxed(new_count);
}
}
}
return false;
}
bool CollectedHeap::promotion_should_fail() {
return promotion_should_fail(&_promotion_failure_alot_count);
}
void CollectedHeap::reset_promotion_should_fail(volatile size_t* count) {
if (PromotionFailureALot) {
_promotion_failure_alot_gc_number = total_collections();
*count = 0;
}
}
void CollectedHeap::reset_promotion_should_fail() {
reset_promotion_should_fail(&_promotion_failure_alot_count);
if (PromotionFailureALot) {
_promotion_failure_alot_gc_number.store_relaxed(total_collections());
_promotion_failure_alot_count.store_relaxed(0);
}
}
#endif // #ifndef PRODUCT
@@ -32,6 +32,7 @@
#include "memory/metaspace.hpp"
#include "memory/universe.hpp"
#include "oops/stackChunkOop.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.hpp"
#include "runtime/perfDataTypes.hpp"
#include "runtime/safepoint.hpp"
@@ -129,8 +130,8 @@ class CollectedHeap : public CHeapObj<mtGC> {
unsigned int _total_collections; // ... started
unsigned int _total_full_collections; // ... started
NOT_PRODUCT(volatile size_t _promotion_failure_alot_count;)
NOT_PRODUCT(volatile size_t _promotion_failure_alot_gc_number;)
NOT_PRODUCT(Atomic<size_t> _promotion_failure_alot_count;)
NOT_PRODUCT(Atomic<size_t> _promotion_failure_alot_gc_number;)
jlong _vmthread_cpu_time;
@@ -503,14 +504,11 @@ protected:
// Non product verification and debugging.
#ifndef PRODUCT
// Support for PromotionFailureALot. Return true if it's time to cause a
// promotion failure. The no-argument version uses
// this->_promotion_failure_alot_count as the counter.
bool promotion_should_fail(volatile size_t* count);
// promotion failure.
bool promotion_should_fail();
// Reset the PromotionFailureALot counters. Should be called at the end of a
// GC in which promotion failure occurred.
void reset_promotion_should_fail(volatile size_t* count);
void reset_promotion_should_fail();
#endif // #ifndef PRODUCT
};
+1 -1
View File
@@ -285,7 +285,7 @@
develop(uintx, MaxVirtMemFraction, 2, \
"Maximum fraction (1/n) of virtual memory used for ergonomically "\
"determining maximum heap size") \
range(1, max_uintx) \
range(1, max_juint) \
\
product(bool, UseAdaptiveSizePolicy, true, \
"Use adaptive generation sizing policies") \
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,16 +44,6 @@ void ShenandoahArguments::initialize() {
vm_exit_during_initialization("Shenandoah GC is not supported on this platform.");
#endif
// Shenandoah relies on the object header bits (including the self-forwarded bit
// at markWord::self_fwd_mask_in_place) being preserved across monitor inflation,
// which only holds with UseObjectMonitorTable.
if (!UseObjectMonitorTable) {
if (FLAG_IS_CMDLINE(UseObjectMonitorTable)) {
vm_exit_during_initialization("Shenandoah requires UseObjectMonitorTable");
}
FLAG_SET_DEFAULT(UseObjectMonitorTable, true);
}
#if 0 // leave this block as stepping stone for future platforms
log_warning(gc)("Shenandoah GC is not fully supported on this platform:");
log_warning(gc)(" concurrent modes are not supported, only STW cycles are enabled;");
@@ -110,9 +110,6 @@ public:
template <class T>
inline oop load_reference_barrier(DecoratorSet decorators, oop obj, T* load_addr);
template <typename T>
inline oop oop_load(DecoratorSet decorators, T* addr);
template <typename T>
inline oop oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value);
@@ -147,6 +144,9 @@ public:
typedef BarrierSet::AccessBarrier<decorators, BarrierSetT> Raw;
private:
template <typename T>
static oop oop_load_common(DecoratorSet resolved_decorators, T* addr);
template <typename T>
static void oop_store_common(T* addr, oop value);
@@ -233,14 +233,6 @@ inline void ShenandoahBarrierSet::write_ref_field_post(T* field, oop new_value)
*byte = CardTable::dirty_card_val();
}
template <typename T>
inline oop ShenandoahBarrierSet::oop_load(DecoratorSet decorators, T* addr) {
oop value = RawAccess<>::oop_load(addr);
value = load_reference_barrier(decorators, value, addr);
keep_alive_if_weak(decorators, value);
return value;
}
template <typename T>
inline oop ShenandoahBarrierSet::oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value) {
shenandoah_assert_not_in_cset_except(nullptr, compare_value, (compare_value == nullptr || ShenandoahHeap::heap()->cancelled_gc()));
@@ -274,27 +266,35 @@ inline oop ShenandoahBarrierSet::oop_xchg(DecoratorSet decorators, T* addr, oop
return RawAccess<>::oop_atomic_xchg(addr, new_value);
}
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_common(DecoratorSet resolved_decorators, T* addr) {
// This raw access inherits decorators that are needed for proper memory ordering.
oop value = Raw::template oop_load<oop>(addr);
ShenandoahBarrierSet* bs = barrier_set();
value = bs->load_reference_barrier(resolved_decorators, value, addr);
bs->keep_alive_if_weak(resolved_decorators, value);
return value;
}
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_not_in_heap(T* addr) {
assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent");
ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
return bs->oop_load(decorators, addr);
return oop_load_common(decorators, addr);
}
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_in_heap(T* addr) {
assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent");
ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
return bs->oop_load(decorators, addr);
return oop_load_common(decorators, addr);
}
template <DecoratorSet decorators, typename BarrierSetT>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_in_heap_at(oop base, ptrdiff_t offset) {
ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
return bs->oop_load(resolved_decorators, AccessInternal::oop_field_addr<decorators>(base, offset));
return oop_load_common(resolved_decorators, AccessInternal::oop_field_addr<decorators>(base, offset));
}
template <DecoratorSet decorators, typename BarrierSetT>
@@ -105,7 +105,7 @@ ShenandoahGC::ShenandoahDegenPoint ShenandoahConcurrentGC::degen_point() const {
void ShenandoahConcurrentGC::entry_concurrent_update_refs_prepare(ShenandoahHeap* const heap) {
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_init_update_refs_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent init update refs", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs_prepare);
EventMark em("%s", msg);
@@ -117,8 +117,7 @@ void ShenandoahConcurrentGC::entry_concurrent_update_refs_prepare(ShenandoahHeap
void ShenandoahConcurrentGC::entry_update_card_table() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent update cards";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update cards", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_card_table);
EventMark em("%s", msg);
@@ -295,7 +294,7 @@ void ShenandoahConcurrentGC::entry_complete_abbreviated_cycle() {
ShenandoahGenerationalHeap* const heap = ShenandoahGenerationalHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent complete abbreviated cycle";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent complete abbreviated cycle", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::complete_abbreviated);
EventMark em("%s", msg);
@@ -376,7 +375,10 @@ void ShenandoahConcurrentGC::vmop_entry_final_verify() {
}
void ShenandoahConcurrentGC::entry_init_mark() {
const char* msg = init_mark_event_message();
ShenandoahHeap* const heap = ShenandoahHeap::heap();
assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Init Mark", "");
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_mark);
EventMark em("%s", msg);
@@ -388,7 +390,11 @@ void ShenandoahConcurrentGC::entry_init_mark() {
}
void ShenandoahConcurrentGC::entry_final_mark() {
const char* msg = final_mark_event_message();
ShenandoahHeap* const heap = ShenandoahHeap::heap();
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
"Should not have forwarded objects during final mark, unless old gen concurrent mark is running");
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Final Mark", "");
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_mark);
EventMark em("%s", msg);
@@ -400,7 +406,7 @@ void ShenandoahConcurrentGC::entry_final_mark() {
}
void ShenandoahConcurrentGC::entry_init_update_refs() {
static const char* msg = "Pause Init Update Refs";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Init Update Refs", "");
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_update_refs);
EventMark em("%s", msg);
@@ -409,7 +415,7 @@ void ShenandoahConcurrentGC::entry_init_update_refs() {
}
void ShenandoahConcurrentGC::entry_final_update_refs() {
static const char* msg = "Pause Final Update Refs";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Final Update Refs", "");
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_update_refs);
EventMark em("%s", msg);
@@ -421,7 +427,7 @@ void ShenandoahConcurrentGC::entry_final_update_refs() {
}
void ShenandoahConcurrentGC::entry_final_verify() {
const char* msg = verify_final_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Verify Final", "");
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_verify);
EventMark em("%s", msg);
@@ -435,7 +441,7 @@ void ShenandoahConcurrentGC::entry_reset() {
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
{
const char* msg = conc_reset_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent reset", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset);
EventMark em("%s", msg);
@@ -450,7 +456,8 @@ void ShenandoahConcurrentGC::entry_scan_remembered_set() {
if (_generation->is_young()) {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = "Concurrent remembered set scanning";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent remembered set scanning", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::init_scan_rset);
EventMark em("%s", msg);
@@ -466,7 +473,7 @@ void ShenandoahConcurrentGC::entry_scan_remembered_set() {
void ShenandoahConcurrentGC::entry_mark_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = "Concurrent marking roots";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent marking roots", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark_roots);
EventMark em("%s", msg);
@@ -480,8 +487,11 @@ void ShenandoahConcurrentGC::entry_mark_roots() {
void ShenandoahConcurrentGC::entry_mark() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
"Should not have forwarded objects concurrent mark, unless old gen concurrent mark is running");
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_mark_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent marking", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark);
EventMark em("%s", msg);
@@ -496,7 +506,7 @@ void ShenandoahConcurrentGC::entry_mark() {
void ShenandoahConcurrentGC::entry_thread_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
static const char* msg = "Concurrent thread roots";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent thread roots", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_thread_roots);
EventMark em("%s", msg);
@@ -511,7 +521,7 @@ void ShenandoahConcurrentGC::entry_thread_roots() {
void ShenandoahConcurrentGC::entry_weak_refs() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
const char* msg = conc_weak_refs_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent weak references", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_refs);
EventMark em("%s", msg);
@@ -527,7 +537,7 @@ void ShenandoahConcurrentGC::entry_weak_refs() {
void ShenandoahConcurrentGC::entry_weak_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_weak_roots_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent weak roots", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_roots);
EventMark em("%s", msg);
@@ -543,7 +553,7 @@ void ShenandoahConcurrentGC::entry_weak_roots() {
void ShenandoahConcurrentGC::entry_class_unloading() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent class unloading";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent class unloading", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_class_unload);
EventMark em("%s", msg);
@@ -559,7 +569,7 @@ void ShenandoahConcurrentGC::entry_class_unloading() {
void ShenandoahConcurrentGC::entry_strong_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent strong roots";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent strong roots", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_strong_roots);
EventMark em("%s", msg);
@@ -577,7 +587,7 @@ void ShenandoahConcurrentGC::entry_strong_roots() {
void ShenandoahConcurrentGC::entry_cleanup_early() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_cleanup_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent cleanup", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_early, true /* log_heap_usage */);
EventMark em("%s", msg);
@@ -596,8 +606,7 @@ void ShenandoahConcurrentGC::entry_cleanup_early() {
void ShenandoahConcurrentGC::entry_evacuate() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent evacuation";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent evacuation", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_evac);
EventMark em("%s", msg);
@@ -613,8 +622,7 @@ void ShenandoahConcurrentGC::entry_evacuate() {
void ShenandoahConcurrentGC::entry_update_thread_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent update thread roots";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update thread roots", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_thread_roots);
EventMark em("%s", msg);
@@ -627,7 +635,7 @@ void ShenandoahConcurrentGC::entry_update_thread_roots() {
void ShenandoahConcurrentGC::entry_update_refs() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent update references";
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update references", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs);
EventMark em("%s", msg);
@@ -643,7 +651,7 @@ void ShenandoahConcurrentGC::entry_update_refs() {
void ShenandoahConcurrentGC::entry_cleanup_complete() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_cleanup_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent cleanup", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_complete, true /* log_heap_usage */);
EventMark em("%s", msg);
@@ -655,7 +663,7 @@ void ShenandoahConcurrentGC::entry_cleanup_complete() {
void ShenandoahConcurrentGC::entry_reset_after_collect() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_reset_after_collect_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent reset after collect", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_after_collect);
EventMark em("%s", msg);
@@ -1250,7 +1258,7 @@ void ShenandoahConcurrentGC::op_final_update_refs() {
void ShenandoahConcurrentGC::entry_final_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_final_roots_event_message();
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent final roots", "");
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_final_roots);
EventMark em("%s", msg);
@@ -1295,100 +1303,3 @@ bool ShenandoahConcurrentGC::check_cancellation_and_abort(ShenandoahDegenPoint p
}
return false;
}
const char* ShenandoahConcurrentGC::init_mark_event_message() const {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");
if (heap->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Init Mark", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Init Mark", "");
}
}
const char* ShenandoahConcurrentGC::final_mark_event_message() const {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
"Should not have forwarded objects during final mark, unless old gen concurrent mark is running");
if (heap->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Mark", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Mark", "");
}
}
const char* ShenandoahConcurrentGC::conc_mark_event_message() const {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
"Should not have forwarded objects concurrent mark, unless old gen concurrent mark is running");
if (heap->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent marking", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent marking", "");
}
}
const char* ShenandoahConcurrentGC::conc_reset_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset", "");
}
}
const char* ShenandoahConcurrentGC::conc_reset_after_collect_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", "");
}
}
const char* ShenandoahConcurrentGC::verify_final_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", "");
}
}
const char* ShenandoahConcurrentGC::conc_final_roots_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Final Roots", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Final Roots", "");
}
}
const char* ShenandoahConcurrentGC::conc_weak_refs_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak references", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak references", "");
}
}
const char* ShenandoahConcurrentGC::conc_weak_roots_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak roots", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak roots", "");
}
}
const char* ShenandoahConcurrentGC::conc_cleanup_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent cleanup", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent cleanup", "");
}
}
const char* ShenandoahConcurrentGC::conc_init_update_refs_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Init Update Refs", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Init Update Refs", "");
}
}
@@ -132,20 +132,6 @@ private:
void start_mark();
static bool has_in_place_promotions(ShenandoahHeap* heap);
// Messages for GC trace events, they have to be immortal for
// passing around the logging/tracing systems
const char* init_mark_event_message() const;
const char* final_mark_event_message() const;
const char* verify_final_event_message() const;
const char* conc_final_roots_event_message() const;
const char* conc_mark_event_message() const;
const char* conc_reset_event_message() const;
const char* conc_reset_after_collect_event_message() const;
const char* conc_weak_refs_event_message() const;
const char* conc_weak_roots_event_message() const;
const char* conc_cleanup_event_message() const;
const char* conc_init_update_refs_event_message() const;
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTGC_HPP

Some files were not shown because too many files have changed in this diff Show More