diff --git a/8300800-UB-Shift-exponent-32-is-too-large-for-32-bit.patch b/8300800-UB-Shift-exponent-32-is-too-large-for-32-bit.patch new file mode 100644 index 0000000000000000000000000000000000000000..9468f5865d6989fb4f2c09309ef08ddfea8d54ea --- /dev/null +++ b/8300800-UB-Shift-exponent-32-is-too-large-for-32-bit.patch @@ -0,0 +1,22 @@ +Subject: 8300800: UB: Shift exponent 32 is too large for 32-bit type 'int' + +--- + src/hotspot/cpu/aarch64/immediate_aarch64.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp +index 3d87fde2b..961f93ed7 100644 +--- a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp ++++ b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp +@@ -295,7 +295,7 @@ int expandLogicalImmediate(uint32_t immN, uint32_t immr, + uint64_t and_bits_sub = replicate(and_bit, 1, nbits); + uint64_t or_bits_sub = replicate(or_bit, 1, nbits); + uint64_t and_bits_top = (and_bits_sub << nbits) | ones(nbits); +- uint64_t or_bits_top = (0 << nbits) | or_bits_sub; ++ uint64_t or_bits_top = (UCONST64(0) << nbits) | or_bits_sub; + + tmask = ((tmask + & (replicate(and_bits_top, 2 * nbits, 32 / nbits))) +-- +2.33.0 + diff --git a/8334780-Crash-assert-h_array_list.not_null-failed-in.patch b/8334780-Crash-assert-h_array_list.not_null-failed-in.patch new file mode 100644 index 0000000000000000000000000000000000000000..52dde77a9def47c92bc3c156b29016682fe2c992 --- /dev/null +++ b/8334780-Crash-assert-h_array_list.not_null-failed-in.patch @@ -0,0 +1,25 @@ +Subject: 8334780: Crash: assert(h_array_list.not_null()) failed: invariant + +--- + src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp +index 5388349c3..1f594a19e 100644 +--- a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp ++++ b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp +@@ -136,8 +136,9 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) { + transform_klasses_to_local_jni_handles(event_subklasses, THREAD); + + Handle h_array_list(THREAD, new_java_util_arraylist(THREAD)); +- assert(h_array_list.not_null(), "invariant"); +- ++ if (h_array_list.is_null()) { ++ return empty_java_util_arraylist; ++ } + static const char add_method_name[] = "add"; + static const char add_method_signature[] = "(Ljava/lang/Object;)Z"; + const Klass* const array_list_klass = JfrJavaSupport::klass(empty_java_util_arraylist); +-- +2.33.0 + diff --git a/8335610-DiagnosticFramework-CmdLine-is_executable-co.patch b/8335610-DiagnosticFramework-CmdLine-is_executable-co.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb055a53f1aaed6b2aa143ad6af6f29fd03883fe --- /dev/null +++ b/8335610-DiagnosticFramework-CmdLine-is_executable-co.patch @@ -0,0 +1,22 @@ +Subject: 8335610: DiagnosticFramework: CmdLine::is_executable() correction + +--- + src/hotspot/share/services/diagnosticFramework.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hotspot/share/services/diagnosticFramework.hpp b/src/hotspot/share/services/diagnosticFramework.hpp +index 8313954aa..3f5087fd1 100644 +--- a/src/hotspot/share/services/diagnosticFramework.hpp ++++ b/src/hotspot/share/services/diagnosticFramework.hpp +@@ -67,7 +67,7 @@ public: + const char* cmd_addr() const { return _cmd; } + size_t cmd_len() const { return _cmd_len; } + bool is_empty() const { return _cmd_len == 0; } +- bool is_executable() const { return is_empty() || _cmd[0] != '#'; } ++ bool is_executable() const { return !is_empty() && _cmd[0] != '#'; } + bool is_stop() const { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; } + }; + +-- +2.33.0 + diff --git a/8337982-Remove-dead-undef-assrt0n.patch b/8337982-Remove-dead-undef-assrt0n.patch new file mode 100644 index 0000000000000000000000000000000000000000..144f2711463ef0f3b9c8b6532653920147f5d520 --- /dev/null +++ b/8337982-Remove-dead-undef-assrt0n.patch @@ -0,0 +1,21 @@ +Subject: 8337982: Remove dead undef assrt0n + +--- + src/hotspot/share/memory/metaspace/blockTree.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/hotspot/share/memory/metaspace/blockTree.cpp b/src/hotspot/share/memory/metaspace/blockTree.cpp +index 934f25d84..883f7792e 100644 +--- a/src/hotspot/share/memory/metaspace/blockTree.cpp ++++ b/src/hotspot/share/memory/metaspace/blockTree.cpp +@@ -179,7 +179,6 @@ void BlockTree::verify() const { + // as many nodes as are in this tree) + _counter.check(counter); + +- #undef assrt0n + } + + void BlockTree::zap_range(MetaWord* p, size_t word_size) { +-- +2.33.0 + diff --git a/8339149-jfr_flush_event_writer-return-value-type-mis.patch b/8339149-jfr_flush_event_writer-return-value-type-mis.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5969be15335a30d58fb6af122b11f77c076aa81 --- /dev/null +++ b/8339149-jfr_flush_event_writer-return-value-type-mis.patch @@ -0,0 +1,22 @@ +Subject: 8339149: jfr_flush_event_writer - return value type mismatch + +--- + src/hotspot/share/jfr/jni/jfrJniMethod.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +index c7efe1c6a..90d74d59e 100644 +--- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp ++++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +@@ -119,7 +119,7 @@ jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass cls); + + jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls); + +-jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size); ++void JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size); + + jlong JNICALL jfr_commit(JNIEnv* env, jclass cls, jlong next_position); + +-- +2.33.0 + diff --git a/8339351-Remove-duplicate-line-in-FileMapHeader-print.patch b/8339351-Remove-duplicate-line-in-FileMapHeader-print.patch new file mode 100644 index 0000000000000000000000000000000000000000..42026d1899e1dfad6cabb539a6e63ba0671f7f98 --- /dev/null +++ b/8339351-Remove-duplicate-line-in-FileMapHeader-print.patch @@ -0,0 +1,21 @@ +Subject: 8339351: Remove duplicate line in FileMapHeader::print + +--- + src/hotspot/share/cds/filemap.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp +index 7d12e1aca..023c0762a 100644 +--- a/src/hotspot/share/cds/filemap.cpp ++++ b/src/hotspot/share/cds/filemap.cpp +@@ -278,7 +278,6 @@ void FileMapHeader::print(outputStream* st) { + st->print_cr("- core_region_alignment: " SIZE_FORMAT, _core_region_alignment); + st->print_cr("- obj_alignment: %d", _obj_alignment); + st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base)); +- st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base)); + st->print_cr("- narrow_oop_shift %d", _narrow_oop_shift); + st->print_cr("- compact_strings: %d", _compact_strings); + st->print_cr("- max_heap_size: " UINTX_FORMAT, _max_heap_size); +-- +2.33.0 + diff --git a/8352716-tz-Update-Timezone-Data-to-2025b.patch b/8352716-tz-Update-Timezone-Data-to-2025b.patch new file mode 100644 index 0000000000000000000000000000000000000000..06f702c08e9a3d8e7380a3cc520bf8b7db4517e7 --- /dev/null +++ b/8352716-tz-Update-Timezone-Data-to-2025b.patch @@ -0,0 +1,241 @@ +From ffbb19474b77e5892735ebaf0f6f734982f48ab7 Mon Sep 17 00:00:00 2001 +Date: Tue, 29 Apr 2025 14:23:11 +0800 +Subject: [PATCH] 8352716: (tz) Update Timezone Data to 2025b + +--- + src/java.base/share/data/tzdata/VERSION | 2 +- + src/java.base/share/data/tzdata/asia | 12 ++- + src/java.base/share/data/tzdata/northamerica | 9 ++ + src/java.base/share/data/tzdata/southamerica | 86 +++++++++++++++---- + src/java.base/share/data/tzdata/zone.tab | 3 +- + .../java/util/TimeZone/TimeZoneData/VERSION | 2 +- + 6 files changed, 94 insertions(+), 20 deletions(-) + +diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION +index 9c056fac3..4bd54efbc 100644 +--- a/src/java.base/share/data/tzdata/VERSION ++++ b/src/java.base/share/data/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2025a ++tzdata2025b +diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia +index b0a6fa01d..55b13134f 100644 +--- a/src/java.base/share/data/tzdata/asia ++++ b/src/java.base/share/data/tzdata/asia +@@ -1523,6 +1523,16 @@ Zone Asia/Jayapura 9:22:48 - LMT 1932 Nov + # (UIT No. 143 17.XI.1977) and not 23 September (UIT No. 141 13.IX.1977). + # UIT is the Operational Bulletin of International Telecommunication Union. + ++# From Roozbeh Pournader (2025-03-18): ++# ... the exact time of Iran's transition from +0400 to +0330 ... was Friday ++# 1357/8/19 AP=1978-11-10. Here's a newspaper clip from the Ettela'at ++# newspaper, dated 1357/8/14 AP=1978-11-05, translated from Persian ++# (at https://w.wiki/DUEY): ++# Following the government's decision about returning the official time ++# to the previous status, the spokesperson for the Ministry of Energy ++# announced today: At the hour 24 of Friday 19th of Aban (=1978-11-10), ++# the country's time will be pulled back half an hour. ++# + # From Roozbeh Pournader (2003-03-15): + # This is an English translation of what I just found (originally in Persian). + # The Gregorian dates in brackets are mine: +@@ -1650,7 +1660,7 @@ Rule Iran 2021 2022 - Sep 21 24:00 0 - + Zone Asia/Tehran 3:25:44 - LMT 1916 + 3:25:44 - TMT 1935 Jun 13 # Tehran Mean Time + 3:30 Iran %z 1977 Oct 20 24:00 +- 4:00 Iran %z 1979 ++ 4:00 Iran %z 1978 Nov 10 24:00 + 3:30 Iran %z + + +diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica +index 0a54e63be..21f178ee8 100644 +--- a/src/java.base/share/data/tzdata/northamerica ++++ b/src/java.base/share/data/tzdata/northamerica +@@ -1634,6 +1634,15 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + # For more on Orillia, see: Daubs K. Bold attempt at daylight saving + # time became a comic failure in Orillia. Toronto Star 2017-07-08. + # https://www.thestar.com/news/insight/2017/07/08/bold-attempt-at-daylight-saving-time-became-a-comic-failure-in-orillia.html ++# From Paul Eggert (2025-03-20): ++# Also see the 1912-06-17 front page of The Evening Sunbeam, ++# reproduced in: Richardson M. "Daylight saving was a confusing ++# time in Orillia" in the 2025-03-15 Orillia Matters. Richardson writes, ++# "The first Sunday after the switch was made, [DST proponent and ++# Orillia mayor William Sword] Frost walked into church an hour late. ++# This became a symbol of the downfall of daylight saving in Orillia." ++# The mayor became known as "Daylight Bill". ++# https://www.orilliamatters.com/local-news/column-daylight-saving-was-a-confusing-time-in-orillia-10377529 + + # From Mark Brader (2010-03-06): + # +diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica +index 0a5859600..ca3c33859 100644 +--- a/src/java.base/share/data/tzdata/southamerica ++++ b/src/java.base/share/data/tzdata/southamerica +@@ -1269,35 +1269,45 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 + # dates to 2014. + # DST End: last Saturday of April 2014 (Sun 27 Apr 2014 03:00 UTC) + # DST Start: first Saturday of September 2014 (Sun 07 Sep 2014 04:00 UTC) +-# http://www.diariooficial.interior.gob.cl//media/2014/02/19/do-20140219.pdf ++# From Tim Parenti (2025-03-22): ++# Decreto 307 of 2014 of the Ministry of the Interior and Public Security, ++# promulgated 2014-01-30 and published 2014-02-19: ++# https://www.diariooficial.interior.gob.cl/media/2014/02/19/do-20140219.pdf#page=1 ++# https://www.bcn.cl/leychile/navegar?idNorma=1059557 + + # From Eduardo Romero Urra (2015-03-03): + # Today has been published officially that Chile will use the DST time + # permanently until March 25 of 2017 +-# http://www.diariooficial.interior.gob.cl/media/2015/03/03/1-large.jpg +-# +-# From Paul Eggert (2015-03-03): +-# For now, assume that the extension will persist indefinitely. ++# From Tim Parenti (2025-03-22): ++# Decreto 106 of 2015 of the Ministry of the Interior and Public Security, ++# promulgated 2015-01-27 and published 2015-03-03: ++# https://www.diariooficial.interior.gob.cl/media/2015/03/03/do-20150303.pdf#page=1 ++# https://www.bcn.cl/leychile/navegar?idNorma=1075157 + + # From Juan Correa (2016-03-18): +-# The decree regarding DST has been published in today's Official Gazette: +-# http://www.diariooficial.interior.gob.cl/versiones-anteriores/do/20160318/ +-# http://www.leychile.cl/Navegar?idNorma=1088502 ++# The decree regarding DST has been published in today's Official Gazette... + # It does consider the second Saturday of May and August as the dates + # for the transition; and it lists DST dates until 2019, but I think + # this scheme will stick. +-# + # From Paul Eggert (2016-03-18): +-# For now, assume the pattern holds for the indefinite future. + # The decree says transitions occur at 24:00; in practice this appears + # to mean 24:00 mainland time, not 24:00 local time, so that Easter + # Island is always two hours behind the mainland. ++# From Tim Parenti (2025-03-22): ++# Decreto 253 of 2016 of the Ministry of the Interior and Public Security, ++# promulgated 2016-03-16 and published 2016-03-18. ++# https://www.diariooficial.interior.gob.cl/media/2016/03/18/do-20160318.pdf#page=1 ++# https://www.bcn.cl/leychile/navegar?idNorma=1088502 + + # From Juan Correa (2016-12-04): + # Magallanes region ... will keep DST (UTC -3) all year round.... + # http://www.soychile.cl/Santiago/Sociedad/2016/12/04/433428/Bachelet-firmo-el-decreto-para-establecer-un-horario-unico-para-la-Region-de-Magallanes.aspx +-# From Deborah Goldsmith (2017-01-19): +-# http://www.diariooficial.interior.gob.cl/publicaciones/2017/01/17/41660/01/1169626.pdf ++# From Tim Parenti (2025-03-22), via Deborah Goldsmith (2017-01-19): ++# Decreto 1820 of 2016 of the Ministry of the Interior and Public Security, ++# promulgated 2016-12-02 and published 2017-01-17: ++# https://www.diariooficial.interior.gob.cl/publicaciones/2017/01/17/41660/01/1169626.pdf ++# https://www.bcn.cl/leychile/Navegar?idNorma=1099217 ++# Model this as a change to standard offset effective 2016-12-04. + + # From Juan Correa (2018-08-13): + # As of moments ago, the Ministry of Energy in Chile has announced the new +@@ -1316,13 +1326,20 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 + # https://twitter.com/MinEnergia/status/1029009354001973248 + # "We will keep the new time policy unchanged for at least the next 4 years." + # So we extend the new rules on Saturdays at 24:00 mainland time indefinitely. +-# From Juan Correa (2019-02-04): +-# http://www.diariooficial.interior.gob.cl/publicaciones/2018/11/23/42212/01/1498738.pdf ++# From Tim Parenti (2025-03-22), via Juan Correa (2019-02-04): ++# Decreto 1286 of 2018 of the Ministry of the Interior and Public Security, ++# promulgated 2018-09-21 and published 2018-11-23: ++# https://www.diariooficial.interior.gob.cl/publicaciones/2018/11/23/42212/01/1498738.pdf ++# https://www.bcn.cl/leychile/Navegar?idNorma=1125760 + + # From Juan Correa (2022-04-02): + # I found there was a decree published last Thursday that will keep +-# Magallanes region to UTC -3 "indefinitely". The decree is available at ++# Magallanes region to UTC -3 "indefinitely". ++# From Tim Parenti (2025-03-22): ++# Decreto 143 of 2022 of the Ministry of the Interior and Public Security, ++# promulgated 2022-03-29 and published 2022-03-31: + # https://www.diariooficial.interior.gob.cl/publicaciones/2022/03/31/43217-B/01/2108910.pdf ++# https://www.bcn.cl/leychile/Navegar?idNorma=1174342 + + # From Juan Correa (2022-08-09): + # the Internal Affairs Ministry (Ministerio del Interior) informed DST +@@ -1331,13 +1348,36 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 + # will keep UTC -3 "indefinitely"... This is because on September 4th + # we will have a voting whether to approve a new Constitution. + # +-# From Eduardo Romero Urra (2022-08-17): ++# From Tim Parenti (2025-03-22), via Eduardo Romero Urra (2022-08-17): ++# Decreto 224 of 2022 of the Ministry of the Interior and Public Security, ++# promulgated 2022-07-14 and published 2022-08-13: + # https://www.diariooficial.interior.gob.cl/publicaciones/2022/08/13/43327/01/2172567.pdf ++# https://www.bcn.cl/leychile/navegar?idNorma=1179983 + # + # From Paul Eggert (2022-08-17): + # Although the presidential decree stops at fall 2026, assume that + # similar DST rules will continue thereafter. + ++# From Paul Eggert (2025-01-15): ++# Diario Regional Aysén's Sebastián Martel reports that 94% of Aysén ++# citizens polled in November favored changing the rules from ++# -04/-03-with-DST to -03 all year... ++# https://www.diarioregionalaysen.cl/noticia/actualidad/2024/12/presentan-decision-que-gano-la-votacion-sobre-el-cambio-del-huso-horario-en-aysen ++# ++# From Yonathan Dossow (2025-03-20): ++# [T]oday we have more confirmation of the change. [Aysén] region will keep ++# UTC-3 all year... ++# https://www.cnnchile.com/pais/region-de-aysen-mantendra-horario-de-verano-todo-el-ano_20250320/ ++# https://www.latercera.com/nacional/noticia/tras-consulta-ciudadana-region-de-aysen-mantendra-el-horario-de-verano-durante-todo-el-ano/ ++# https://x.com/min_interior/status/1902692504270672098 ++# ++# From Tim Parenti (2025-03-22), via Eduardo Romero Urra (2025-03-20): ++# Decreto 93 of 2025 of the Ministry of the Interior and Public Security, ++# promulgated 2025-03-11 and published 2025-03-20: ++# https://www.diariooficial.interior.gob.cl/publicaciones/2025/03/20/44104/01/2624263.pdf ++# https://www.bcn.cl/leychile/Navegar?idNorma=1211955 ++# Model this as a change to standard offset effective 2025-03-20. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Chile 1927 1931 - Sep 1 0:00 1:00 - + Rule Chile 1928 1932 - Apr 1 0:00 0 - +@@ -1394,6 +1434,20 @@ Zone America/Santiago -4:42:45 - LMT 1890 + -5:00 1:00 %z 1947 Mar 31 24:00 + -5:00 - %z 1947 May 21 23:00 + -4:00 Chile %z ++Zone America/Coyhaique -4:48:16 - LMT 1890 ++ -4:42:45 - SMT 1910 Jan 10 ++ -5:00 - %z 1916 Jul 1 ++ -4:42:45 - SMT 1918 Sep 10 ++ -4:00 - %z 1919 Jul 1 ++ -4:42:45 - SMT 1927 Sep 1 ++ -5:00 Chile %z 1932 Sep 1 ++ -4:00 - %z 1942 Jun 1 ++ -5:00 - %z 1942 Aug 1 ++ -4:00 - %z 1946 Aug 28 24:00 ++ -5:00 1:00 %z 1947 Mar 31 24:00 ++ -5:00 - %z 1947 May 21 23:00 ++ -4:00 Chile %z 2025 Mar 20 ++ -3:00 - %z + Zone America/Punta_Arenas -4:43:40 - LMT 1890 + -4:42:45 - SMT 1910 Jan 10 + -5:00 - %z 1916 Jul 1 +diff --git a/src/java.base/share/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab +index e7a4868c3..c8fc60104 100644 +--- a/src/java.base/share/data/tzdata/zone.tab ++++ b/src/java.base/share/data/tzdata/zone.tab +@@ -162,7 +162,8 @@ CH +4723+00832 Europe/Zurich + CI +0519-00402 Africa/Abidjan + CK -2114-15946 Pacific/Rarotonga + CL -3327-07040 America/Santiago most of Chile +-CL -5309-07055 America/Punta_Arenas Region of Magallanes ++CL -4534-07204 America/Coyhaique Aysen Region ++CL -5309-07055 America/Punta_Arenas Magallanes Region + CL -2709-10926 Pacific/Easter Easter Island + CM +0403+00942 Africa/Douala + CN +3114+12128 Asia/Shanghai Beijing Time +diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +index 5159b3786..750d9fae2 100644 +--- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION ++++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +@@ -1 +1 @@ +-tzdata2025a ++tzdata2025b +-- + diff --git a/BackPort-JDK-8336346-Fix--Wzero-as-null-pointer-cons.patch b/BackPort-JDK-8336346-Fix--Wzero-as-null-pointer-cons.patch new file mode 100644 index 0000000000000000000000000000000000000000..3115d0c287c5746fb1cea48721a45d10a1065b7c --- /dev/null +++ b/BackPort-JDK-8336346-Fix--Wzero-as-null-pointer-cons.patch @@ -0,0 +1,31 @@ +Subject: BackPort of JDK-8336346: Fix -Wzero-as-null-pointer-constant warnings in jvmciJavaClasses.cpp + +--- + src/hotspot/share/jvmci/jvmciJavaClasses.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp +index 4346c4050..94229dcb3 100644 +--- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp ++++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp +@@ -581,7 +581,7 @@ void JNIJVMCI::register_natives(JNIEnv* env) { + #define EMPTY2(x,y) + #define FIELD3(className, name, sig) FIELD2(className, name) + #define FIELD2(className, name) \ +- jfieldID JNIJVMCI::className::_##name##_field_id = 0; \ ++ jfieldID JNIJVMCI::className::_##name##_field_id = nullptr; \ + int HotSpotJVMCI::className::_##name##_offset = 0; + #define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) + #define CONSTRUCTOR(className, signature) +@@ -623,7 +623,7 @@ JVMCI_CLASSES_DO(EMPTY2, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, + void JNIJVMCI::className::check(JVMCIEnv* jvmciEnv, JVMCIObject obj, const char* field_name, jfieldID offset) { \ + assert(obj.is_non_null(), "null field access of %s.%s", #className, field_name); \ + assert(jvmciEnv->isa_##className(obj), "wrong class, " #className " expected, found %s", jvmciEnv->klass_name(obj)); \ +- assert(offset != 0, "must be valid offset"); \ ++ assert(offset != nullptr, "must be valid offset"); \ + } \ + jclass JNIJVMCI::className::_class = nullptr; + +-- +2.33.0 + diff --git a/Backport-JDK-8304484-CDS-dynamic-dumping-incorrectly.patch b/Backport-JDK-8304484-CDS-dynamic-dumping-incorrectly.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ebe2627bd215a9d35a91595a701c43bcd14c1cf --- /dev/null +++ b/Backport-JDK-8304484-CDS-dynamic-dumping-incorrectly.patch @@ -0,0 +1,22 @@ +Subject: Backport JDK-8304484 CDS dynamic dumping incorrectly leads to "Error occurred during initialization of VM" + +--- + src/hotspot/share/classfile/classLoader.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp +index 5e89673a5..e4a14d560 100644 +--- a/src/hotspot/share/classfile/classLoader.cpp ++++ b/src/hotspot/share/classfile/classLoader.cpp +@@ -445,7 +445,7 @@ bool ClassPathImageEntry::is_modules_image() const { + void ClassLoader::exit_with_path_failure(const char* error, const char* message) { + Arguments::assert_is_dumping_archive(); + tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure"); +- vm_exit_during_initialization(error, message); ++ vm_exit_during_cds_dumping(error, message); + } + #endif + +-- +2.33.0 + diff --git a/Backport-JDK-8313909-JVMCI-assert-cp-tag_at-index-.i.patch b/Backport-JDK-8313909-JVMCI-assert-cp-tag_at-index-.i.patch new file mode 100644 index 0000000000000000000000000000000000000000..52ecc8588507cd95b1a84f35347c7ea3f899ef3b --- /dev/null +++ b/Backport-JDK-8313909-JVMCI-assert-cp-tag_at-index-.i.patch @@ -0,0 +1,24 @@ +Subject: Backport JDK-8313909 [JVMCI] assert(cp->tag_at(index).is_unresolved_klass()) in lookupKlassInPool + +--- + src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +index 5b45499f9..df9f866b9 100644 +--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp ++++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +@@ -879,7 +879,9 @@ C2V_VMENTRY_NULL(jobject, lookupKlassInPool, (JNIEnv* env, jobject, ARGUMENT_PAI + } else if (tag.is_symbol()) { + symbol = cp->symbol_at(index); + } else { +- assert(cp->tag_at(index).is_unresolved_klass(), "wrong tag"); ++ if (!tag.is_unresolved_klass()) { ++ JVMCI_THROW_MSG_NULL(InternalError, err_msg("Expected %d at index %d, got %d", JVM_CONSTANT_UnresolvedClassInError, index, tag.value())); ++ } + symbol = cp->klass_name_at(index); + } + } +-- +2.33.0 + diff --git a/Backport-JDK-8315338-RISC-V-Change-flags-for-stable-.patch b/Backport-JDK-8315338-RISC-V-Change-flags-for-stable-.patch new file mode 100644 index 0000000000000000000000000000000000000000..29dfaaf6f5fc13fb6f1a079983444b5f7ad147b5 --- /dev/null +++ b/Backport-JDK-8315338-RISC-V-Change-flags-for-stable-.patch @@ -0,0 +1,29 @@ +From 845c2409581d1c2435b1f9b0eab1169649042236 Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Mon, 17 Mar 2025 16:24:36 +0800 +Subject: [PATCH] Backport JDK-8315338: RISC-V: Change flags for stable + extensions to non-experimental + + +diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp +index ce572fd9a4d..53c4f2c2842 100644 +--- a/src/hotspot/cpu/riscv/globals_riscv.hpp ++++ b/src/hotspot/cpu/riscv/globals_riscv.hpp +@@ -101,10 +101,10 @@ define_pd_global(intx, InlineSmallCode, 1000); + product(bool, UseRVA20U64, true, "Use RVA20U64 profile") \ + product(bool, UseRVC, false, "Use RVC instructions") \ + product(bool, UseRVA22U64, false, EXPERIMENTAL, "Use RVA22U64 profile") \ +- product(bool, UseRVV, false, EXPERIMENTAL, "Use RVV instructions") \ +- product(bool, UseZba, false, EXPERIMENTAL, "Use Zba instructions") \ +- product(bool, UseZbb, false, EXPERIMENTAL, "Use Zbb instructions") \ +- product(bool, UseZbs, false, EXPERIMENTAL, "Use Zbs instructions") \ ++ product(bool, UseRVV, false, "Use RVV instructions") \ ++ product(bool, UseZba, false, "Use Zba instructions") \ ++ product(bool, UseZbb, false, "Use Zbb instructions") \ ++ product(bool, UseZbs, false, "Use Zbs instructions") \ + product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \ + product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \ + product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \ +-- +2.34.1 + diff --git a/Backport-JDK-8320308-C2-compilation-crashes-in-Libra.patch b/Backport-JDK-8320308-C2-compilation-crashes-in-Libra.patch new file mode 100644 index 0000000000000000000000000000000000000000..88203a960b22bc329a08dc0b338bd3d356f676da --- /dev/null +++ b/Backport-JDK-8320308-C2-compilation-crashes-in-Libra.patch @@ -0,0 +1,161 @@ +Subject: Backport JDK-8320308 C2 compilation crashes in LibraryCallKit::inline_unsafe_access + +--- + src/hotspot/share/opto/library_call.cpp | 7 +- + .../TestUnsafeArrayAccessWithNullBase.java | 113 ++++++++++++++++++ + 2 files changed, 117 insertions(+), 3 deletions(-) + create mode 100644 test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java + +diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp +index af2ea6095..3ef0098c4 100644 +--- a/src/hotspot/share/opto/library_call.cpp ++++ b/src/hotspot/share/opto/library_call.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1999, 2024, 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 +@@ -2004,7 +2004,7 @@ LibraryCallKit::classify_unsafe_addr(Node* &base, Node* &offset, BasicType type) + if (base_type == nullptr) { + // Unknown type. + return Type::AnyPtr; +- } else if (base_type == TypePtr::NULL_PTR) { ++ } else if (_gvn.type(base->uncast()) == TypePtr::NULL_PTR) { + // Since this is a null+long form, we have to switch to a rawptr. + base = _gvn.transform(new CastX2PNode(offset)); + offset = MakeConX(0); +@@ -2322,8 +2322,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c + SafePointNode* old_map = clone_map(); + + Node* adr = make_unsafe_address(base, offset, type, kind == Relaxed); ++ assert(!stopped(), "Inlining of unsafe access failed: address construction stopped unexpectedly"); + +- if (_gvn.type(base)->isa_ptr() == TypePtr::NULL_PTR) { ++ if (_gvn.type(base->uncast())->isa_ptr() == TypePtr::NULL_PTR) { + if (type != T_OBJECT) { + decorators |= IN_NATIVE; // off-heap primitive access + } else { +diff --git a/test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java b/test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java +new file mode 100644 +index 000000000..28eb4f3c1 +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java +@@ -0,0 +1,113 @@ ++/* ++ * Copyright (c) 2024, 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. ++ */ ++ ++/** ++ * @test ++ * @bug 8320308 ++ * @summary Unsafe::getShortUnaligned with base null hidden behind CheckCastPP nodes ++ * @library /test/lib ++ * @modules java.base/jdk.internal.misc ++ * @run main/othervm -Xbatch -XX:CompileCommand=quiet -XX:TypeProfileLevel=222 ++ * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline ++ * -XX:CompileCommand=compileonly,compiler.parsing.TestUnsafeArrayAccessWithNullBase::test* ++ * -XX:-TieredCompilation compiler.parsing.TestUnsafeArrayAccessWithNullBase ++ * @run main compiler.parsing.TestUnsafeArrayAccessWithNullBase ++ */ ++ ++package compiler.parsing; ++ ++import java.lang.reflect.*; ++import jdk.internal.misc.Unsafe; ++ ++public class TestUnsafeArrayAccessWithNullBase { ++ ++ /* ++ Trigger bug when handling Unsafe.getShortUnaligned with null checks and inlined methods. ++ The bug appears when the method is incrementally inlined and optimized based on the argument profile information. ++ ++ Warmup Phase: By warming up with non-null values, the argument profile for the helper methods records non-null types. ++ - insert CheckCastPP: speculative=byte[int:>=0] for return of getSmall/getLarge ++ - insert CheckCastPP: speculative=byte[int:>=0] for argument `Object array` in helperSmall/helperLarge ++ Trigger Phase: Calling test causes LibraryCallKit::inline_unsafe_access(..) for Unsafe::getShortUnaligned to fail: ++ Reason: UNSAFE.getShortUnaligned(array, offset) is called with array=null, ++ but ConP null is now hidden by two CheckCastPP with speculative=byte[int:>=0] in the graph ++ */ ++ ++ private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ ++ private static final Object byteArray = new byte[1_050_000]; ++ ++ public static Object getLarge(boolean useNull) { ++ return useNull ? null : byteArray; ++ } ++ ++ public static Object getSmall(boolean useNull) { ++ return useNull ? null : new byte[10]; ++ } ++ ++ // use a helper to delay inlining of UNSAFE.getShortUnaligned ++ public static int helperLarge(Object array, boolean run) { ++ // offset >= os::vm_page_size(): LibraryCallKit::classify_unsafe_addr returns Type::AnyPtr ++ return run ? UNSAFE.getShortUnaligned(array, 1_049_000) : 0; // after warmup CheckCastPP: speculative=byte[int:>=0] ++ } ++ ++ public static int accessLargeArray(boolean useNull, boolean run) { ++ Object array = getLarge(useNull); // after warmup CheckCastPP: speculative=byte[int:>=0] ++ // getLarge() ensures null is only visible after helperLarge was (incrementally) inlined ++ return helperLarge(array, run); ++ } ++ ++ // use a helper to delay inlining of UNSAFE.getShortUnaligned ++ // warmup adds argument profile information for array: CheckCastPP with type non null ++ public static int helperSmall(Object array, boolean run) { ++ // 0 <= offset < os::vm_page_size(): LibraryCallKit::classify_unsafe_addr returns Type::OopPtr ++ return run ? UNSAFE.getShortUnaligned(array, 1) : 0; // after warmup CheckCastPP: speculative=byte[int:>=0] ++ } ++ ++ public static int accessSmallArray(boolean useNull, boolean run) { ++ Object array = getSmall(useNull); // after warmup CheckCastPP: speculative=byte[int:>=0] ++ return helperSmall(array, run); ++ } ++ ++ public static int test1(boolean run) { ++ return accessLargeArray(true, run); ++ } ++ ++ public static int test2(boolean run) { ++ return accessSmallArray(true, run); ++ } ++ ++ public static void main(String[] args) { ++ // Warmup to collect speculative types ++ for (int i = 0; i < 10_000; i++) { ++ accessLargeArray(false, true); ++ accessSmallArray(false, true); ++ } ++ ++ // Trigger Compilation ++ for (int i = 0; i < 10_000; ++i) { ++ test1(false); ++ test2(false); ++ } ++ } ++} +-- +2.33.0 + diff --git a/Backport-JDK-8322812-Manpage-for-jcmd-is-missing-JFR.patch b/Backport-JDK-8322812-Manpage-for-jcmd-is-missing-JFR.patch new file mode 100644 index 0000000000000000000000000000000000000000..544e826de204fcf76e44ba9ad13fd4a375177387 --- /dev/null +++ b/Backport-JDK-8322812-Manpage-for-jcmd-is-missing-JFR.patch @@ -0,0 +1,84 @@ +Subject: Backport JDK-8322812 Manpage for jcmd is missing JFR.view command + +--- + src/jdk.jcmd/share/man/jcmd.1 | 53 +++++++++++++++++++++++++++++++++-- + 1 file changed, 51 insertions(+), 2 deletions(-) + +diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 +index 27f5ee5eb..f3e254be9 100644 +--- a/src/jdk.jcmd/share/man/jcmd.1 ++++ b/src/jdk.jcmd/share/man/jcmd.1 +@@ -1,4 +1,4 @@ +-.\" Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. ++.\" Copyright (c) 2012, 2024, 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 +@@ -35,7 +35,7 @@ + . ftr VB CB + . ftr VBI CBI + .\} +-.TH "JCMD" "1" "2023" "JDK 21" "JDK Commands" ++.TH "JCMD" "1" "2025" "JDK 24-ea" "JDK Commands" + .hy + .SH NAME + .PP +@@ -625,6 +625,55 @@ If no path is provided, the data from the recording is discarded. + value) + .RE + .TP ++\f[V]JFR.view\f[R] [\f[I]options\f[R]] ++Display event data in predefined views. ++.RS ++.PP ++Impact: Medium ++.PP ++\f[B]Note:\f[R] ++.PP ++The \f[I]options\f[R] must be specified using either \f[I]key\f[R] or ++\f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. ++If no parameters are entered, then a list of available views are ++displayed. ++.PP ++\f[I]options\f[R]: ++.IP \[bu] 2 ++\f[V]cell-height\f[R]: (Optional) Maximum number of rows in a table ++cell. ++(INT, default value depends on the view) ++.IP \[bu] 2 ++\f[V]maxage\f[R]: (Optional) Length of time for the view to span. ++(INT followed by \[aq]s\[aq] for seconds \[aq]m\[aq] for minutes or ++\[aq]h\[aq] for hours, default value is 10m) ++.IP \[bu] 2 ++\f[V]maxsize\f[R]: (Optional) Maximum size for the view to span in bytes ++if one of the following suffixes is not used: \[aq]m\[aq] or \[aq]M\[aq] ++for megabytes OR \[aq]g\[aq] or \[aq]G\[aq] for gigabytes. ++(STRING, default value is 32MB) ++.IP \[bu] 2 ++\f[V]truncate\f[R]: (Optional) Maximum number of rows in a table cell. ++(INT, default value depends on the view) ++.IP \[bu] 2 ++\f[V]verbose\f[R]: (Optional) Displays the query that makes up the view. ++(BOOLEAN, default value is false) ++.IP \[bu] 2 ++\f[V]width\f[R]: (Optional) The width of the view in characters. ++(INT, default value depends on the view) ++.PP ++\f[I]arguments\f[R]: ++.IP \[bu] 2 ++\f[V]view\f[R]: Name of the view or event type to display. ++Use \f[V]help JFR.view\f[R] to see a list of available views. ++(STRING, no default value) ++.PP ++The view parameter can be an event type name. ++Use \f[V]JFR.view types\f[R] to see a list. ++To display all views, use \f[V]JFR.view all-views\f[R]. ++To display all events, use \f[V]JFR.view all-events\f[R]. ++.RE ++.TP + \f[V]JVMTI.agent_load\f[R] [\f[I]arguments\f[R]] + Loads JVMTI native agent. + .RS +-- +2.33.0 + diff --git a/Backport-JDK-8323699-MessageFormat.toPattern-generat.patch b/Backport-JDK-8323699-MessageFormat.toPattern-generat.patch new file mode 100644 index 0000000000000000000000000000000000000000..174cac22b5f2a2b51d3a0e41dc9674fc7b2428bf --- /dev/null +++ b/Backport-JDK-8323699-MessageFormat.toPattern-generat.patch @@ -0,0 +1,566 @@ +Subject: Backport JDK-8323699: MessageFormat.toPattern() generates non-equivalent MessageFormat pattern + +--- + .../classes/java/text/MessageFormat.java | 76 +++- + .../MessageFormatToPatternTest.java | 364 ++++++++++++++++++ + .../MessageFormatsByArgumentIndex.java | 8 +- + .../MessageFormat/MessageRegression.java | 6 +- + 4 files changed, 442 insertions(+), 12 deletions(-) + create mode 100644 test/jdk/java/text/Format/MessageFormat/MessageFormatToPatternTest.java + +diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java +index 28d1474ad..659838c8a 100644 +--- a/src/java.base/share/classes/java/text/MessageFormat.java ++++ b/src/java.base/share/classes/java/text/MessageFormat.java +@@ -548,6 +548,11 @@ public class MessageFormat extends Format { + * The string is constructed from internal information and therefore + * does not necessarily equal the previously applied pattern. + * ++ * @implSpec The implementation in {@link MessageFormat} returns a ++ * string that, when passed to a {@code MessageFormat()} constructor ++ * or {@link #applyPattern applyPattern()}, produces an instance that ++ * is semantically equivalent to this instance. ++ * + * @return a pattern representing the current state of the message format + */ + public String toPattern() { +@@ -559,6 +564,7 @@ public class MessageFormat extends Format { + lastOffset = offsets[i]; + result.append('{').append(argumentNumbers[i]); + Format fmt = formats[i]; ++ String subformatPattern = null; + if (fmt == null) { + // do nothing, string format + } else if (fmt instanceof NumberFormat) { +@@ -571,10 +577,12 @@ public class MessageFormat extends Format { + } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) { + result.append(",number,integer"); + } else { +- if (fmt instanceof DecimalFormat) { +- result.append(",number,").append(((DecimalFormat)fmt).toPattern()); +- } else if (fmt instanceof ChoiceFormat) { +- result.append(",choice,").append(((ChoiceFormat)fmt).toPattern()); ++ if (fmt instanceof DecimalFormat dfmt) { ++ result.append(",number"); ++ subformatPattern = dfmt.toPattern(); ++ } else if (fmt instanceof ChoiceFormat cfmt) { ++ result.append(",choice"); ++ subformatPattern = cfmt.toPattern(); + } else { + // UNKNOWN + } +@@ -596,8 +604,9 @@ public class MessageFormat extends Format { + } + } + if (index >= DATE_TIME_MODIFIERS.length) { +- if (fmt instanceof SimpleDateFormat) { +- result.append(",date,").append(((SimpleDateFormat)fmt).toPattern()); ++ if (fmt instanceof SimpleDateFormat sdfmt) { ++ result.append(",date"); ++ subformatPattern = sdfmt.toPattern(); + } else { + // UNKNOWN + } +@@ -607,6 +616,14 @@ public class MessageFormat extends Format { + } else { + //result.append(", unknown"); + } ++ if (subformatPattern != null) { ++ result.append(','); ++ ++ // The subformat pattern comes already quoted, but only for those characters that are ++ // special to the subformat. Therefore, we may need to quote additional characters. ++ // The ones we care about at the MessageFormat level are '{' and '}'. ++ copyAndQuoteBraces(subformatPattern, result); ++ } + result.append('}'); + } + copyAndFixQuotes(pattern, lastOffset, pattern.length(), result); +@@ -1624,6 +1641,53 @@ public class MessageFormat extends Format { + } + } + ++ // Copy the text, but add quotes around any quotables that aren't already quoted ++ private static void copyAndQuoteBraces(String source, StringBuilder target) { ++ ++ // Analyze existing string for already quoted and newly quotable characters ++ record Qchar(char ch, boolean quoted) { }; ++ ArrayList qchars = new ArrayList<>(); ++ boolean quoted = false; ++ boolean anyChangeNeeded = false; ++ for (int i = 0; i < source.length(); i++) { ++ char ch = source.charAt(i); ++ if (ch == '\'') { ++ if (i + 1 < source.length() && source.charAt(i + 1) == '\'') { ++ qchars.add(new Qchar('\'', quoted)); ++ i++; ++ } else { ++ quoted = !quoted; ++ } ++ } else { ++ boolean quotable = ch == '{' || ch == '}'; ++ anyChangeNeeded |= quotable && !quoted; ++ qchars.add(new Qchar(ch, quoted || quotable)); ++ } ++ } ++ ++ // Was any change needed? ++ if (!anyChangeNeeded) { ++ target.append(source); ++ return; ++ } ++ ++ // Build new string, automatically consolidating adjacent runs of quoted chars ++ quoted = false; ++ for (Qchar qchar : qchars) { ++ char ch = qchar.ch; ++ if (ch == '\'') { ++ target.append(ch); // doubling works whether quoted or not ++ } else if (qchar.quoted() != quoted) { ++ target.append('\''); ++ quoted = qchar.quoted(); ++ } ++ target.append(ch); ++ } ++ if (quoted) { ++ target.append('\''); ++ } ++ } ++ + /** + * After reading an object from the input stream, do a simple verification + * to maintain class invariants. +diff --git a/test/jdk/java/text/Format/MessageFormat/MessageFormatToPatternTest.java b/test/jdk/java/text/Format/MessageFormat/MessageFormatToPatternTest.java +new file mode 100644 +index 000000000..020bc8033 +--- /dev/null ++++ b/test/jdk/java/text/Format/MessageFormat/MessageFormatToPatternTest.java +@@ -0,0 +1,364 @@ ++/* ++ * Copyright (c) 2024, 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. ++ */ ++ ++/* ++ * @test ++ * @summary Verify that MessageFormat.toPattern() properly escapes special curly braces ++ * @bug 8323699 ++ * @run junit MessageFormatToPatternTest ++ */ ++ ++import java.text.ChoiceFormat; ++import java.text.DateFormat; ++import java.text.DecimalFormat; ++import java.text.Format; ++import java.text.MessageFormat; ++import java.text.NumberFormat; ++import java.text.SimpleDateFormat; ++import java.util.ArrayList; ++import java.util.Date; ++import java.util.Locale; ++import java.util.Random; ++import java.util.stream.Stream; ++ ++import org.junit.jupiter.api.AfterAll; ++import org.junit.jupiter.api.BeforeAll; ++import org.junit.jupiter.api.Test; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.Arguments; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++public class MessageFormatToPatternTest { ++ ++ private static final int NUM_RANDOM_TEST_CASES = 1000; ++ ++ // Max levels of nesting of ChoiceFormats inside MessageFormats ++ private static final int MAX_FORMAT_NESTING = 3; ++ ++ private static Locale savedLocale; ++ private static long randomSeed; // set this to a non-zero value for reproducibility ++ private static Random random; ++ private static boolean spitSeed; ++ private static int textCount; ++ ++// Setup & Teardown ++ ++ @BeforeAll ++ public static void setup() { ++ savedLocale = Locale.getDefault(); ++ Locale.setDefault(Locale.US); ++ if (randomSeed == 0) ++ randomSeed = new Random().nextLong(); ++ random = new Random(randomSeed); ++ } ++ ++ @AfterAll ++ public static void teardown() { ++ Locale.setDefault(savedLocale); ++ } ++ ++// Tests ++ ++ // Test expected output when given a MessageFormat pattern string and value 1.23 ++ @ParameterizedTest ++ @MethodSource("generateOutputTestCases") ++ public void testOutput(String pattern, String expected) { ++ ++ // Test we get the expected output ++ MessageFormat format = new MessageFormat(pattern); ++ String actual = format.format(new Object[] { 1.23 }); ++ assertEquals(expected, actual); ++ ++ // Test round trip as well ++ testRoundTrip(format); ++ } ++ ++ public static Stream generateOutputTestCases() { ++ return Stream.of( ++ ++ // This is the test case from JDK-8323699 ++ Arguments.of("{0,choice,0.0#option A: {0}|1.0#option B: {0}'}'}", "option B: 1.23}"), ++ Arguments.of("{0,choice,0.0#option A: {0}|2.0#option B: {0}'}'}", "option A: 1.23"), ++ ++ // A few more test cases from the PR#17416 discussion ++ Arguments.of("Test: {0,number,foo'{'#.00}", "Test: foo{1.23"), ++ Arguments.of("Test: {0,number,foo'}'#.00}", "Test: foo}1.23"), ++ Arguments.of("{0,number,' abc }'' ' 0.00}", " abc }' 1.23"), ++ Arguments.of("Wayne ''The Great One'' Gretsky", "Wayne 'The Great One' Gretsky"), ++ Arguments.of("'Wayne ''The Great One'' Gretsky'", "Wayne 'The Great One' Gretsky"), ++ Arguments.of("{0,choice,0.0#'''{''curly''}'' braces'}", "{curly} braces"), ++ Arguments.of("{0,choice,0.0#''{''curly''}'' braces}", "{curly} braces"), ++ Arguments.of("{0,choice,0.0#'{0,choice,0.0#''{0,choice,0.0#''''{0,choice,0.0#foo}''''}''}'}", "foo"), ++ ++ // Absurd double quote examples ++ Arguments.of("Foo '}''''''''}' {0,number,bar'}' '}' } baz ", "Foo }''''} bar} } 1 baz "), ++ Arguments.of("'''}''{'''}''''}'", "'}'{'}''}"), ++ ++ // An absurdly complicated example ++ Arguments.of("{0,choice,0.0#text2887 [] '{'1,date,YYYY-MM-DD'}' text2888 [''*'']|1.0#found|2.0#'text2901 [oog'')!''] {2,choice,0.0#''text2897 ['''']''''wq1Q] {2,choice,0.0#''''text2891 [s''''''''&''''''''] {0,number,#0.##} text2892 [8''''''''|$'''''''''''''''''''''''']''''|1.0#''''text2893 [] {0,number,#0.##} text2894 [S'''''''']'''''''']''''|2.0#text2895 [''''''''.''''''''eB] {1,date,YYYY-MM-DD} text2896 [9Y]} text2898 []''|1.0#''text2899 [xk7] {0,number,#0.##} text2900 []''} text2902 [7'':$)''O]'}{0,choice,0.0#'text2903 [] {0,number,#0.##} text2904 [S'':'']'|1.0#'me'}", "foundme") ++ ); ++ } ++ ++ // Go roundrip from MessageFormat -> pattern string -> MessageFormat and verify equivalence ++ @ParameterizedTest ++ @MethodSource("generateRoundTripTestCases") ++ public void testRoundTrip(MessageFormat format1) { ++ ++ // Prepare MessageFormat argument ++ Object[] args = new Object[] { ++ 8.5, // argument for DecimalFormat ++ new Date(1705502102677L), // argument for SimpleDateFormat ++ random.nextInt(6) // argument for ChoiceFormat ++ }; ++ ++ String pattern1 = null; ++ String result1 = null; ++ String pattern2 = null; ++ String result2 = null; ++ try { ++ ++ // Format using the given MessageFormat ++ pattern1 = format1.toPattern(); ++ result1 = format1.format(args); ++ ++ // Round-trip via toPattern() and repeat ++ MessageFormat format2 = new MessageFormat(pattern1); ++ pattern2 = format2.toPattern(); ++ result2 = format2.format(args); ++ ++ // Check equivalence ++ assertEquals(result1, result2); ++ assertEquals(pattern1, pattern2); ++ ++ // Debug ++ //showRoundTrip(format1, pattern1, result1, pattern2, result2); ++ } catch (RuntimeException | Error e) { ++ System.out.println(String.format("%n********** FAILURE **********%n")); ++ System.out.println(String.format("%s%n", e)); ++ if (!spitSeed) { ++ System.out.println(String.format("*** Random seed was 0x%016xL%n", randomSeed)); ++ spitSeed = true; ++ } ++ showRoundTrip(format1, pattern1, result1, pattern2, result2); ++ throw e; ++ } ++ } ++ ++ public static Stream generateRoundTripTestCases() { ++ final ArrayList argList = new ArrayList<>(); ++ for (int i = 0; i < NUM_RANDOM_TEST_CASES; i++) ++ argList.add(Arguments.of(randomFormat())); ++ return argList.stream(); ++ } ++ ++ // Generate a "random" MessageFormat. We do this by creating a MessageFormat with "{0}" placeholders ++ // and then substituting in random DecimalFormat, DateFormat, and ChoiceFormat subformats. The goal here ++ // is to avoid using pattern strings to construct formats, because they're what we're trying to check. ++ private static MessageFormat randomFormat() { ++ ++ // Create a temporary MessageFormat containing "{0}" placeholders and random text ++ StringBuilder tempPattern = new StringBuilder(); ++ int numParts = random.nextInt(3) + 1; ++ for (int i = 0; i < numParts; i++) { ++ if (random.nextBoolean()) ++ tempPattern.append("{0}"); // temporary placeholder for a subformat ++ else ++ tempPattern.append(quoteText(randomText())); ++ } ++ ++ // Replace all the "{0}" placeholders with random subformats ++ MessageFormat format = new MessageFormat(tempPattern.toString()); ++ Format[] formats = format.getFormats(); ++ for (int i = 0; i < formats.length; i++) ++ formats[i] = randomSubFormat(0); ++ format.setFormats(formats); ++ ++ // Done ++ return format; ++ } ++ ++ // Generate some random text ++ private static String randomText() { ++ StringBuilder buf = new StringBuilder(); ++ int length = random.nextInt(6); ++ for (int i = 0; i < length; i++) { ++ char ch = (char)(0x20 + random.nextInt(0x5f)); ++ buf.append(ch); ++ } ++ return buf.toString(); ++ } ++ ++ // Quote non-alphanumeric characters in the given plain text ++ private static String quoteText(String string) { ++ StringBuilder buf = new StringBuilder(); ++ boolean quoted = false; ++ for (int i = 0; i < string.length(); i++) { ++ char ch = string.charAt(i); ++ if (ch == '\'') ++ buf.append("''"); ++ else if (!(ch == ' ' || Character.isLetter(ch) || Character.isDigit(ch))) { ++ if (!quoted) { ++ buf.append('\''); ++ quoted = true; ++ } ++ buf.append(ch); ++ } else { ++ if (quoted) { ++ buf.append('\''); ++ quoted = false; ++ } ++ buf.append(ch); ++ } ++ } ++ if (quoted) ++ buf.append('\''); ++ return buf.toString(); ++ } ++ ++ // Create a random subformat for a MessageFormat ++ private static Format randomSubFormat(int nesting) { ++ int which; ++ if (nesting >= MAX_FORMAT_NESTING) ++ which = random.nextInt(2); // no more recursion ++ else ++ which = random.nextInt(3); ++ switch (which) { ++ case 0: ++ return new DecimalFormat("#.##"); ++ case 1: ++ return new SimpleDateFormat("YYYY-MM-DD"); ++ default: ++ int numChoices = random.nextInt(3) + 1; ++ assert numChoices > 0; ++ final double[] limits = new double[numChoices]; ++ final String[] formats = new String[numChoices]; ++ for (int i = 0; i < limits.length; i++) { ++ limits[i] = (double)i; ++ formats[i] = randomMessageFormatContaining(randomSubFormat(nesting + 1)); ++ } ++ return new ChoiceFormat(limits, formats); ++ } ++ } ++ ++ // Create a MessageFormat pattern string that includes the given Format as a subformat. ++ // The result will be one option in a ChoiceFormat which is nested in an outer MessageFormat. ++ // A ChoiceFormat option string is just a plain string; it's only when that plain string ++ // bubbles up to a containing MessageFormat that it gets interpreted as a MessageFormat string, ++ // and that only happens if the option string contains a '{' character. That will always ++ // be the case for the strings returned by this method of course. ++ private static String randomMessageFormatContaining(Format format) { ++ String beforeText = quoteText(randomText().replaceAll("\\{", "")); // avoid invalid MessageFormat syntax ++ String afterText = quoteText(randomText().replaceAll("\\{", "")); // avoid invalid MessageFormat syntax ++ String middleText; ++ if (format instanceof DecimalFormat dfmt) ++ middleText = String.format("{0,number,%s}", dfmt.toPattern()); ++ else if (format instanceof SimpleDateFormat sdfmt) ++ middleText = String.format("{1,date,%s}", sdfmt.toPattern()); ++ else if (format instanceof ChoiceFormat cfmt) ++ middleText = String.format("{2,choice,%s}", cfmt.toPattern()); ++ else ++ throw new RuntimeException("internal error"); ++ return String.format("text%d [%s] %s text%d [%s]", ++textCount, beforeText, middleText, ++textCount, afterText); ++ } ++ ++// Debug printing ++ ++ private void showRoundTrip(MessageFormat format1, String pattern1, String result1, String pattern2, String result2) { ++ print(0, format1); ++ System.out.println(); ++ if (pattern1 != null) ++ System.out.println(String.format(" pattern1 = %s", javaLiteral(pattern1))); ++ if (result1 != null) ++ System.out.println(String.format(" result1 = %s", javaLiteral(result1))); ++ if (pattern2 != null) ++ System.out.println(String.format(" pattern2 = %s", javaLiteral(pattern2))); ++ if (result2 != null) ++ System.out.println(String.format(" result2 = %s", javaLiteral(result2))); ++ System.out.println(); ++ } ++ ++ private static void print(int depth, Object format) { ++ if (format == null) ++ return; ++ if (format instanceof String) ++ System.out.println(String.format("%s- %s", indent(depth), javaLiteral((String)format))); ++ else if (format instanceof MessageFormat) ++ print(depth, (MessageFormat)format); ++ else if (format instanceof DecimalFormat) ++ print(depth, (DecimalFormat)format); ++ else if (format instanceof SimpleDateFormat) ++ print(depth, (SimpleDateFormat)format); ++ else if (format instanceof ChoiceFormat) ++ print(depth, (ChoiceFormat)format); ++ else ++ throw new RuntimeException("internal error: " + format.getClass()); ++ } ++ ++ private static void print(int depth, MessageFormat format) { ++ System.out.println(String.format("%s- %s: %s", indent(depth), "MessageFormat", javaLiteral(format.toPattern()))); ++ for (Format subformat : format.getFormats()) ++ print(depth + 1, subformat); ++ } ++ ++ private static void print(int depth, DecimalFormat format) { ++ System.out.println(String.format("%s- %s: %s", indent(depth), "DecimalFormat", javaLiteral(format.toPattern()))); ++ } ++ ++ private static void print(int depth, SimpleDateFormat format) { ++ System.out.println(String.format("%s- %s: %s", indent(depth), "SimpleDateFormat", javaLiteral(format.toPattern()))); ++ } ++ ++ private static void print(int depth, ChoiceFormat format) { ++ System.out.println(String.format("%s- %s: %s", indent(depth), "ChoiceFormat", javaLiteral(format.toPattern()))); ++ for (Object subformat : format.getFormats()) ++ print(depth + 1, subformat); ++ } ++ ++ private static String indent(int depth) { ++ StringBuilder buf = new StringBuilder(); ++ for (int i = 0; i < depth; i++) ++ buf.append(" "); ++ return buf.toString(); ++ } ++ ++ // Print a Java string in double quotes so it looks like a String literal (for easy pasting into jshell) ++ private static String javaLiteral(String string) { ++ StringBuilder buf = new StringBuilder(); ++ buf.append('"'); ++ for (int i = 0; i < string.length(); i++) { ++ char ch = string.charAt(i); ++ switch (ch) { ++ case '"': ++ case '\\': ++ buf.append('\\'); ++ // FALLTHROUGH ++ default: ++ buf.append(ch); ++ break; ++ } ++ } ++ return buf.append('"').toString(); ++ } ++} +diff --git a/test/jdk/java/text/Format/MessageFormat/MessageFormatsByArgumentIndex.java b/test/jdk/java/text/Format/MessageFormat/MessageFormatsByArgumentIndex.java +index 1d69258f6..b82d566d3 100644 +--- a/test/jdk/java/text/Format/MessageFormat/MessageFormatsByArgumentIndex.java ++++ b/test/jdk/java/text/Format/MessageFormat/MessageFormatsByArgumentIndex.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2000, 2024, 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 +@@ -35,6 +35,7 @@ import java.text.NumberFormat; + public class MessageFormatsByArgumentIndex { + + private static String choicePattern = "0.0#are no files|1.0#is one file|1.0 JFR.start filename=dump.jfr + $ jcmd JFR.start filename=%s + $ jcmd JFR.start dumponexit=true +- $ jcmd JFR.start maxage=1h,maxsize=1000M ++ $ jcmd JFR.start maxage=1h maxsize=1000M + $ jcmd JFR.start settings=profile +- $ jcmd JFR.start delay=5m,settings=my.jfc ++ $ jcmd JFR.start delay=5m settings=my.jfc + $ jcmd JFR.start gc=high method-profiling=high + $ jcmd JFR.start jdk.JavaMonitorEnter#threshold=1ms + $ jcmd JFR.start +HelloWorld#enabled=true +HelloWorld#stackTrace=true +-- +2.33.0 + diff --git a/Backport-JDK-8326957-Implement-JEP-474-ZGC-Generatio.patch b/Backport-JDK-8326957-Implement-JEP-474-ZGC-Generatio.patch new file mode 100644 index 0000000000000000000000000000000000000000..1bc34960686834afaf3bf3ea4f4b027f0af1e15c --- /dev/null +++ b/Backport-JDK-8326957-Implement-JEP-474-ZGC-Generatio.patch @@ -0,0 +1,214 @@ +Subject: Backport JDK-8326957 Implement JEP 474: ZGC: Generational Mode by Default + +--- + src/hotspot/share/gc/shared/gc_globals.hpp | 4 +- + src/hotspot/share/gc/x/xArguments.cpp | 2 + + src/hotspot/share/gc/x/xInitialize.cpp | 2 +- + src/hotspot/share/runtime/arguments.cpp | 3 +- + test/hotspot/jtreg/gc/x/TestDeprecated.java | 50 ++++++++++++++++++ + test/hotspot/jtreg/gc/z/TestDefault.java | 51 +++++++++++++++++++ + .../CommandLine/VMDeprecatedOptions.java | 3 +- + 7 files changed, 110 insertions(+), 5 deletions(-) + create mode 100644 test/hotspot/jtreg/gc/x/TestDeprecated.java + create mode 100644 test/hotspot/jtreg/gc/z/TestDefault.java + +diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp +index 5d7202685..8e51632bd 100644 +--- a/src/hotspot/share/gc/shared/gc_globals.hpp ++++ b/src/hotspot/share/gc/shared/gc_globals.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2024, 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 +@@ -125,7 +125,7 @@ + product(bool, UseZGC, false, \ + "Use the Z garbage collector") \ + \ +- product(bool, ZGenerational, false, \ ++ product(bool, ZGenerational, true, \ + "Use the generational version of ZGC") \ + \ + product(bool, UseShenandoahGC, false, \ +diff --git a/src/hotspot/share/gc/x/xArguments.cpp b/src/hotspot/share/gc/x/xArguments.cpp +index 60e78d2c7..13cb302d1 100644 +--- a/src/hotspot/share/gc/x/xArguments.cpp ++++ b/src/hotspot/share/gc/x/xArguments.cpp +@@ -42,6 +42,8 @@ void XArguments::initialize_heap_flags_and_sizes() { + } + + void XArguments::initialize() { ++ warning("Non-generational ZGC is deprecated."); ++ + // Check mark stack size + const size_t mark_stack_space_limit = XAddressSpaceLimit::mark_stack(); + if (ZMarkStackSpaceLimit > mark_stack_space_limit) { +diff --git a/src/hotspot/share/gc/x/xInitialize.cpp b/src/hotspot/share/gc/x/xInitialize.cpp +index 01b79f3ff..156be1797 100644 +--- a/src/hotspot/share/gc/x/xInitialize.cpp ++++ b/src/hotspot/share/gc/x/xInitialize.cpp +@@ -41,7 +41,7 @@ XInitialize::XInitialize(XBarrierSet* barrier_set) { + log_info(gc, init)("Version: %s (%s)", + VM_Version::vm_release(), + VM_Version::jdk_debug_level()); +- log_info(gc, init)("Using legacy single-generation mode"); ++ log_info(gc, init)("Using deprecated non-generational mode"); + + // Early initialization + XAddress::initialize(); +diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp +index 720a0e9ba..9b8e5aa87 100644 +--- a/src/hotspot/share/runtime/arguments.cpp ++++ b/src/hotspot/share/runtime/arguments.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2024, 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 +@@ -500,6 +500,7 @@ static SpecialFlag const special_jvm_flags[] = { + { "InitialRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() }, + { "AllowRedefinitionToAddDeleteMethods", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() }, + { "FlightRecorder", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() }, ++ { "ZGenerational", JDK_Version::jdk(21), JDK_Version::undefined(), JDK_Version::undefined() }, + { "DumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, + { "DynamicDumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, + { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, +diff --git a/test/hotspot/jtreg/gc/x/TestDeprecated.java b/test/hotspot/jtreg/gc/x/TestDeprecated.java +new file mode 100644 +index 000000000..17e2e70f4 +--- /dev/null ++++ b/test/hotspot/jtreg/gc/x/TestDeprecated.java +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2024, 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. ++ */ ++ ++package gc.x; ++ ++/* ++ * @test TestDeprecated ++ * @requires vm.gc.ZSinglegen ++ * @summary Test ZGenerational Deprecated ++ * @library /test/lib ++ * @run driver gc.x.TestDeprecated ++ */ ++ ++import java.util.LinkedList; ++import jdk.test.lib.process.ProcessTools; ++ ++public class TestDeprecated { ++ static class Test { ++ public static void main(String[] args) throws Exception {} ++ } ++ public static void main(String[] args) throws Exception { ++ ProcessTools.executeLimitedTestJava("-XX:+UseZGC", ++ "-XX:-ZGenerational", ++ "-Xlog:gc+init", ++ Test.class.getName()) ++ .shouldContain("Option ZGenerational was deprecated") ++ .shouldContain("Using deprecated non-generational mode") ++ .shouldHaveExitValue(0); ++ } ++} +diff --git a/test/hotspot/jtreg/gc/z/TestDefault.java b/test/hotspot/jtreg/gc/z/TestDefault.java +new file mode 100644 +index 000000000..c693e8745 +--- /dev/null ++++ b/test/hotspot/jtreg/gc/z/TestDefault.java +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) 2024, 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. ++ */ ++ ++package gc.z; ++ ++/* ++ * @test TestDefault ++ * @requires vm.gc.ZGenerational ++ * @summary Test that ZGC Generational Mode is Default ++ * @library /test/lib ++ * @run driver gc.z.TestDefault ++ */ ++ ++import java.util.LinkedList; ++import jdk.test.lib.process.ProcessTools; ++ ++public class TestDefault { ++ static class Test { ++ public static void main(String[] args) throws Exception {} ++ } ++ public static void main(String[] args) throws Exception { ++ ProcessTools.executeLimitedTestJava("-XX:+UseZGC", ++ "-Xlog:gc+init", ++ Test.class.getName()) ++ .shouldNotContain("Option ZGenerational was deprecated") ++ .shouldNotContain("Using deprecated non-generational mode") ++ .shouldContain("GC Workers for Old Generation") ++ .shouldContain("GC Workers for Young Generation") ++ .shouldHaveExitValue(0); ++ } ++} +diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +index 95dd88c72..0c9c2d6ea 100644 +--- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java ++++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, 2024, 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 +@@ -62,6 +62,7 @@ public class VMDeprecatedOptions { + {"InitialRAMFraction", "64"}, + {"TLABStats", "false"}, + {"AllowRedefinitionToAddDeleteMethods", "true"}, ++ {"ZGenerational", "false"}, + + // deprecated alias flags (see also aliased_jvm_flags): + {"DefaultMaxRAMFraction", "4"}, +-- +2.33.0 + diff --git a/Backport-JDK-8327538-The-SSLExtension-class-specifie.patch b/Backport-JDK-8327538-The-SSLExtension-class-specifie.patch new file mode 100644 index 0000000000000000000000000000000000000000..20130629a63829e2da04c9733d2eb9e7758543c2 --- /dev/null +++ b/Backport-JDK-8327538-The-SSLExtension-class-specifie.patch @@ -0,0 +1,38 @@ +Subject: Backport JDK-8327538 The SSLExtension class specifies incorrect values for heartbeat per RFC 6520 and post_handshake_auth per RFC 8446 + +--- + .../share/classes/sun/security/ssl/SSLExtension.java | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java +index 2a9239fac..2cb74fb10 100644 +--- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java ++++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, 2024, 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 +@@ -181,7 +181,7 @@ enum SSLExtension implements SSLStringizer { + USE_SRTP (0x000E, "use_srtp"), + + // Extensions defined in RFC 6520 (TLS and DTLS Heartbeat Extension) +- HEARTBEAT (0x000E, "heartbeat"), ++ HEARTBEAT (0x000F, "heartbeat"), + + // Extensions defined in RFC 7301 (TLS Application-Layer Protocol Negotiation Extension) + CH_ALPN (0x0010, "application_layer_protocol_negotiation", +@@ -406,7 +406,7 @@ enum SSLExtension implements SSLStringizer { + CertificateAuthoritiesExtension.ssStringizer), + + OID_FILTERS (0x0030, "oid_filters"), +- POST_HANDSHAKE_AUTH (0x0030, "post_handshake_auth"), ++ POST_HANDSHAKE_AUTH (0x0031, "post_handshake_auth"), + + CH_SIGNATURE_ALGORITHMS_CERT (0x0032, "signature_algorithms_cert", + SSLHandshake.CLIENT_HELLO, +-- +2.33.0 + diff --git a/Backport-JDK-8328107-Shenandoah-C2-TestVerifyLoopOpt.patch b/Backport-JDK-8328107-Shenandoah-C2-TestVerifyLoopOpt.patch new file mode 100644 index 0000000000000000000000000000000000000000..b6a47291de0cb32161093d91b3ce1372e7bc456f --- /dev/null +++ b/Backport-JDK-8328107-Shenandoah-C2-TestVerifyLoopOpt.patch @@ -0,0 +1,120 @@ +Subject: Backport JDK-8328107 Shenandoah/C2: TestVerifyLoopOptimizations test failure + +--- + .../gc/shenandoah/c2/shenandoahSupport.cpp | 8 ++ + .../compiler/TestBarrierOnLoopBackedge.java | 84 +++++++++++++++++++ + 2 files changed, 92 insertions(+) + create mode 100644 test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierOnLoopBackedge.java + +diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +index acf4b8f08..ce6403cb4 100644 +--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp ++++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +@@ -1321,6 +1321,14 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { + OuterStripMinedLoopNode* outer = head->as_OuterStripMinedLoop(); + hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase); + } ++ if (head->is_BaseCountedLoop() && ctrl->is_IfProj() && ctrl->in(0)->is_BaseCountedLoopEnd() && ++ head->as_BaseCountedLoop()->loopexit() == ctrl->in(0)) { ++ Node* entry = head->in(LoopNode::EntryControl); ++ Node* backedge = head->in(LoopNode::LoopBackControl); ++ Node* new_head = new LoopNode(entry, backedge); ++ phase->register_control(new_head, phase->get_loop(entry), entry); ++ phase->lazy_replace(head, new_head); ++ } + } + + // Expand load-reference-barriers +diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierOnLoopBackedge.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierOnLoopBackedge.java +new file mode 100644 +index 000000000..a72c7d69d +--- /dev/null ++++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierOnLoopBackedge.java +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (c) 2024, Red Hat, Inc. 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. ++ */ ++ ++/** ++ * @test ++ * @bug 8328107 ++ * @summary Barrier expanded on backedge break loop verification code ++ * @requires vm.gc.Shenandoah ++ * ++ * @run main/othervm -XX:+UseShenandoahGC -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestBarrierOnLoopBackedge::notInlined ++ * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyLoopOptimizations TestBarrierOnLoopBackedge ++ * @run main/othervm -XX:+UseShenandoahGC -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestBarrierOnLoopBackedge::notInlined ++ * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyLoopOptimizations -XX:-UseCountedLoopSafepoints TestBarrierOnLoopBackedge ++ */ ++ ++public class TestBarrierOnLoopBackedge { ++ private static A field = new A(); ++ private static final A finalField = new A(); ++ private static float floatField; ++ ++ public static void main(String[] args) { ++ A[] array = new A[1]; ++ array[0] = finalField; ++ for (int i = 0; i < 20_000; i++) { ++ test1(); ++ test2(); ++ } ++ } ++ ++ private static void test1() { ++ floatField = field.f; ++ for (int i = 0; i < 1000; i++) { ++ notInlined(field); // load barrier split thru phi and ends up on back edge ++ if (i % 2 == 0) { ++ field = finalField; ++ } ++ } ++ } ++ ++ private static void test2() { ++ A[] array = new A[1]; ++ notInlined(array); ++ int i = 0; ++ A a = array[0]; ++ for (;;) { ++ synchronized (new Object()) { ++ } ++ notInlined(a); ++ i++; ++ if (i >= 1000) { ++ break; ++ } ++ a = array[0]; // load barrier pinned on backedge ++ } ++ } ++ ++ private static void notInlined(Object a) { ++ ++ } ++ ++ private static class A { ++ float f; ++ } ++} +-- +2.33.0 + diff --git a/Backport-JDK-8329083-RISC-V-Update-profiles-supporte.patch b/Backport-JDK-8329083-RISC-V-Update-profiles-supporte.patch new file mode 100644 index 0000000000000000000000000000000000000000..f55980f9207e1e38cc70544a7cfaca0dd68c4c15 --- /dev/null +++ b/Backport-JDK-8329083-RISC-V-Update-profiles-supporte.patch @@ -0,0 +1,151 @@ +From 0d7ae782a1460d07b4c421539d6270b75e42f7eb Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Mon, 17 Mar 2025 16:27:36 +0800 +Subject: [PATCH] Backport JDK-8329083: RISC-V: Update profiles supported on + riscv + + +diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp +index 53c4f2c2842..85aaa3d239d 100644 +--- a/src/hotspot/cpu/riscv/globals_riscv.hpp ++++ b/src/hotspot/cpu/riscv/globals_riscv.hpp +@@ -99,8 +99,9 @@ define_pd_global(intx, InlineSmallCode, 1000); + product(bool, AvoidUnalignedAccesses, true, \ + "Avoid generating unaligned memory accesses") \ + product(bool, UseRVA20U64, true, "Use RVA20U64 profile") \ +- product(bool, UseRVC, false, "Use RVC instructions") \ + product(bool, UseRVA22U64, false, EXPERIMENTAL, "Use RVA22U64 profile") \ ++ product(bool, UseRVA23U64, false, EXPERIMENTAL, "Use RVA23U64 profile") \ ++ product(bool, UseRVC, false, "Use RVC instructions") \ + product(bool, UseRVV, false, "Use RVV instructions") \ + product(bool, UseZba, false, "Use Zba instructions") \ + product(bool, UseZbb, false, "Use Zbb instructions") \ +diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +index 4ad0b16b623..febe7cc0d73 100644 +--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp ++++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +@@ -45,6 +45,18 @@ VM_Version::RVFeatureValue* VM_Version::_feature_list[] = { + RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST) + nullptr}; + ++void VM_Version::useRVA20U64Profile() { ++ RV_USE_RVA20U64; ++} ++ ++void VM_Version::useRVA22U64Profile() { ++ RV_USE_RVA22U64; ++} ++ ++void VM_Version::useRVA23U64Profile() { ++ RV_USE_RVA23U64; ++} ++ + void VM_Version::initialize() { + _supports_cx8 = true; + _supports_atomic_getset4 = true; +@@ -62,41 +74,14 @@ void VM_Version::initialize() { + (int)satp_mode.value())); + } + +- // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva20-profiles + if (UseRVA20U64) { +- if (FLAG_IS_DEFAULT(UseRVC)) { +- FLAG_SET_DEFAULT(UseRVC, true); +- } ++ useRVA20U64Profile(); + } +- // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles + if (UseRVA22U64) { +- if (FLAG_IS_DEFAULT(UseRVC)) { +- FLAG_SET_DEFAULT(UseRVC, true); +- } +- if (FLAG_IS_DEFAULT(UseZba)) { +- FLAG_SET_DEFAULT(UseZba, true); +- } +- if (FLAG_IS_DEFAULT(UseZbb)) { +- FLAG_SET_DEFAULT(UseZbb, true); +- } +- if (FLAG_IS_DEFAULT(UseZbs)) { +- FLAG_SET_DEFAULT(UseZbs, true); +- } +- if (FLAG_IS_DEFAULT(UseZic64b)) { +- FLAG_SET_DEFAULT(UseZic64b, true); +- } +- if (FLAG_IS_DEFAULT(UseZicbom)) { +- FLAG_SET_DEFAULT(UseZicbom, true); +- } +- if (FLAG_IS_DEFAULT(UseZicbop)) { +- FLAG_SET_DEFAULT(UseZicbop, true); +- } +- if (FLAG_IS_DEFAULT(UseZicboz)) { +- FLAG_SET_DEFAULT(UseZicboz, true); +- } +- if (FLAG_IS_DEFAULT(UseZihintpause)) { +- FLAG_SET_DEFAULT(UseZihintpause, true); +- } ++ useRVA22U64Profile(); ++ } ++ if (UseRVA23U64) { ++ useRVA23U64Profile(); + } + + if (UseZic64b) { +diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp +index 0de6e9a19e1..01c5cf0c600 100644 +--- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp ++++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp +@@ -161,6 +161,51 @@ class VM_Version : public Abstract_VM_Version { + RV_FEATURE_FLAGS(DECLARE_RV_FEATURE) + #undef DECLARE_RV_FEATURE + ++ // enable extensions based on profile, current supported profiles: ++ // RVA20U64 ++ // RVA22U64 ++ // RVA23U64 ++ // NOTE: we only enable the mandatory extensions, not optional extension. ++ #define RV_ENABLE_EXTENSION(UseExtension) \ ++ if (FLAG_IS_DEFAULT(UseExtension)) { \ ++ FLAG_SET_DEFAULT(UseExtension, true); \ ++ } \ ++ ++ // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva20-profiles ++ #define RV_USE_RVA20U64 \ ++ RV_ENABLE_EXTENSION(UseRVC) \ ++ ++ static void useRVA20U64Profile(); ++ ++ // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles ++ #define RV_USE_RVA22U64 \ ++ RV_ENABLE_EXTENSION(UseRVC) \ ++ RV_ENABLE_EXTENSION(UseZba) \ ++ RV_ENABLE_EXTENSION(UseZbb) \ ++ RV_ENABLE_EXTENSION(UseZbs) \ ++ RV_ENABLE_EXTENSION(UseZic64b) \ ++ RV_ENABLE_EXTENSION(UseZicbom) \ ++ RV_ENABLE_EXTENSION(UseZicbop) \ ++ RV_ENABLE_EXTENSION(UseZicboz) \ ++ RV_ENABLE_EXTENSION(UseZihintpause) \ ++ ++ static void useRVA22U64Profile(); ++ ++ // https://github.com/riscv/riscv-profiles/blob/main/rva23-profile.adoc#rva23u64-profile ++ #define RV_USE_RVA23U64 \ ++ RV_ENABLE_EXTENSION(UseRVC) \ ++ RV_ENABLE_EXTENSION(UseRVV) \ ++ RV_ENABLE_EXTENSION(UseZba) \ ++ RV_ENABLE_EXTENSION(UseZbb) \ ++ RV_ENABLE_EXTENSION(UseZbs) \ ++ RV_ENABLE_EXTENSION(UseZic64b) \ ++ RV_ENABLE_EXTENSION(UseZicbom) \ ++ RV_ENABLE_EXTENSION(UseZicbop) \ ++ RV_ENABLE_EXTENSION(UseZicboz) \ ++ RV_ENABLE_EXTENSION(UseZihintpause) \ ++ ++ static void useRVA23U64Profile(); ++ + // VM modes (satp.mode) privileged ISA 1.10 + enum VM_MODE : int { + VM_NOTSET = -1, +-- +2.34.1 + diff --git a/Backport-JDK-8329174-update-CodeBuffer-layout-in-com.patch b/Backport-JDK-8329174-update-CodeBuffer-layout-in-com.patch new file mode 100644 index 0000000000000000000000000000000000000000..392b3f012d263f85424f156d4e9400bf20d516c4 --- /dev/null +++ b/Backport-JDK-8329174-update-CodeBuffer-layout-in-com.patch @@ -0,0 +1,45 @@ +Subject: Backport JDK-8329174 update CodeBuffer layout in comment after constants section moved + +--- + src/hotspot/share/asm/codeBuffer.cpp | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp +index ab8aed1cb..4bc33cc89 100644 +--- a/src/hotspot/share/asm/codeBuffer.cpp ++++ b/src/hotspot/share/asm/codeBuffer.cpp +@@ -24,6 +24,7 @@ + + #include "precompiled.hpp" + #include "asm/codeBuffer.hpp" ++#include "code/compiledIC.hpp" + #include "code/oopRecorder.inline.hpp" + #include "compiler/disassembler.hpp" + #include "logging/log.hpp" +@@ -65,7 +66,11 @@ + // The structure of the CodeBuffer while code is being accumulated: + // + // _total_start -> \ +-// _insts._start -> +----------------+ ++// _consts._start -> +----------------+ ++// | | ++// | Constants | ++// | | ++// _insts._start -> |----------------| + // | | + // | Code | + // | | +@@ -73,10 +78,6 @@ + // | | + // | Stubs | (also handlers for deopt/exception) + // | | +-// _consts._start -> |----------------| +-// | | +-// | Constants | +-// | | + // +----------------+ + // + _total_size -> | | + // +-- +2.33.0 + diff --git a/Backport-JDK-8329754-The-ThreadSafe-attribute-is-ign.patch b/Backport-JDK-8329754-The-ThreadSafe-attribute-is-ign.patch new file mode 100644 index 0000000000000000000000000000000000000000..7cf8f2ab970c73ca681b4da04e65d36c6dc40c51 --- /dev/null +++ b/Backport-JDK-8329754-The-ThreadSafe-attribute-is-ign.patch @@ -0,0 +1,143 @@ +Subject: Backport JDK-8329754 The ThreadSafe attribute is ignored for SecureRandom algorithm aliases + +--- + .../classes/java/security/SecureRandom.java | 6 +- + .../security/SecureRandom/ThreadSafe.java | 55 +++++++++++++------ + 2 files changed, 41 insertions(+), 20 deletions(-) + +diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java +index 6a1683e99..36e71cf54 100644 +--- a/src/java.base/share/classes/java/security/SecureRandom.java ++++ b/src/java.base/share/classes/java/security/SecureRandom.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1996, 2024, 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 +@@ -230,8 +230,8 @@ public class SecureRandom extends java.util.Random { + if (provider == null || algorithm == null) { + return false; + } else { +- return Boolean.parseBoolean(provider.getProperty( +- "SecureRandom." + algorithm + " ThreadSafe", "false")); ++ Service service = provider.getService("SecureRandom", algorithm); ++ return Boolean.parseBoolean(service.getAttribute("ThreadSafe")); + } + } + +diff --git a/test/jdk/java/security/SecureRandom/ThreadSafe.java b/test/jdk/java/security/SecureRandom/ThreadSafe.java +index 174f3253c..b0975678e 100644 +--- a/test/jdk/java/security/SecureRandom/ThreadSafe.java ++++ b/test/jdk/java/security/SecureRandom/ThreadSafe.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2016, 2024, 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 +@@ -21,33 +21,46 @@ + * questions. + */ + ++import static jdk.test.lib.Utils.runAndCheckException; ++ ++import java.lang.Override; + import java.security.Provider; + import java.security.SecureRandom; + import java.security.SecureRandomSpi; ++import java.util.List; + import java.util.Map; + + /* + * @test +- * @bug 7004967 ++ * @library /test/lib ++ * @bug 7004967 8329754 + * @summary SecureRandom should be more explicit about threading + */ ++ + public class ThreadSafe { + public static void main(String[] args) throws Exception { + Provider p = new P(); + NoSync.test(SecureRandom.getInstance("S1", p), 5, 5); +- try { +- NoSync.test(SecureRandom.getInstance("S2", p), 5, 5); +- throw new Exception("Failed"); +- } catch (RuntimeException re) { +- // Good +- } ++ NoSync.test(SecureRandom.getInstance("AliasS1", p), 5, 5); ++ ++ runAndCheckException( ++ () -> NoSync.test(SecureRandom.getInstance("S2", p), 5, 5), ++ RuntimeException.class); ++ ++ runAndCheckException( ++ () -> NoSync.test(SecureRandom.getInstance("AliasS2", p), 5, 5), ++ RuntimeException.class); ++ + NoSync.test(SecureRandom.getInstance("S3", p), 5, 5); +- try { +- NoSync.test(SecureRandom.getInstance("S4", p), 5, 5); +- throw new Exception("Failed"); +- } catch (RuntimeException re) { +- // Good +- } ++ NoSync.test(SecureRandom.getInstance("AliasS3", p), 5, 5); ++ ++ runAndCheckException( ++ () -> NoSync.test(SecureRandom.getInstance("S4", p), 5, 5), ++ RuntimeException.class); ++ ++ runAndCheckException( ++ () -> NoSync.test(SecureRandom.getInstance("AliasS4", p), 5, 5), ++ RuntimeException.class); + } + + public static class P extends Provider { +@@ -58,28 +71,36 @@ public class ThreadSafe { + // Good. No attribute. + put("SecureRandom.S1", S.class.getName()); + ++ // Good. Alias of S1, should pass because S1 is not marked as ThreadSafe ++ put("Alg.alias.SecureRandom.AliasS1", "S1"); ++ + // Bad. Boasting ThreadSafe but isn't + put("SecureRandom.S2", S.class.getName()); + put("SecureRandom.S2 ThreadSafe", "true"); + ++ //Bad. Alias of S2, should fail because S2 is marked as ThreadSafe ++ put("alg.Alias.SecureRandom.AliasS2", "S2"); ++ + // Good. No attribute. + putService(new Service(this, "SecureRandom", "S3", +- S.class.getName(), null, null)); ++ S.class.getName(), List.of("AliasS3"), null)); + + // Bad. Boasting ThreadSafe but isn't + putService(new Service(this, "SecureRandom", "S4", +- S.class.getName(), null, Map.of("ThreadSafe", "true"))); ++ S.class.getName(), List.of("AliasS4"), Map.of("ThreadSafe", "true"))); + } + } + + // This implementation is not itself thread safe. + public static class S extends SecureRandomSpi { +- @java.lang.Override ++ ++ @Override + protected void engineSetSeed(byte[] seed) { + return; + } + + private volatile boolean inCall = false; ++ + @Override + protected void engineNextBytes(byte[] bytes) { + if (inCall) { +-- +2.33.0 + diff --git a/Backport-JDK-8332297-annotation-processor-that-gener.patch b/Backport-JDK-8332297-annotation-processor-that-gener.patch new file mode 100644 index 0000000000000000000000000000000000000000..e49784c083ea786c0d58943d3b7bf29fcb7e769e --- /dev/null +++ b/Backport-JDK-8332297-annotation-processor-that-gener.patch @@ -0,0 +1,183 @@ +Subject: Backport JDK-8332297 annotation processor that generates records sometimes fails due to NPE in javac + +--- + .../com/sun/tools/javac/code/Symbol.java | 6 +- + .../processing/RecordGenerationTest.java | 148 ++++++++++++++++++ + 2 files changed, 152 insertions(+), 2 deletions(-) + create mode 100644 test/langtools/tools/javac/processing/RecordGenerationTest.java + +diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +index 7a939abb3..3438756be 100644 +--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java ++++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +@@ -1549,9 +1549,11 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem + RecordComponent toRemove = null; + for (RecordComponent rc : recordComponents) { + /* it could be that a record erroneously declares two record components with the same name, in that +- * case we need to use the position to disambiguate ++ * case we need to use the position to disambiguate, but if we loaded the record from a class file ++ * all positions will be -1, in that case we have to ignore the position and match only based on the ++ * name + */ +- if (rc.name == var.name && var.pos == rc.pos) { ++ if (rc.name == var.name && (var.pos == rc.pos || rc.pos == -1)) { + toRemove = rc; + } + } +diff --git a/test/langtools/tools/javac/processing/RecordGenerationTest.java b/test/langtools/tools/javac/processing/RecordGenerationTest.java +new file mode 100644 +index 000000000..9ee28d264 +--- /dev/null ++++ b/test/langtools/tools/javac/processing/RecordGenerationTest.java +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (c) 2024, 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. ++ */ ++ ++/** ++ * @test ++ * @bug 8332297 ++ * @summary annotation processor that generates records sometimes fails due to NPE in javac ++ * @library /tools/lib /tools/javac/lib ++ * @modules jdk.compiler/com.sun.tools.javac.api ++ * jdk.compiler/com.sun.tools.javac.main ++ * @build toolbox.ToolBox toolbox.JavacTask toolbox.Task ++ * @build RecordGenerationTest JavacTestingAbstractProcessor ++ * @run main RecordGenerationTest ++ */ ++ ++import java.io.IOException; ++import java.io.OutputStream; ++import java.io.Writer; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.Paths; ++import java.util.Set; ++ ++import javax.annotation.processing.FilerException; ++import javax.annotation.processing.RoundEnvironment; ++import javax.annotation.processing.SupportedOptions; ++import javax.annotation.processing.SupportedAnnotationTypes; ++ ++import javax.lang.model.element.TypeElement; ++import javax.tools.StandardLocation; ++ ++import toolbox.JavacTask; ++import toolbox.Task; ++import toolbox.ToolBox; ++ ++public class RecordGenerationTest { ++ public static void main(String... args) throws Exception { ++ new RecordGenerationTest().run(); ++ } ++ ++ Path[] findJavaFiles(Path... paths) throws Exception { ++ return tb.findJavaFiles(paths); ++ } ++ ++ ToolBox tb = new ToolBox(); ++ ++ void run() throws Exception { ++ Path allInOne = Paths.get("allInOne"); ++ if (Files.isDirectory(allInOne)) { ++ tb.cleanDirectory(allInOne); ++ } ++ Files.deleteIfExists(allInOne); ++ tb.createDirectories(allInOne); ++ ++ tb.writeJavaFiles(allInOne, ++ """ ++ import java.io.IOException; ++ import java.io.OutputStream; ++ import java.io.Writer; ++ import java.nio.file.Files; ++ import java.nio.file.Path; ++ import java.nio.file.Paths; ++ import java.util.Set; ++ ++ import javax.annotation.processing.AbstractProcessor; ++ import javax.annotation.processing.FilerException; ++ import javax.annotation.processing.RoundEnvironment; ++ import javax.annotation.processing.SupportedOptions; ++ import javax.annotation.processing.SupportedAnnotationTypes; ++ ++ import javax.lang.model.element.TypeElement; ++ import javax.tools.StandardLocation; ++ ++ @SupportedAnnotationTypes("*") ++ public class AP extends AbstractProcessor { ++ @Override ++ public boolean process(Set annotations, RoundEnvironment roundEnv) { ++ if (roundEnv.processingOver()) { ++ try (Writer w = processingEnv.getFiler().createSourceFile("ConfRecord").openWriter()) { ++ w.append("@RecordBuilder public record ConfRecord(int maxConcurrency) implements Conf {}"); ++ } catch (IOException ex) { ++ throw new IllegalStateException(ex); ++ } ++ } ++ return true; ++ } ++ } ++ """ ++ ); ++ ++ new JavacTask(tb).options("-d", allInOne.toString()) ++ .files(findJavaFiles(allInOne)) ++ .run() ++ .writeAll(); ++ ++ tb.writeJavaFiles(allInOne, ++ """ ++ interface Conf { ++ int maxConcurrency( ); ++ } ++ """, ++ """ ++ import java.lang.annotation.*; ++ public @interface RecordBuilder { ++ } ++ """ ++ ); ++ ++ Path confSource = Paths.get(allInOne.toString(), "Conf.java"); ++ new JavacTask(tb).options("-processor", "AP", ++ "-cp", allInOne.toString(), ++ "-d", allInOne.toString()) ++ .files(confSource) ++ .run() ++ .writeAll(); ++ ++ /* the bug reported at JDK-8332297 was reproducible only every other time this is why we reproduce ++ * the same compilation command as above basically the second time the compiler is completing the ++ * record symbol from the class file produced during the first compilation ++ */ ++ new JavacTask(tb).options("-processor", "AP", ++ "-cp", allInOne.toString(), ++ "-d", allInOne.toString()) ++ .files(confSource) ++ .run() ++ .writeAll(); ++ } ++} +-- +2.33.0 + diff --git a/Backport-JDK-8333599-Improve-description-of-b-matche.patch b/Backport-JDK-8333599-Improve-description-of-b-matche.patch new file mode 100644 index 0000000000000000000000000000000000000000..23ea2136c74175398bf842ead6cd46fe298c9055 --- /dev/null +++ b/Backport-JDK-8333599-Improve-description-of-b-matche.patch @@ -0,0 +1,41 @@ +Subject: Backport JDK-8333599 Improve description of \b matcher in j.u.r.Pattern + +--- + src/java.base/share/classes/java/util/regex/Pattern.java | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java +index 45c48ddab..84e5a140d 100644 +--- a/src/java.base/share/classes/java/util/regex/Pattern.java ++++ b/src/java.base/share/classes/java/util/regex/Pattern.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1999, 2024, 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 +@@ -160,7 +160,7 @@ import jdk.internal.util.regex.Grapheme; + * Any character (may or may not match line terminators) + * {@code \d} + * A digit: {@code [0-9]} if +- * * UNICODE_CHARACTER_CLASS is not set. See Unicode Support. ++ * UNICODE_CHARACTER_CLASS is not set. See Unicode Support. + * {@code \D} + * A non-digit: {@code [^0-9]} + * {@code \h} +@@ -251,8 +251,9 @@ import jdk.internal.util.regex.Grapheme; + * {@code $} + * The end of a line + * {@code \b} +- * A word boundary: {@code (?:(?<=\w)(?=\W)|(?<=\W)(?=\w))} (the location +- * where a non-word character abuts a word character) ++ * A word boundary: ++ * at the beginning or at the end of a line if a word character ({@code \w}) appears there; ++ * or between a word ({@code \w}) and a non-word character ({@code \W}), in either order. + * {@code \b{g}} + * A Unicode extended grapheme cluster boundary + * {@code \B} +-- +2.33.0 + diff --git a/Backport-JDK-8333805-Replaying-compilation-with-null.patch b/Backport-JDK-8333805-Replaying-compilation-with-null.patch new file mode 100644 index 0000000000000000000000000000000000000000..df99142cf9cf3ecb9b5c42b110ce7bd832626b8e --- /dev/null +++ b/Backport-JDK-8333805-Replaying-compilation-with-null.patch @@ -0,0 +1,242 @@ +Subject: Backport JDK-8333805 Replaying compilation with null static final fields results in a crash + +--- + src/hotspot/share/ci/ciInstanceKlass.cpp | 10 ++- + src/hotspot/share/ci/ciReplay.cpp | 89 ++++++++++--------- + .../ciReplay/TestNullStaticField.java | 82 +++++++++++++++++ + 3 files changed, 136 insertions(+), 45 deletions(-) + create mode 100644 test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java + +diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp +index fa084e228..240bb25ae 100644 +--- a/src/hotspot/share/ci/ciInstanceKlass.cpp ++++ b/src/hotspot/share/ci/ciInstanceKlass.cpp +@@ -661,7 +661,8 @@ class StaticFinalFieldPrinter : public FieldClosure { + ResourceMark rm; + oop mirror = fd->field_holder()->java_mirror(); + _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii()); +- switch (fd->field_type()) { ++ BasicType field_type = fd->field_type(); ++ switch (field_type) { + case T_BYTE: _out->print_cr("%d", mirror->byte_field(fd->offset())); break; + case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset())); break; + case T_SHORT: _out->print_cr("%d", mirror->short_field(fd->offset())); break; +@@ -682,9 +683,12 @@ class StaticFinalFieldPrinter : public FieldClosure { + case T_OBJECT: { + oop value = mirror->obj_field_acquire(fd->offset()); + if (value == nullptr) { +- _out->print_cr("null"); ++ if (field_type == T_ARRAY) { ++ _out->print("%d", -1); ++ } ++ _out->cr(); + } else if (value->is_instance()) { +- assert(fd->field_type() == T_OBJECT, ""); ++ assert(field_type == T_OBJECT, ""); + if (value->is_a(vmClasses::String_klass())) { + const char* ascii_value = java_lang_String::as_quoted_ascii(value); + _out->print_cr("\"%s\"", (ascii_value != nullptr) ? ascii_value : ""); +diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp +index 68d4308a2..3171a5d51 100644 +--- a/src/hotspot/share/ci/ciReplay.cpp ++++ b/src/hotspot/share/ci/ciReplay.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013, 2024, 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 +@@ -1065,46 +1065,48 @@ class CompileReplay : public StackObj { + int length = parse_int("array length"); + oop value = nullptr; + +- if (field_signature[1] == JVM_SIGNATURE_ARRAY) { +- // multi dimensional array +- ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); +- if (kelem == nullptr) { +- return; +- } +- int rank = 0; +- while (field_signature[rank] == JVM_SIGNATURE_ARRAY) { +- rank++; +- } +- jint* dims = NEW_RESOURCE_ARRAY(jint, rank); +- dims[0] = length; +- for (int i = 1; i < rank; i++) { +- dims[i] = 1; // These aren't relevant to the compiler +- } +- value = kelem->multi_allocate(rank, dims, CHECK); +- } else { +- if (strcmp(field_signature, "[B") == 0) { +- value = oopFactory::new_byteArray(length, CHECK); +- } else if (strcmp(field_signature, "[Z") == 0) { +- value = oopFactory::new_boolArray(length, CHECK); +- } else if (strcmp(field_signature, "[C") == 0) { +- value = oopFactory::new_charArray(length, CHECK); +- } else if (strcmp(field_signature, "[S") == 0) { +- value = oopFactory::new_shortArray(length, CHECK); +- } else if (strcmp(field_signature, "[F") == 0) { +- value = oopFactory::new_floatArray(length, CHECK); +- } else if (strcmp(field_signature, "[D") == 0) { +- value = oopFactory::new_doubleArray(length, CHECK); +- } else if (strcmp(field_signature, "[I") == 0) { +- value = oopFactory::new_intArray(length, CHECK); +- } else if (strcmp(field_signature, "[J") == 0) { +- value = oopFactory::new_longArray(length, CHECK); +- } else if (field_signature[0] == JVM_SIGNATURE_ARRAY && +- field_signature[1] == JVM_SIGNATURE_CLASS) { +- parse_klass(CHECK); // eat up the array class name +- Klass* kelem = resolve_klass(field_signature + 1, CHECK); +- value = oopFactory::new_objArray(kelem, length, CHECK); ++ if (length != -1) { ++ if (field_signature[1] == JVM_SIGNATURE_ARRAY) { ++ // multi dimensional array ++ ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); ++ if (kelem == nullptr) { ++ return; ++ } ++ int rank = 0; ++ while (field_signature[rank] == JVM_SIGNATURE_ARRAY) { ++ rank++; ++ } ++ jint* dims = NEW_RESOURCE_ARRAY(jint, rank); ++ dims[0] = length; ++ for (int i = 1; i < rank; i++) { ++ dims[i] = 1; // These aren't relevant to the compiler ++ } ++ value = kelem->multi_allocate(rank, dims, CHECK); + } else { +- report_error("unhandled array staticfield"); ++ if (strcmp(field_signature, "[B") == 0) { ++ value = oopFactory::new_byteArray(length, CHECK); ++ } else if (strcmp(field_signature, "[Z") == 0) { ++ value = oopFactory::new_boolArray(length, CHECK); ++ } else if (strcmp(field_signature, "[C") == 0) { ++ value = oopFactory::new_charArray(length, CHECK); ++ } else if (strcmp(field_signature, "[S") == 0) { ++ value = oopFactory::new_shortArray(length, CHECK); ++ } else if (strcmp(field_signature, "[F") == 0) { ++ value = oopFactory::new_floatArray(length, CHECK); ++ } else if (strcmp(field_signature, "[D") == 0) { ++ value = oopFactory::new_doubleArray(length, CHECK); ++ } else if (strcmp(field_signature, "[I") == 0) { ++ value = oopFactory::new_intArray(length, CHECK); ++ } else if (strcmp(field_signature, "[J") == 0) { ++ value = oopFactory::new_longArray(length, CHECK); ++ } else if (field_signature[0] == JVM_SIGNATURE_ARRAY && ++ field_signature[1] == JVM_SIGNATURE_CLASS) { ++ Klass* actual_array_klass = parse_klass(CHECK); ++ Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); ++ value = oopFactory::new_objArray(kelem, length, CHECK); ++ } else { ++ report_error("unhandled array staticfield"); ++ } + } + } + java_mirror->obj_field_put(fd.offset(), value); +@@ -1142,8 +1144,11 @@ class CompileReplay : public StackObj { + Handle value = java_lang_String::create_from_str(string_value, CHECK); + java_mirror->obj_field_put(fd.offset(), value()); + } else if (field_signature[0] == JVM_SIGNATURE_CLASS) { +- Klass* k = resolve_klass(string_value, CHECK); +- oop value = InstanceKlass::cast(k)->allocate_instance(CHECK); ++ oop value = nullptr; ++ if (string_value != nullptr) { ++ Klass* k = resolve_klass(string_value, CHECK); ++ value = InstanceKlass::cast(k)->allocate_instance(CHECK); ++ } + java_mirror->obj_field_put(fd.offset(), value); + } else { + report_error("unhandled staticfield"); +diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java b/test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java +new file mode 100644 +index 000000000..47a78ad5e +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (c) 2024, Red Hat, Inc. 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. ++ */ ++ ++/* ++ * @test ++ * @bug 8333805 ++ * @library / /test/lib ++ * @summary Replaying compilation with null static final fields results in a crash ++ * @requires vm.flightRecorder != true & vm.compMode != "Xint" & vm.compMode != "Xcomp" & vm.debug == true & vm.compiler2.enabled ++ * @modules java.base/jdk.internal.misc ++ * @build jdk.test.whitebox.WhiteBox ++ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox ++ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ++ * compiler.ciReplay.TestNullStaticField ++ */ ++ ++package compiler.ciReplay; ++ ++public class TestNullStaticField extends DumpReplayBase { ++ ++ public static void main(String[] args) { ++ new TestNullStaticField().runTest(TIERED_DISABLED_VM_OPTION); ++ } ++ ++ @Override ++ public void testAction() { ++ positiveTest(TIERED_DISABLED_VM_OPTION, "-XX:+ReplayIgnoreInitErrors"); ++ } ++ ++ @Override ++ public String getTestClass() { ++ return TestClassNullStaticField.class.getName(); ++ } ++ ++} ++ ++class TestClassNullStaticField { ++ ++ static final Object[] staticNullArrayField = null; ++ static final Object[][] staticNullMultiArrayField = null; ++ static final Object staticNullObjectField = null; ++ static final String staticNullStringField = null; ++ static final int[] staticNullIntArrayField = null; ++ static final Object[] staticNotNullArrayField = new A[10]; ++ static final Object[][] staticNotNullMultiArrayField = new A[10][10]; ++ static final Object staticNotNullObjectField = new A(); ++ static final String staticNotNullStringField = "Not null"; ++ static final int[] staticNotNullIntArrayField = new int[10]; ++ ++ public static void main(String[] args) { ++ for (int i = 0; i < 20_000; i++) { ++ test(); ++ } ++ } ++ public static void test() { ++ ++ } ++ ++ private static class A { ++ } ++} ++ +-- +2.33.0 + diff --git a/Backport-JDK-8334758-Incorrect-note-in-Javadoc-for-a.patch b/Backport-JDK-8334758-Incorrect-note-in-Javadoc-for-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..4de6a24418ffe75dc1db5d0851669875cb2844e0 --- /dev/null +++ b/Backport-JDK-8334758-Incorrect-note-in-Javadoc-for-a.patch @@ -0,0 +1,97 @@ +Subject: Backport JDK-8334758: Incorrect note in Javadoc for a few RandomGenerator methods + +--- + .../java/util/random/RandomGenerator.java | 51 +++++++++---------- + 1 file changed, 23 insertions(+), 28 deletions(-) + +diff --git a/src/java.base/share/classes/java/util/random/RandomGenerator.java b/src/java.base/share/classes/java/util/random/RandomGenerator.java +index a7c6bcec3..5c0d07fb1 100644 +--- a/src/java.base/share/classes/java/util/random/RandomGenerator.java ++++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, 2024, 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 +@@ -640,12 +640,11 @@ public interface RandomGenerator { + * + * @throws IllegalArgumentException if {@code bound} is not positive + * +- * @implSpec The default implementation checks that {@code bound} is a +- * positive {@code int}. Then invokes {@code nextInt()}, limiting the result +- * to be greater than or equal zero and less than {@code bound}. If {@code bound} +- * is a power of two then limiting is a simple masking operation. Otherwise, +- * the result is re-calculated by invoking {@code nextInt()} until the +- * result is greater than or equal zero and less than {@code bound}. ++ * @implSpec The default implementation checks that {@code bound} is positive. ++ * It then invokes {@link #nextInt()} one or more times to ensure a uniform ++ * distribution in the range 0 (inclusive) ++ * to {@code bound} (exclusive). ++ * It assumes the distribution of {@link #nextInt()} to be uniform. + */ + default int nextInt(int bound) { + RandomSupport.checkBound(bound); +@@ -666,13 +665,12 @@ public interface RandomGenerator { + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} + * +- * @implSpec The default implementation checks that {@code origin} and +- * {@code bound} are positive {@code ints}. Then invokes {@code nextInt()}, +- * limiting the result to be greater that or equal {@code origin} and less +- * than {@code bound}. If {@code bound} is a power of two then limiting is a +- * simple masking operation. Otherwise, the result is re-calculated by +- * invoking {@code nextInt()} until the result is greater than or equal +- * {@code origin} and less than {@code bound}. ++ * @implSpec The default implementation checks that {@code origin} ++ * is less than {@code bound}. ++ * It then invokes {@link #nextInt()} one or more times to ensure a uniform ++ * distribution in the range {@code origin} (inclusive) ++ * to {@code bound} (exclusive). ++ * It assumes the distribution of {@link #nextInt()} to be uniform. + */ + default int nextInt(int origin, int bound) { + RandomSupport.checkRange(origin, bound); +@@ -699,13 +697,11 @@ public interface RandomGenerator { + * + * @throws IllegalArgumentException if {@code bound} is not positive + * +- * @implSpec The default implementation checks that {@code bound} is a +- * positive {@code long}. Then invokes {@code nextLong()}, limiting the +- * result to be greater than or equal zero and less than {@code bound}. If +- * {@code bound} is a power of two then limiting is a simple masking +- * operation. Otherwise, the result is re-calculated by invoking +- * {@code nextLong()} until the result is greater than or equal zero and +- * less than {@code bound}. ++ * @implSpec The default implementation checks that {@code bound} is positive. ++ * It then invokes {@link #nextLong()} one or more times to ensure a uniform ++ * distribution in the range 0 (inclusive) ++ * to {@code bound} (exclusive). ++ * It assumes the distribution of {@link #nextLong()} to be uniform. + */ + default long nextLong(long bound) { + RandomSupport.checkBound(bound); +@@ -726,13 +722,12 @@ public interface RandomGenerator { + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} + * +- * @implSpec The default implementation checks that {@code origin} and +- * {@code bound} are positive {@code longs}. Then invokes {@code nextLong()}, +- * limiting the result to be greater than or equal {@code origin} and less +- * than {@code bound}. If {@code bound} is a power of two then limiting is a +- * simple masking operation. Otherwise, the result is re-calculated by +- * invoking {@code nextLong()} until the result is greater than or equal +- * {@code origin} and less than {@code bound}. ++ * @implSpec The default implementation checks that {@code origin} ++ * is less than {@code bound}. ++ * It then invokes {@link #nextLong()} one or more times to ensure a uniform ++ * distribution in the range {@code origin} (inclusive) ++ * to {@code bound} (exclusive). ++ * It assumes the distribution of {@link #nextLong()} to be uniform. + */ + default long nextLong(long origin, long bound) { + RandomSupport.checkRange(origin, bound); +-- +2.33.0 + diff --git a/Backport-JDK-8335638-Calling-VarHandle.-access-mode-.patch b/Backport-JDK-8335638-Calling-VarHandle.-access-mode-.patch new file mode 100644 index 0000000000000000000000000000000000000000..15c74dfa842086763080c4d9f3e0e9425b9d7012 --- /dev/null +++ b/Backport-JDK-8335638-Calling-VarHandle.-access-mode-.patch @@ -0,0 +1,162 @@ +Subject: Backport JDK-8335638 Calling VarHandle.{access-mode} methods reflectively throws wrong exception + +--- + src/hotspot/share/prims/methodHandles.cpp | 59 ++++++++++++++++++- + .../VarHandles/VarHandleTestReflection.java | 25 +++++++- + 2 files changed, 78 insertions(+), 6 deletions(-) + +diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp +index f6412504a..55a6b3286 100644 +--- a/src/hotspot/share/prims/methodHandles.cpp ++++ b/src/hotspot/share/prims/methodHandles.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2008, 2024, 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 +@@ -1362,6 +1362,18 @@ JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv* env, jobject mh, jobjectArray args + } + JVM_END + ++/** ++ * Throws a java/lang/UnsupportedOperationException unconditionally. ++ * This is required by the specification of VarHandle.{access-mode} if ++ * invoked directly. ++ */ ++JVM_ENTRY(jobject, VH_UOE(JNIEnv* env, jobject vh, jobjectArray args)) { ++ THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "VarHandle access mode methods cannot be invoked reflectively"); ++ return nullptr; ++} ++JVM_END ++ ++ + /// JVM_RegisterMethodHandleMethods + + #define LANG "Ljava/lang/" +@@ -1401,6 +1413,40 @@ static JNINativeMethod MH_methods[] = { + {CC "invoke", CC "([" OBJ ")" OBJ, FN_PTR(MH_invoke_UOE)}, + {CC "invokeExact", CC "([" OBJ ")" OBJ, FN_PTR(MH_invokeExact_UOE)} + }; ++static JNINativeMethod VH_methods[] = { ++ // UnsupportedOperationException throwers ++ {CC "get", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "set", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, ++ {CC "getVolatile", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "setVolatile", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, ++ {CC "getAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "setRelease", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, ++ {CC "getOpaque", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "setOpaque", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, ++ {CC "compareAndSet", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, ++ {CC "compareAndExchange", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "compareAndExchangeAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "compareAndExchangeRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "weakCompareAndSetPlain", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, ++ {CC "weakCompareAndSet", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, ++ {CC "weakCompareAndSetAcquire", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, ++ {CC "weakCompareAndSetRelease", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, ++ {CC "getAndSet", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndSetAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndSetRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndAdd", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndAddAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndAddRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseOr", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseOrAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseOrRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseAnd", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseAndAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseAndRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseXor", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseXorAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, ++ {CC "getAndBitwiseXorRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)} ++}; + + /** + * This one function is exported, used by NativeLookup. +@@ -1408,9 +1454,12 @@ static JNINativeMethod MH_methods[] = { + JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { + assert(!MethodHandles::enabled(), "must not be enabled"); + assert(vmClasses::MethodHandle_klass() != nullptr, "should be present"); ++ assert(vmClasses::VarHandle_klass() != nullptr, "should be present"); + +- oop mirror = vmClasses::MethodHandle_klass()->java_mirror(); +- jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mirror); ++ oop mh_mirror = vmClasses::MethodHandle_klass()->java_mirror(); ++ oop vh_mirror = vmClasses::VarHandle_klass()->java_mirror(); ++ jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mh_mirror); ++ jclass VH_class = (jclass) JNIHandles::make_local(THREAD, vh_mirror); + + { + ThreadToNativeFromVM ttnfv(thread); +@@ -1422,6 +1471,10 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) + status = env->RegisterNatives(MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod)); + guarantee(status == JNI_OK && !env->ExceptionOccurred(), + "register java.lang.invoke.MethodHandle natives"); ++ ++ status = env->RegisterNatives(VH_class, VH_methods, sizeof(VH_methods)/sizeof(JNINativeMethod)); ++ guarantee(status == JNI_OK && !env->ExceptionOccurred(), ++ "register java.lang.invoke.VarHandle natives"); + } + + log_debug(methodhandles, indy)("MethodHandle support loaded (using LambdaForms)"); +diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java +index 652272ca8..b20e18d26 100644 +--- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java ++++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2024, 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 +@@ -33,6 +33,7 @@ import java.lang.invoke.MethodHandle; + import java.lang.invoke.MethodHandleInfo; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; ++import java.lang.reflect.InvocationTargetException; + import java.lang.reflect.Method; + import java.util.stream.Stream; + +@@ -52,15 +53,33 @@ public class VarHandleTestReflection extends VarHandleBaseTest { + } + + @Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) +- public void methodInvocation(VarHandle.AccessMode accessMode) throws Exception { ++ public void methodInvocationArgumentMismatch(VarHandle.AccessMode accessMode) throws Exception { + VarHandle v = handle(); + +- // Try a reflective invoke using a Method ++ // Try a reflective invoke using a Method, with no arguments + + Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class); + vhm.invoke(v, new Object[]{}); + } + ++ @Test(dataProvider = "accessModesProvider") ++ public void methodInvocationMatchingArguments(VarHandle.AccessMode accessMode) throws Exception { ++ VarHandle v = handle(); ++ ++ // Try a reflective invoke using a Method, with the minimal required arguments ++ ++ Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class); ++ Object arg = new Object[0]; ++ try { ++ vhm.invoke(v, arg); ++ } catch (InvocationTargetException e) { ++ if (!(e.getCause() instanceof UnsupportedOperationException)) { ++ throw new RuntimeException("expected UnsupportedOperationException but got: " ++ + e.getCause().getClass().getName(), e); ++ } ++ } ++ } ++ + @Test(dataProvider = "accessModesProvider", expectedExceptions = UnsupportedOperationException.class) + public void methodHandleInvoke(VarHandle.AccessMode accessMode) throws Throwable { + VarHandle v = handle(); +-- +2.33.0 + diff --git a/Backport-JDK-8336080-Fix--Wzero-as-null-pointer-cons.patch b/Backport-JDK-8336080-Fix--Wzero-as-null-pointer-cons.patch new file mode 100644 index 0000000000000000000000000000000000000000..7cae0ad17fc2c4abcfe136d5548289e6637b4e97 --- /dev/null +++ b/Backport-JDK-8336080-Fix--Wzero-as-null-pointer-cons.patch @@ -0,0 +1,33 @@ +Subject: Backport of JDK-8336080 Fix -Wzero-as-null-pointer-constant warnings in ClassLoaderStats ctor + +--- + src/hotspot/share/classfile/classLoaderStats.hpp | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/hotspot/share/classfile/classLoaderStats.hpp b/src/hotspot/share/classfile/classLoaderStats.hpp +index 8296c6ee2..4818ddff6 100644 +--- a/src/hotspot/share/classfile/classLoaderStats.hpp ++++ b/src/hotspot/share/classfile/classLoaderStats.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2024, 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 +@@ -82,9 +82,9 @@ public: + uintx _hidden_classes_count; + + ClassLoaderStats() : +- _cld(0), +- _class_loader(0), +- _parent(0), ++ _cld(nullptr), ++ _class_loader(), ++ _parent(), + _chunk_sz(0), + _block_sz(0), + _classes_count(0), +-- +2.33.0 + diff --git a/Backport-JDK-8336152-Remove-unused-forward-declarati.patch b/Backport-JDK-8336152-Remove-unused-forward-declarati.patch new file mode 100644 index 0000000000000000000000000000000000000000..b0792cca16049d894d8162305ec35344acf27494 --- /dev/null +++ b/Backport-JDK-8336152-Remove-unused-forward-declarati.patch @@ -0,0 +1,29 @@ +Subject: Backport of JDK-8336152 Remove unused forward declaration in classLoadInfo.hpp + +--- + src/hotspot/share/classfile/classLoadInfo.hpp | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/hotspot/share/classfile/classLoadInfo.hpp b/src/hotspot/share/classfile/classLoadInfo.hpp +index b1257dc99..ab665c6b3 100644 +--- a/src/hotspot/share/classfile/classLoadInfo.hpp ++++ b/src/hotspot/share/classfile/classLoadInfo.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2020, 2024, 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 +@@ -29,8 +29,6 @@ + + class InstanceKlass; + +-template class GrowableArray; +- + class ClassInstanceInfo : public StackObj { + private: + InstanceKlass* _dynamic_nest_host; +-- +2.33.0 + diff --git a/Backport-JDK-8336855-Duplicate-protected-declaration.patch b/Backport-JDK-8336855-Duplicate-protected-declaration.patch new file mode 100644 index 0000000000000000000000000000000000000000..dab65b0a1a659e446e1cc7f76a18aabe3aa59e23 --- /dev/null +++ b/Backport-JDK-8336855-Duplicate-protected-declaration.patch @@ -0,0 +1,40 @@ +Subject: Backport JDK-8336855 Duplicate protected declaration and comment in interp_masm_aarch64.hpp + +--- + src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +index 019eb2355..6dd8ea70d 100644 +--- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp ++++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +@@ -35,8 +35,6 @@ + typedef ByteSize (*OffsetFunction)(uint); + + class InterpreterMacroAssembler: public MacroAssembler { +- protected: +- + protected: + // Interpreter specific version of call_VM_base + using MacroAssembler::call_VM_leaf_base; +@@ -110,8 +108,6 @@ class InterpreterMacroAssembler: public MacroAssembler { + + void get_dispatch(); + +- // Helpers for runtime call arguments/results +- + // Helpers for runtime call arguments/results + void get_method(Register reg) { + ldr(reg, Address(rfp, frame::interpreter_frame_method_offset * wordSize)); +@@ -183,7 +179,7 @@ class InterpreterMacroAssembler: public MacroAssembler { + void load_ptr(int n, Register val); + void store_ptr(int n, Register val); + +-// Load float value from 'address'. The value is loaded onto the FPU register v0. ++ // Load float value from 'address'. The value is loaded onto the FPU register v0. + void load_float(Address src); + void load_double(Address src); + +-- +2.33.0 + diff --git a/Backport-JDK-8336879-Always-true-condition-img-null-.patch b/Backport-JDK-8336879-Always-true-condition-img-null-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7063e49b1ef6eee684a522abeb255356534fcf12 --- /dev/null +++ b/Backport-JDK-8336879-Always-true-condition-img-null-.patch @@ -0,0 +1,34 @@ +Subject: Backport JDK-8336879 Always true condition 'img != null' in GTKPainter.paintPopupMenuBackground + +--- + .../classes/com/sun/java/swing/plaf/gtk/GTKPainter.java | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +index 1635ff66f..6231e11d6 100644 +--- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java ++++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2002, 2024, 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 +@@ -610,10 +610,10 @@ class GTKPainter extends SynthPainter { + x + insets.left, y + insets.top, w - insets.left - insets.right, + h - insets.top - insets.bottom); + BufferedImage img = ENGINE.finishPainting(); +- if(!isHW) { ++ if (!isHW && img != null) { + int border = img.getRGB(0, h / 2); +- if (img != null && border == img.getRGB(w / 2, h / 2)) { +- // fix no menu borders in Adwaita theme ++ if (border == img.getRGB(w / 2, h / 2)) { ++ // fix no menu borders + Graphics g2 = img.getGraphics(); + Color c = new Color(border); + g2.setColor(new Color(Math.max((int) (c.getRed() * 0.8), 0), +-- +2.33.0 + diff --git a/Backport-JDK-8337334-Test-tools-javac-7142086-T71420.patch b/Backport-JDK-8337334-Test-tools-javac-7142086-T71420.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e8b3867d9f873a4a43453cede27f3951ba91eab --- /dev/null +++ b/Backport-JDK-8337334-Test-tools-javac-7142086-T71420.patch @@ -0,0 +1,54 @@ +Subject: Backport JDK-8337334 Test tools/javac/7142086/T7142086.java timeout with fastdebug binary + +--- + test/langtools/TEST.ROOT | 3 ++- + test/langtools/tools/javac/7142086/T7142086.java | 12 ++++++++++-- + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT +index da884dee1..938c7674b 100644 +--- a/test/langtools/TEST.ROOT ++++ b/test/langtools/TEST.ROOT +@@ -42,4 +42,5 @@ requires.extraPropDefns.vmOpts = \ + -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED + requires.properties= \ +- vm.continuations ++ vm.continuations \ ++ vm.debug +diff --git a/test/langtools/tools/javac/7142086/T7142086.java b/test/langtools/tools/javac/7142086/T7142086.java +index bc8260bd4..b6521b7ff 100644 +--- a/test/langtools/tools/javac/7142086/T7142086.java ++++ b/test/langtools/tools/javac/7142086/T7142086.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2012, 2024, 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 +@@ -23,12 +23,20 @@ + + /* + * @test +- * @bug 7142086 ++ * @bug 7142086 8337334 ++ * @requires vm.debug == false + * @summary performance problem in Check.checkOverrideClashes(...) + * @modules jdk.compiler + * @run main/timeout=10 T7142086 + */ + ++/* ++ * @test ++ * @requires vm.debug == true ++ * @modules jdk.compiler ++ * @run main/timeout=20 T7142086 ++ */ ++ + import com.sun.source.util.JavacTask; + import java.net.URI; + import java.util.List; +-- +2.33.0 + diff --git a/Backport-JDK-8337679-Memset-warning-in-src-hotspot-s.patch b/Backport-JDK-8337679-Memset-warning-in-src-hotspot-s.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad77865350a1caaeff5c0b5db0ad00e4a02cbbb7 --- /dev/null +++ b/Backport-JDK-8337679-Memset-warning-in-src-hotspot-s.patch @@ -0,0 +1,29 @@ +Subject: Backport JDK-8337679 Memset warning in src/hotspot/share/adlc/adlArena.cpp + +--- + src/hotspot/share/adlc/adlArena.cpp | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/hotspot/share/adlc/adlArena.cpp b/src/hotspot/share/adlc/adlArena.cpp +index d29a255a9..f0f489d90 100644 +--- a/src/hotspot/share/adlc/adlArena.cpp ++++ b/src/hotspot/share/adlc/adlArena.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1998, 2024, 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 +@@ -62,8 +62,6 @@ void AdlChunk::chop() { + AdlChunk *k = this; + while( k ) { + AdlChunk *tmp = k->_next; +- // clear out this chunk (to detect allocation bugs) +- memset(k, 0xBE, k->_len); + free(k); // Free chunk (was malloc'd) + k = tmp; + } +-- +2.33.0 + diff --git a/Backport-JDK-8338010-WB_IsFrameDeoptimized-miss-Reso.patch b/Backport-JDK-8338010-WB_IsFrameDeoptimized-miss-Reso.patch new file mode 100644 index 0000000000000000000000000000000000000000..761150fd686eccb1b7b44329ea546542eba25dc9 --- /dev/null +++ b/Backport-JDK-8338010-WB_IsFrameDeoptimized-miss-Reso.patch @@ -0,0 +1,28 @@ +Subject: Backport JDK-8338010 WB_IsFrameDeoptimized miss ResourceMark + +--- + src/hotspot/share/prims/whitebox.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp +index 4a7e69ca8..f83e84e30 100644 +--- a/src/hotspot/share/prims/whitebox.cpp ++++ b/src/hotspot/share/prims/whitebox.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2012, 2024, 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 +@@ -771,6 +771,7 @@ WB_END + WB_ENTRY(jboolean, WB_IsFrameDeoptimized(JNIEnv* env, jobject o, jint depth)) + bool result = false; + if (thread->has_last_Java_frame()) { ++ ResourceMark rm(THREAD); + RegisterMap reg_map(thread, + RegisterMap::UpdateMap::include, + RegisterMap::ProcessFrames::include, +-- +2.33.0 + diff --git a/Backport-JDK-8338938-The-result-of-the-combine-metho.patch b/Backport-JDK-8338938-The-result-of-the-combine-metho.patch new file mode 100644 index 0000000000000000000000000000000000000000..a5ff5fc93fcaec38a1c44a19e61e26aff3b17e80 --- /dev/null +++ b/Backport-JDK-8338938-The-result-of-the-combine-metho.patch @@ -0,0 +1,82 @@ +Subject: Backport JDK-8338938 The result of the combine method of SettingsControl is not used + +--- + .../classes/jdk/jfr/internal/Control.java | 4 +-- + .../jfr/api/settings/TestFilterEvents.java | 31 ++++++++++++++++++- + 2 files changed, 32 insertions(+), 3 deletions(-) + +diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java +index 339346bd6..fbc4d4c91 100644 +--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java ++++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2016, 2024, 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 +@@ -136,7 +136,7 @@ final class Control { + @Override + public String run() { + try { +- delegate.combine(Collections.unmodifiableSet(values)); ++ return delegate.combine(Collections.unmodifiableSet(values)); + } catch (Throwable t) { + // Prevent malicious user to propagate exception callback in the wrong context + Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occurred when combining " + values + " for " + getClass()); +diff --git a/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java b/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java +index 42bfc3176..67619fb10 100644 +--- a/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java ++++ b/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, 2024, 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 +@@ -70,6 +70,7 @@ public class TestFilterEvents { + continuous.enable(HTTPGetEvent.class).with("threadNames", "\"unused-threadname-1\""); + assertEquals(0, makeProfilingRecording("\"unused-threadname-2\"")); + assertEquals(1, makeProfilingRecording("\"" + Thread.currentThread().getName() + "\"")); ++ assertEquals(2, makeCombineControl()); + continuous.close(); + } + +@@ -94,4 +95,32 @@ public class TestFilterEvents { + } + } + ++ private static int makeCombineControl() throws Exception { ++ try (Recording r1 = new Recording()) { ++ r1.enable(HTTPPostEvent.class).with("uriFilter", "https://www.example.com/list"); ++ r1.start(); ++ ++ try (Recording r2 = new Recording()) { ++ r2.enable(HTTPPostEvent.class).with("uriFilter", "https://www.example.com/get"); ++ r2.start(); ++ ++ HTTPPostEvent e1 = new HTTPPostEvent(); ++ e1.uri = "https://www.example.com/list"; ++ e1.commit(); ++ ++ HTTPPostEvent e2 = new HTTPPostEvent(); ++ e2.uri = "https://www.example.com/get"; ++ e2.commit(); ++ ++ HTTPPostEvent e3 = new HTTPPostEvent(); ++ e3.uri = "https://www.example.com/put"; ++ e3.commit(); ++ } ++ ++ r1.stop(); ++ ++ return Events.fromRecording(r1).size(); ++ } ++ } ++ + } +-- +2.33.0 + diff --git a/Backport-JDK-8339460-CDS-error-when-module-is-locate.patch b/Backport-JDK-8339460-CDS-error-when-module-is-locate.patch new file mode 100644 index 0000000000000000000000000000000000000000..66e3b4bcd82ce46059342d6ac2a35f7ab35518c4 --- /dev/null +++ b/Backport-JDK-8339460-CDS-error-when-module-is-locate.patch @@ -0,0 +1,486 @@ +Subject: Backport JDK-8339460 CDS error when module is located in a directory with space in the name + +--- + src/hotspot/share/cds/classListParser.cpp | 6 +- + src/hotspot/share/cds/classListWriter.cpp | 4 +- + src/hotspot/share/cds/filemap.cpp | 4 +- + src/hotspot/share/classfile/classLoader.cpp | 50 +++++- + src/hotspot/share/classfile/classLoader.hpp | 4 +- + .../share/classfile/classLoaderExt.cpp | 12 +- + test/hotspot/jtreg/TEST.groups | 3 +- + .../cds/appcds/complexURI/ComplexURITest.java | 167 ++++++++++++++++++ + .../appcds/complexURI/mypackage/Another.java | 27 +++ + .../cds/appcds/complexURI/mypackage/Main.java | 37 ++++ + 10 files changed, 296 insertions(+), 18 deletions(-) + create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java + create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java + create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java + +diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp +index a1e1a4131..0ba74ca4e 100644 +--- a/src/hotspot/share/cds/classListParser.cpp ++++ b/src/hotspot/share/cds/classListParser.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, 2024, 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 +@@ -472,7 +472,9 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS + THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); + } + +- InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL); ++ ResourceMark rm; ++ char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source)); ++ InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL); + if (k->local_interfaces()->length() != _interfaces->length()) { + print_specified_interfaces(); + print_actual_interfaces(k); +diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp +index 2a65ee51d..53637429a 100644 +--- a/src/hotspot/share/cds/classListWriter.cpp ++++ b/src/hotspot/share/cds/classListWriter.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, 2024, 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 +@@ -171,6 +171,8 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre + } + } + ++ // NB: the string following "source: " is not really a proper file name, but rather ++ // a truncated URI referring to a file. It must be decoded after reading. + #ifdef _WINDOWS + // "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar" + stream->print(" source: %s", cfs->source() + 6); +diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp +index 023c0762a..f56920c64 100644 +--- a/src/hotspot/share/cds/filemap.cpp ++++ b/src/hotspot/share/cds/filemap.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2003, 2024, 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 +@@ -583,7 +583,7 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) { + + // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table() + ResourceMark rm; +- const char* file = ClassLoader::skip_uri_protocol(location->as_C_string()); ++ const char* file = ClassLoader::uri_to_path(location->as_C_string()); + for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) { + SharedClassPathEntry* ent = shared_path(i); + assert(ent->in_named_module(), "must be"); +diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp +index 5e89673a5..74b9d9300 100644 +--- a/src/hotspot/share/classfile/classLoader.cpp ++++ b/src/hotspot/share/classfile/classLoader.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2024, 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 +@@ -78,6 +78,9 @@ + #include "utilities/macros.hpp" + #include "utilities/utf8.hpp" + ++#include ++#include ++ + // Entry point in java.dll for path canonicalization + + typedef int (*canonicalize_fn_t)(const char *orig, char *out, int len); +@@ -1223,7 +1226,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR + } + + #if INCLUDE_CDS +-char* ClassLoader::skip_uri_protocol(char* source) { ++static const char* skip_uri_protocol(const char* source) { + if (strncmp(source, "file:", 5) == 0) { + // file: protocol path could start with file:/ or file:/// + // locate the char after all the forward slashes +@@ -1242,6 +1245,47 @@ char* ClassLoader::skip_uri_protocol(char* source) { + return source; + } + ++static char decode_percent_encoded(const char *str, size_t& index) { ++ if (str[index] == '%' ++ && isxdigit(str[index + 1]) ++ && isxdigit(str[index + 2])) { ++ char hex[3]; ++ hex[0] = str[index + 1]; ++ hex[1] = str[index + 2]; ++ hex[2] = '\0'; ++ index += 2; ++ return (char) strtol(hex, NULL, 16); ++ } ++ return str[index]; ++} ++ ++char* ClassLoader::uri_to_path(const char* uri) { ++ const size_t len = strlen(uri) + 1; ++ char* path = NEW_RESOURCE_ARRAY(char, len); ++ ++ uri = skip_uri_protocol(uri); ++ ++ if (strncmp(uri, "//", 2) == 0) { ++ // Skip the empty "authority" part ++ uri += 2; ++ } ++ ++#ifdef _WINDOWS ++ if (uri[0] == '/') { ++ // Absolute path name on Windows does not begin with a slash ++ uri += 1; ++ } ++#endif ++ ++ size_t path_index = 0; ++ for (size_t i = 0; i < strlen(uri); ++i) { ++ char decoded = decode_percent_encoded(uri, i); ++ path[path_index++] = decoded; ++ } ++ path[path_index] = '\0'; ++ return path; ++} ++ + // Record the shared classpath index and loader type for classes loaded + // by the builtin loaders at dump time. + void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, +@@ -1275,7 +1319,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, + // Save the path from the file: protocol or the module name from the jrt: protocol + // if no protocol prefix is found, path is the same as stream->source(). This path + // must be valid since the class has been successfully parsed. +- char* path = skip_uri_protocol(src); ++ const char* path = ClassLoader::uri_to_path(src); + assert(path != nullptr, "sanity"); + for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) { + SharedClassPathEntry* ent = FileMapInfo::shared_path(i); +diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp +index 4cb196719..2f464063e 100644 +--- a/src/hotspot/share/classfile/classLoader.hpp ++++ b/src/hotspot/share/classfile/classLoader.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2024, 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 +@@ -364,7 +364,7 @@ class ClassLoader: AllStatic { + // entries during shared classpath setup time. + static int num_module_path_entries(); + static void exit_with_path_failure(const char* error, const char* message); +- static char* skip_uri_protocol(char* source); ++ static char* uri_to_path(const char* uri); + static void record_result(JavaThread* current, InstanceKlass* ik, + const ClassFileStream* stream, bool redefined); + #endif +diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp +index c9fd8173b..5334b118e 100644 +--- a/src/hotspot/share/classfile/classLoaderExt.cpp ++++ b/src/hotspot/share/classfile/classLoaderExt.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, 2024, 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 +@@ -98,12 +98,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* + ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : + _current(current), _module_paths(module_paths) {} + void do_module(ModuleEntry* m) { +- char* path = m->location()->as_C_string(); +- if (strncmp(path, "file:", 5) == 0) { +- path = ClassLoader::skip_uri_protocol(path); +- char* path_copy = NEW_RESOURCE_ARRAY(char, strlen(path) + 1); +- strcpy(path_copy, path); +- _module_paths->append(path_copy); ++ char* uri = m->location()->as_C_string(); ++ if (strncmp(uri, "file:", 5) == 0) { ++ char* path = ClassLoader::uri_to_path(uri); ++ _module_paths->append(path); + } + } + }; +diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups +index 4923fbd5b..4c7352956 100644 +--- a/test/hotspot/jtreg/TEST.groups ++++ b/test/hotspot/jtreg/TEST.groups +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. ++# Copyright (c) 2013, 2024, 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 +@@ -430,6 +430,7 @@ hotspot_cds_only = \ + hotspot_appcds_dynamic = \ + runtime/cds/appcds/ \ + -runtime/cds/appcds/cacheObject \ ++ -runtime/cds/appcds/complexURI \ + -runtime/cds/appcds/customLoader \ + -runtime/cds/appcds/dynamicArchive \ + -runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \ +diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java +new file mode 100644 +index 000000000..409e37e10 +--- /dev/null ++++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java +@@ -0,0 +1,167 @@ ++/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2024 JetBrains s.r.o. ++ * 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. ++ */ ++ ++/* ++ * @test ++ * @summary Verifies that CDS works with jar located in directories ++ * with names that need escaping ++ * @bug 8339460 ++ * @requires vm.cds ++ * @requires vm.cds.custom.loaders ++ * @requires vm.flagless ++ * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds ++ * @compile mypackage/Main.java mypackage/Another.java ++ * @run main/othervm ComplexURITest ++ */ ++ ++import jdk.test.lib.process.OutputAnalyzer; ++import jdk.test.lib.process.ProcessTools; ++import jdk.test.lib.Platform; ++ ++import java.io.File; ++import java.nio.file.Files; ++import java.nio.file.Path; ++ ++public class ComplexURITest { ++ final static String moduleName = "mymodule"; ++ ++ public static void main(String[] args) throws Exception { ++ System.setProperty("test.noclasspath", "true"); ++ String jarFile = JarBuilder.build(moduleName, "mypackage/Main", "mypackage/Another"); ++ ++ Path subDir = Path.of(".", "dir with space"); ++ Files.createDirectory(subDir); ++ Path newJarFilePath = subDir.resolve(moduleName + ".jar"); ++ Files.move(Path.of(jarFile), newJarFilePath); ++ jarFile = newJarFilePath.toString(); ++ ++ final String listFileName = "test-classlist.txt"; ++ final String staticArchiveName = "test-static.jsa"; ++ final String dynamicArchiveName = "test-dynamic.jsa"; ++ ++ // Verify static archive creation and use ++ File fileList = new File(listFileName); ++ delete(fileList.toPath()); ++ File staticArchive = new File(staticArchiveName); ++ delete(staticArchive.toPath()); ++ ++ createClassList(jarFile, listFileName); ++ if (!fileList.exists()) { ++ throw new RuntimeException("No class list created at " + fileList); ++ } ++ ++ createArchive(jarFile, listFileName, staticArchiveName); ++ if (!staticArchive.exists()) { ++ throw new RuntimeException("No shared classes archive created at " + staticArchive); ++ } ++ ++ useArchive(jarFile, staticArchiveName); ++ ++ // Verify dynamic archive creation and use ++ File dynamicArchive = new File(dynamicArchiveName); ++ delete(dynamicArchive.toPath()); ++ ++ createDynamicArchive(jarFile, dynamicArchiveName); ++ if (!dynamicArchive.exists()) { ++ throw new RuntimeException("No dynamic archive created at " + dynamicArchive); ++ } ++ ++ testDynamicArchive(jarFile, dynamicArchiveName); ++ } ++ ++ private static void delete(Path path) throws Exception { ++ if (Files.exists(path)) { ++ if (Platform.isWindows()) { ++ Files.setAttribute(path, "dos:readonly", false); ++ } ++ Files.delete(path); ++ } ++ } ++ ++ private static void createClassList(String jarFile, String list) throws Exception { ++ String[] launchArgs = { ++ "-XX:DumpLoadedClassList=" + list, ++ "--module-path", ++ jarFile, ++ "--module", ++ moduleName + "/mypackage.Main"}; ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); ++ OutputAnalyzer output = TestCommon.executeAndLog(pb, "create-list"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void createArchive(String jarFile, String list, String archive) throws Exception { ++ String[] launchArgs = { ++ "-Xshare:dump", ++ "-XX:SharedClassListFile=" + list, ++ "-XX:SharedArchiveFile=" + archive, ++ "--module-path", ++ jarFile, ++ "--module", ++ moduleName + "/mypackage.Main"}; ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); ++ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dump-archive"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void useArchive(String jarFile, String archive) throws Exception { ++ String[] launchArgs = { ++ "-Xshare:on", ++ "-XX:SharedArchiveFile=" + archive, ++ "--module-path", ++ jarFile, ++ "--module", ++ moduleName + "/mypackage.Main"}; ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); ++ OutputAnalyzer output = TestCommon.executeAndLog(pb, "use-archive"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void createDynamicArchive(String jarFile, String archive) throws Exception { ++ String[] launchArgs = { ++ "-XX:ArchiveClassesAtExit=" + archive, ++ "--module-path", ++ jarFile, ++ "--module", ++ moduleName + "/mypackage.Main"}; ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); ++ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void testDynamicArchive(String jarFile, String archive) throws Exception { ++ String[] launchArgs = { ++ "-XX:SharedArchiveFile=" + archive, ++ "-XX:+PrintSharedArchiveAndExit", ++ "--module-path", ++ jarFile, ++ "--module", ++ moduleName + "/mypackage.Main"}; ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); ++ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive"); ++ output.shouldHaveExitValue(0); ++ output.shouldContain("archive is valid"); ++ output.shouldContain(": mypackage.Main app_loader"); ++ output.shouldContain(": mypackage.Another unregistered_loader"); ++ } ++} +diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java +new file mode 100644 +index 000000000..106dfd490 +--- /dev/null ++++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java +@@ -0,0 +1,27 @@ ++/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2024 JetBrains s.r.o. ++ * 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. ++ */ ++ ++package mypackage; ++ ++public class Another { ++} +diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java +new file mode 100644 +index 000000000..fdb79e895 +--- /dev/null ++++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java +@@ -0,0 +1,37 @@ ++/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2024 JetBrains s.r.o. ++ * 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. ++ */ ++ ++package mypackage; ++ ++import java.net.URL; ++import java.net.URLClassLoader; ++ ++public class Main { ++ public static void main(String[] args) throws Exception { ++ URL url1 = Main.class.getProtectionDomain().getCodeSource().getLocation(); ++ System.out.println("Will load Another from " + url1); ++ ClassLoader cl = URLClassLoader.newInstance(new URL[] { url1 }, null); ++ var anotherClass = cl.loadClass("mypackage.Another"); ++ System.out.println("Class " + anotherClass + " loaded successfully"); ++ } ++} +-- +2.33.0 + diff --git a/Backport-JDK-8340186-Shenandoah-Missing-load_referen.patch b/Backport-JDK-8340186-Shenandoah-Missing-load_referen.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6ca198fea54edc5040a5fe9bfae3607ee427be2 --- /dev/null +++ b/Backport-JDK-8340186-Shenandoah-Missing-load_referen.patch @@ -0,0 +1,30 @@ +Subject: Backport JDK-8340186 Shenandoah: Missing load_reference_barrier_phantom_narrow match in is_shenandoah_lrb_call + +--- + .../share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +index ac3afa774..da9fd5466 100644 +--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp ++++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. ++ * Copyright (c) 2018, 2023, Red Hat, Inc. 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 +@@ -306,7 +306,8 @@ bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) { + (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow)) || + (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)) || + (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow)) || +- (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)); ++ (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)) || ++ (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom_narrow)); + } + + bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseValues* phase, Node* n) { +-- +2.33.0 + diff --git a/Backport-JDK-8340273-Remove-CounterHalfLifeTime.patch b/Backport-JDK-8340273-Remove-CounterHalfLifeTime.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9162b39846e7fe3ad7b5cb31551865b9d913b1a --- /dev/null +++ b/Backport-JDK-8340273-Remove-CounterHalfLifeTime.patch @@ -0,0 +1,23 @@ +Subject: Backport JDK-8340273 Remove CounterHalfLifeTime + +--- + src/hotspot/share/runtime/globals.hpp | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp +index a066d0d37..6f8b3e85e 100644 +--- a/src/hotspot/share/runtime/globals.hpp ++++ b/src/hotspot/share/runtime/globals.hpp +@@ -1221,9 +1221,6 @@ const int ObjectAlignmentInBytes = 8; + product(bool, UseCounterDecay, true, \ + "Adjust recompilation counters") \ + \ +- develop(intx, CounterHalfLifeTime, 30, \ +- "Half-life time of invocation counters (in seconds)") \ +- \ + develop(intx, CounterDecayMinIntervalLength, 500, \ + "The minimum interval (in milliseconds) between invocation of " \ + "CounterDecay") \ +-- +2.33.0 + diff --git a/Backport-JDK-8340623-Remove-outdated-PROCESSOR_ARCHI.patch b/Backport-JDK-8340623-Remove-outdated-PROCESSOR_ARCHI.patch new file mode 100644 index 0000000000000000000000000000000000000000..39e485f618f56119537df41166806a3cf7cd297b --- /dev/null +++ b/Backport-JDK-8340623-Remove-outdated-PROCESSOR_ARCHI.patch @@ -0,0 +1,23 @@ +Subject: Backport JDK-8340623 Remove outdated PROCESSOR_ARCHITECTURE_IA64 from Windows coding + +--- + src/java.base/windows/native/libjava/java_props_md.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c +index 2ff4c9e88..280747d0d 100644 +--- a/src/java.base/windows/native/libjava/java_props_md.c ++++ b/src/java.base/windows/native/libjava/java_props_md.c +@@ -263,9 +263,6 @@ cpu_isalist(void) + SYSTEM_INFO info; + GetSystemInfo(&info); + switch (info.wProcessorArchitecture) { +-#ifdef PROCESSOR_ARCHITECTURE_IA64 +- case PROCESSOR_ARCHITECTURE_IA64: return "ia64"; +-#endif + #ifdef PROCESSOR_ARCHITECTURE_AMD64 + case PROCESSOR_ARCHITECTURE_AMD64: return "amd64"; + #endif +-- +2.33.0 + diff --git a/Backport-JDK-8343555-RISC-V-make-some-verified-on-ha.patch b/Backport-JDK-8343555-RISC-V-make-some-verified-on-ha.patch new file mode 100644 index 0000000000000000000000000000000000000000..95b0e8f31e691edba2d5f5020a6b1d63024b6408 --- /dev/null +++ b/Backport-JDK-8343555-RISC-V-make-some-verified-on-ha.patch @@ -0,0 +1,31 @@ +From 2966967606532deac3dde80fcdbce301eecc19d1 Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Mon, 17 Mar 2025 16:28:35 +0800 +Subject: [PATCH] Backport JDK-8343555: RISC-V: make some verified (on + hardware) extension options diagnostic + + +diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp +index 85aaa3d239d..2ee0b4b9421 100644 +--- a/src/hotspot/cpu/riscv/globals_riscv.hpp ++++ b/src/hotspot/cpu/riscv/globals_riscv.hpp +@@ -101,11 +101,11 @@ define_pd_global(intx, InlineSmallCode, 1000); + product(bool, UseRVA20U64, true, "Use RVA20U64 profile") \ + product(bool, UseRVA22U64, false, EXPERIMENTAL, "Use RVA22U64 profile") \ + product(bool, UseRVA23U64, false, EXPERIMENTAL, "Use RVA23U64 profile") \ +- product(bool, UseRVC, false, "Use RVC instructions") \ +- product(bool, UseRVV, false, "Use RVV instructions") \ +- product(bool, UseZba, false, "Use Zba instructions") \ +- product(bool, UseZbb, false, "Use Zbb instructions") \ +- product(bool, UseZbs, false, "Use Zbs instructions") \ ++ product(bool, UseRVC, false, DIAGNOSTIC, "Use RVC instructions") \ ++ product(bool, UseRVV, false, DIAGNOSTIC, "Use RVV instructions") \ ++ product(bool, UseZba, false, DIAGNOSTIC, "Use Zba instructions") \ ++ product(bool, UseZbb, false, DIAGNOSTIC, "Use Zbb instructions") \ ++ product(bool, UseZbs, false, DIAGNOSTIC, "Use Zbs instructions") \ + product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \ + product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \ + product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \ +-- +2.34.1 + diff --git a/Backport-JDK-8348384-RISC-V-Disable-auto-enable-Vect.patch b/Backport-JDK-8348384-RISC-V-Disable-auto-enable-Vect.patch new file mode 100644 index 0000000000000000000000000000000000000000..222968ccda3d0e4a40844da7ad50218046416ca0 --- /dev/null +++ b/Backport-JDK-8348384-RISC-V-Disable-auto-enable-Vect.patch @@ -0,0 +1,43 @@ +From 0310b533d409704f349b9e9bf861ee6afb9d67ee Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Mon, 17 Mar 2025 16:31:52 +0800 +Subject: [PATCH] Backport JDK-8348384: RISC-V: Disable auto-enable Vector on + buggy kernels + + +diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +index 243c4b850ee..991ce07bb7c 100644 +--- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp ++++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +@@ -25,6 +25,8 @@ + + #include "precompiled.hpp" + #include "logging/log.hpp" ++#include "logging/logMessage.hpp" ++#include "os_linux.hpp" + #include "riscv_hwprobe.hpp" + #include "runtime/os.hpp" + #include "runtime/vm_version.hpp" +@@ -134,7 +136,18 @@ void RiscvHwprobe::add_features_from_query_result() { + VM_Version::ext_C.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_V)) { +- VM_Version::ext_V.enable_feature(); ++ // Linux signal return bug when using vector with vlen > 128b in pre 6.8.5. ++ long major, minor, patch; ++ os::Linux::kernel_version(&major, &minor, &patch); ++ if (os::Linux::kernel_version_compare(major, minor, patch, 6, 8, 5) == -1) { ++ LogMessage(os) log; ++ if (log.is_info()) { ++ log.info("Linux kernels before 6.8.5 (current %ld.%ld.%ld) have a known bug when using Vector and signals.", major, minor, patch); ++ log.info("Vector not enabled automatically via hwprobe, but can be turned on with -XX:+UseRVV."); ++ } ++ } else { ++ VM_Version::ext_V.enable_feature(); ++ } + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBA)) { + VM_Version::ext_Zba.enable_feature(); +-- +2.34.1 + diff --git a/Backport-JDK-8348554-Enhance-Linux-kernel-version-ch.patch b/Backport-JDK-8348554-Enhance-Linux-kernel-version-ch.patch new file mode 100644 index 0000000000000000000000000000000000000000..0e74d63883d714b350a9d8c2d4fe87c28cb76ec5 --- /dev/null +++ b/Backport-JDK-8348554-Enhance-Linux-kernel-version-ch.patch @@ -0,0 +1,100 @@ +From 2565e265b0381ed00428d33fc8040d9367ee394d Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Mon, 17 Mar 2025 16:31:03 +0800 +Subject: [PATCH] Backport JDK-8348554: Enhance Linux kernel version checks + + +diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp +index 7cb862d7c3e..22216a568bc 100644 +--- a/src/hotspot/os/linux/os_linux.cpp ++++ b/src/hotspot/os/linux/os_linux.cpp +@@ -311,9 +311,10 @@ static void next_line(FILE *f) { + } while (c != '\n' && c != EOF); + } + +-void os::Linux::kernel_version(long* major, long* minor) { +- *major = -1; +- *minor = -1; ++void os::Linux::kernel_version(long* major, long* minor, long* patch) { ++ *major = 0; ++ *minor = 0; ++ *patch = 0; + + struct utsname buffer; + int ret = uname(&buffer); +@@ -321,12 +322,29 @@ void os::Linux::kernel_version(long* major, long* minor) { + log_warning(os)("uname(2) failed to get kernel version: %s", os::errno_name(ret)); + return; + } +- int nr_matched = sscanf(buffer.release, "%ld.%ld", major, minor); +- if (nr_matched != 2) { +- log_warning(os)("Parsing kernel version failed, expected 2 version numbers, only matched %d", nr_matched); ++ int nr_matched = sscanf(buffer.release, "%ld.%ld.%ld", major, minor, patch); ++ if (nr_matched != 3) { ++ log_warning(os)("Parsing kernel version failed, expected 3 version numbers, only matched %d", nr_matched); + } + } + ++int os::Linux::kernel_version_compare(long major1, long minor1, long patch1, ++ long major2, long minor2, long patch2) { ++ // Compare major versions ++ if (major1 > major2) return 1; ++ if (major1 < major2) return -1; ++ ++ // Compare minor versions ++ if (minor1 > minor2) return 1; ++ if (minor1 < minor2) return -1; ++ ++ // Compare patchlevel versions ++ if (patch1 > patch2) return 1; ++ if (patch1 < patch2) return -1; ++ ++ return 0; ++} ++ + bool os::Linux::get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu) { + FILE* fh; + uint64_t userTicks, niceTicks, systemTicks, idleTicks; +diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp +index 029f2aa7a52..f2901480d29 100644 +--- a/src/hotspot/os/linux/os_linux.hpp ++++ b/src/hotspot/os/linux/os_linux.hpp +@@ -109,7 +109,13 @@ class os::Linux { + bool has_steal_ticks; + }; + +- static void kernel_version(long* major, long* minor); ++ static void kernel_version(long* major, long* minor, long* patch); ++ ++ // If kernel1 > kernel2 return 1 ++ // If kernel1 < kernel2 return -1 ++ // If kernel1 = kernel2 return 0 ++ static int kernel_version_compare(long major1, long minor1, long patch1, ++ long major2, long minor2, long patch2); + + // which_logical_cpu=-1 returns accumulated ticks for all cpus. + static bool get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu); +diff --git a/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp b/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp +index 51397b139d8..43122a58bce 100644 +--- a/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp ++++ b/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp +@@ -76,11 +76,11 @@ bool LinuxSystemMemoryBarrier::initialize() { + // RISCV port was introduced in kernel 4.4. + // 4.4 also made membar private expedited mandatory. + // But RISCV actually don't support it until 6.9. +- long major, minor; +- os::Linux::kernel_version(&major, &minor); +- if (!(major > 6 || (major == 6 && minor >= 9))) { +- log_info(os)("Linux kernel %ld.%ld does not support MEMBARRIER PRIVATE_EXPEDITED on RISC-V.", +- major, minor); ++ long major, minor, patch; ++ os::Linux::kernel_version(&major, &minor, &patch); ++ if (os::Linux::kernel_version_compare(major, minor, patch, 6, 9, 0) == -1) { ++ log_info(os)("Linux kernel %ld.%ld.%ld does not support MEMBARRIER PRIVATE_EXPEDITED on RISC-V.", ++ major, minor, patch); + return false; + } + #endif +-- +2.34.1 + diff --git a/Backport-JDK-8352673-RISC-V-Vector-can-t-be-turned-o.patch b/Backport-JDK-8352673-RISC-V-Vector-can-t-be-turned-o.patch new file mode 100644 index 0000000000000000000000000000000000000000..437e724ca9e21e1586e1c74c7a87aa2d18b6b663 --- /dev/null +++ b/Backport-JDK-8352673-RISC-V-Vector-can-t-be-turned-o.patch @@ -0,0 +1,23 @@ +From fc255c7c11af6a3e60e3cdd74ae0986579adbaae Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Tue, 29 Apr 2025 22:41:45 +0800 +Subject: [PATCH] Backport JDK-8352673: RISC-V: Vector can't be turned on with + -XX:+UseRVV + + +diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +index febe7cc0d73..97ac3a2e1d4 100644 +--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp ++++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +@@ -166,7 +166,7 @@ void VM_Version::initialize() { + } + + if (UseRVV) { +- if (!ext_V.enabled()) { ++ if (!ext_V.enabled() && FLAG_IS_DEFAULT(UseRVV)) { + warning("RVV is not supported on this CPU"); + FLAG_SET_DEFAULT(UseRVV, false); + } else { +-- +2.34.1 + diff --git a/Backport-JDK-8355878-RISC-V-jdk-incubator-vector-Dou.patch b/Backport-JDK-8355878-RISC-V-jdk-incubator-vector-Dou.patch new file mode 100644 index 0000000000000000000000000000000000000000..a898ee969ade23a5ca2ff7dcb9e118d7f8962485 --- /dev/null +++ b/Backport-JDK-8355878-RISC-V-jdk-incubator-vector-Dou.patch @@ -0,0 +1,34 @@ +From 5724de06f17cae3db89c911674d0b1906403af45 Mon Sep 17 00:00:00 2001 +From: Dingli Zhang +Date: Tue, 29 Apr 2025 22:42:53 +0800 +Subject: [PATCH] Backport JDK-8355878: RISC-V: + jdk/incubator/vector/DoubleMaxVectorTests.java fails when using RVV + + +diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad +index 148cf8dd3ae..d47b3a0502f 100644 +--- a/src/hotspot/cpu/riscv/riscv.ad ++++ b/src/hotspot/cpu/riscv/riscv.ad +@@ -1609,7 +1609,8 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo + __ unspill(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo)); + } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) { + // vpr to vpr +- __ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); ++ __ vsetvli_helper(T_BYTE, MaxVectorSize); ++ __ vmv_v_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); + } else { + ShouldNotReachHere(); + } +@@ -1628,7 +1629,8 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo + __ unspill_vmask(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo)); + } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) { + // vmask to vmask +- __ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); ++ __ vsetvli_helper(T_BYTE, MaxVectorSize >> 3); ++ __ vmv_v_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); + } else { + ShouldNotReachHere(); + } +-- +2.34.1 + diff --git a/Backport-of-8330191-Fix-typo-in-precompiled.hpp.patch b/Backport-of-8330191-Fix-typo-in-precompiled.hpp.patch new file mode 100644 index 0000000000000000000000000000000000000000..d9c97268b8e578ecc5eab9a89eae37b73109c5d8 --- /dev/null +++ b/Backport-of-8330191-Fix-typo-in-precompiled.hpp.patch @@ -0,0 +1,29 @@ +Subject: Backport of 8330191: Fix typo in precompiled.hpp + +--- + src/hotspot/share/precompiled/precompiled.hpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp +index c6b866801..e8dec0fc6 100644 +--- a/src/hotspot/share/precompiled/precompiled.hpp ++++ b/src/hotspot/share/precompiled/precompiled.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2010, 2024, 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 +@@ -29,7 +29,7 @@ + + // These header files are included in at least 130 C++ files, as of + // measurements made in November 2018. This list excludes files named +-// *.include.hpp, since including them decreased build performance. ++// *.incline.hpp, since including them decreased build performance. + + #include "classfile/classLoaderData.hpp" + #include "classfile/javaClasses.hpp" +-- +2.33.0 + diff --git a/Backport-of-8337245-Fix-wrong-comment-of-StringConca.patch b/Backport-of-8337245-Fix-wrong-comment-of-StringConca.patch new file mode 100644 index 0000000000000000000000000000000000000000..4893b74bc6e6df95b700c1ddc2aa22dbd60535ca --- /dev/null +++ b/Backport-of-8337245-Fix-wrong-comment-of-StringConca.patch @@ -0,0 +1,49 @@ +Subject: Backport of 8337245: Fix wrong comment of StringConcatHelper + +--- + .../share/classes/java/lang/StringConcatHelper.java | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java +index 139181af0..db4b2d690 100644 +--- a/src/java.base/share/classes/java/lang/StringConcatHelper.java ++++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java +@@ -228,7 +228,7 @@ final class StringConcatHelper { + * @param indexCoder final char index in the buffer, along with coder packed + * into higher bits. + * @param buf buffer to append to +- * @param value boolean value to encode ++ * @param value char value to encode + * @param prefix a constant to prepend before value + * @return updated index (coder value retained) + */ +@@ -263,7 +263,7 @@ final class StringConcatHelper { + * @param indexCoder final char index in the buffer, along with coder packed + * into higher bits. + * @param buf buffer to append to +- * @param value boolean value to encode ++ * @param value int value to encode + * @param prefix a constant to prepend before value + * @return updated index (coder value retained) + */ +@@ -298,7 +298,7 @@ final class StringConcatHelper { + * @param indexCoder final char index in the buffer, along with coder packed + * into higher bits. + * @param buf buffer to append to +- * @param value boolean value to encode ++ * @param value long value to encode + * @param prefix a constant to prepend before value + * @return updated index (coder value retained) + */ +@@ -335,7 +335,7 @@ final class StringConcatHelper { + * @param indexCoder final char index in the buffer, along with coder packed + * into higher bits. + * @param buf buffer to append to +- * @param value boolean value to encode ++ * @param value String value to encode + * @param prefix a constant to prepend before value + * @return updated index (coder value retained) + */ +-- +2.33.0 + diff --git a/Backport-of-8337274-Remove-repeated-the.patch b/Backport-of-8337274-Remove-repeated-the.patch new file mode 100644 index 0000000000000000000000000000000000000000..edf753afd38474e6ba815d8ff393e6d0bb66de41 --- /dev/null +++ b/Backport-of-8337274-Remove-repeated-the.patch @@ -0,0 +1,40 @@ +Subject: Backport of 8337274: Remove repeated 'the' + +--- + .../share/classes/javax/swing/text/html/StyleSheet.java | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +index fd3c75829..89e8b63d6 100644 +--- a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java ++++ b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +@@ -688,7 +688,7 @@ public class StyleSheet extends StyleContext { + * to return an AttributeSet that provides some sort of + * attribute conversion. + * +- * @param a The set of attributes to be represented in the ++ * @param a The set of attributes to be represented in + * the compact form. + */ + protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) { +@@ -704,7 +704,7 @@ public class StyleSheet extends StyleContext { + * to return a MutableAttributeSet that provides some sort of + * attribute conversion. + * +- * @param a The set of attributes to be represented in the ++ * @param a The set of attributes to be represented in + * the larger form. + */ + protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) { +@@ -2137,7 +2137,7 @@ public class StyleSheet extends StyleContext { + /** + * Returns a string that represents the value + * of the HTML.Attribute.TYPE attribute. +- * If this attributes is not defined, then ++ * If this attributes is not defined, + * then the type defaults to "disc" unless + * the tag is on Ordered list. In the case + * of the latter, the default type is "decimal". +-- +2.33.0 + diff --git a/Backport-of-8337712-Wrong-javadoc-in-java.util.Date-.patch b/Backport-of-8337712-Wrong-javadoc-in-java.util.Date-.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b4202a9b14c1f888de832ac3e74aaaf2cfb7797 --- /dev/null +++ b/Backport-of-8337712-Wrong-javadoc-in-java.util.Date-.patch @@ -0,0 +1,29 @@ +Subject: Backport of 8337712: Wrong javadoc in java.util.Date#toString(): 61 and right parenthesis + +--- + src/java.base/share/classes/java/util/Date.java | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/java.base/share/classes/java/util/Date.java b/src/java.base/share/classes/java/util/Date.java +index 1850564d8..aa16f2a75 100644 +--- a/src/java.base/share/classes/java/util/Date.java ++++ b/src/java.base/share/classes/java/util/Date.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1994, 2024, 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 +@@ -1012,7 +1012,7 @@ public class Date + *
  • {@code mm} is the minute within the hour ({@code 00} through + * {@code 59}), as two decimal digits. + *
  • {@code ss} is the second within the minute ({@code 00} through +- * {@code 61}, as two decimal digits. ++ * {@code 61}), as two decimal digits. + *
  • {@code zzz} is the time zone (and may reflect daylight saving + * time). Standard time zone abbreviations include those + * recognized by the method {@code parse}. If time zone +-- +2.33.0 + diff --git a/Backport-of-8337787-Fix-Wzero-as-null-pointer-consta.patch b/Backport-of-8337787-Fix-Wzero-as-null-pointer-consta.patch new file mode 100644 index 0000000000000000000000000000000000000000..75838354a5ed8e38e85bd84fa82c4e50b3524aca --- /dev/null +++ b/Backport-of-8337787-Fix-Wzero-as-null-pointer-consta.patch @@ -0,0 +1,33 @@ +Subject: Backport of 8337787: Fix -Wzero-as-null-pointer-constant warnings when JVMTI feature is disabled + +--- + src/hotspot/share/prims/jvmtiExport.hpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp +index 805c8c090..d8e20086b 100644 +--- a/src/hotspot/share/prims/jvmtiExport.hpp ++++ b/src/hotspot/share/prims/jvmtiExport.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1998, 2024, 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 +@@ -279,10 +279,10 @@ class JvmtiExport : public AllStatic { + } + + // field access management +- static address get_field_access_count_addr() NOT_JVMTI_RETURN_(0); ++ static address get_field_access_count_addr() NOT_JVMTI_RETURN_(nullptr); + + // field modification management +- static address get_field_modification_count_addr() NOT_JVMTI_RETURN_(0); ++ static address get_field_modification_count_addr() NOT_JVMTI_RETURN_(nullptr); + + // ----------------- + +-- +2.33.0 + diff --git a/LoongArch64-support.patch b/LoongArch64-support.patch index 8ae6956cdcdc1eab391ff2a601e627e1f4c166ac..8b5d303a676c059ff04048a72719b703782e3c47 100644 --- a/LoongArch64-support.patch +++ b/LoongArch64-support.patch @@ -1,5 +1,486 @@ +From 790b520135eeeb11a6269bb16402d3160998363f Mon Sep 17 00:00:00 2001 +From: songliyang +Date: Wed, 30 Apr 2025 11:20:52 +0800 +Subject: [PATCH] LoongArch64 support + +--- + make/autoconf/jvm-features.m4 | 18 +- + make/autoconf/platform.m4 | 17 + + .../abstractInterpreter_loongarch.cpp | 155 + + .../cpu/loongarch/assembler_loongarch.cpp | 820 + + .../cpu/loongarch/assembler_loongarch.hpp | 3213 ++++ + .../loongarch/assembler_loongarch.inline.hpp | 33 + + src/hotspot/cpu/loongarch/bytes_loongarch.hpp | 64 + + .../loongarch/c1_CodeStubs_loongarch_64.cpp | 338 + + .../cpu/loongarch/c1_Defs_loongarch.hpp | 88 + + .../loongarch/c1_FpuStackSim_loongarch.hpp | 32 + + .../loongarch/c1_FpuStackSim_loongarch_64.cpp | 31 + + .../cpu/loongarch/c1_FrameMap_loongarch.hpp | 143 + + .../loongarch/c1_FrameMap_loongarch_64.cpp | 345 + + .../loongarch/c1_LIRAssembler_loongarch.hpp | 84 + + .../c1_LIRAssembler_loongarch_64.cpp | 3383 ++++ + .../c1_LIRGenerator_loongarch_64.cpp | 1393 ++ + .../cpu/loongarch/c1_LIR_loongarch_64.cpp | 57 + + .../cpu/loongarch/c1_LinearScan_loongarch.hpp | 70 + + .../loongarch/c1_LinearScan_loongarch_64.cpp | 33 + + .../loongarch/c1_MacroAssembler_loongarch.hpp | 111 + + .../c1_MacroAssembler_loongarch_64.cpp | 350 + + .../loongarch/c1_Runtime1_loongarch_64.cpp | 1049 + + .../cpu/loongarch/c1_globals_loongarch.hpp | 64 + + .../cpu/loongarch/c2_CodeStubs_loongarch.cpp | 91 + + .../loongarch/c2_MacroAssembler_loongarch.cpp | 1903 ++ + .../loongarch/c2_MacroAssembler_loongarch.hpp | 141 + + .../cpu/loongarch/c2_globals_loongarch.hpp | 85 + + .../cpu/loongarch/c2_init_loongarch.cpp | 37 + + .../cpu/loongarch/codeBuffer_loongarch.cpp | 32 + + .../cpu/loongarch/codeBuffer_loongarch.hpp | 37 + + .../cpu/loongarch/compiledIC_loongarch.cpp | 138 + + .../loongarch/continuationEntry_loongarch.hpp | 33 + + .../continuationEntry_loongarch.inline.hpp | 52 + + ...ontinuationFreezeThaw_loongarch.inline.hpp | 284 + + .../continuationHelper_loongarch.inline.hpp | 145 + + src/hotspot/cpu/loongarch/copy_loongarch.cpp | 147 + + src/hotspot/cpu/loongarch/copy_loongarch.hpp | 65 + + .../cpu/loongarch/disassembler_loongarch.hpp | 49 + + .../loongarch/downcallLinker_loongarch_64.cpp | 360 + + .../loongarch/foreignGlobals_loongarch.cpp | 195 + + .../loongarch/foreignGlobals_loongarch.hpp | 50 + + src/hotspot/cpu/loongarch/frame_loongarch.cpp | 629 + + src/hotspot/cpu/loongarch/frame_loongarch.hpp | 200 + + .../cpu/loongarch/frame_loongarch.inline.hpp | 472 + + .../gc/g1/g1BarrierSetAssembler_loongarch.cpp | 491 + + .../gc/g1/g1BarrierSetAssembler_loongarch.hpp | 72 + + .../loongarch/gc/g1/g1Globals_loongarch.hpp | 30 + + .../shared/barrierSetAssembler_loongarch.cpp | 453 + + .../shared/barrierSetAssembler_loongarch.hpp | 147 + + .../gc/shared/barrierSetNMethod_loongarch.cpp | 222 + + ...cardTableBarrierSetAssembler_loongarch.cpp | 117 + + ...cardTableBarrierSetAssembler_loongarch.hpp | 44 + + .../modRefBarrierSetAssembler_loongarch.cpp | 53 + + .../modRefBarrierSetAssembler_loongarch.hpp | 54 + + .../c1/shenandoahBarrierSetC1_loongarch.cpp | 130 + + ...henandoahBarrierSetAssembler_loongarch.cpp | 783 + + ...henandoahBarrierSetAssembler_loongarch.hpp | 88 + + .../gc/shenandoah/shenandoah_loongarch_64.ad | 232 + + .../gc/x/xBarrierSetAssembler_loongarch.cpp | 471 + + .../gc/x/xBarrierSetAssembler_loongarch.hpp | 105 + + .../cpu/loongarch/gc/x/xGlobals_loongarch.cpp | 211 + + .../cpu/loongarch/gc/x/xGlobals_loongarch.hpp | 34 + + .../cpu/loongarch/gc/x/x_loongarch_64.ad | 256 + + .../cpu/loongarch/gc/z/zAddress_loongarch.cpp | 109 + + .../cpu/loongarch/gc/z/zAddress_loongarch.hpp | 35 + + .../gc/z/zAddress_loongarch.inline.hpp | 38 + + .../gc/z/zBarrierSetAssembler_loongarch.cpp | 1226 ++ + .../gc/z/zBarrierSetAssembler_loongarch.hpp | 192 + + .../cpu/loongarch/gc/z/zGlobals_loongarch.hpp | 30 + + .../cpu/loongarch/gc/z/z_loongarch_64.ad | 250 + + .../loongarch/globalDefinitions_loongarch.hpp | 58 + + .../cpu/loongarch/globals_loongarch.hpp | 125 + + .../cpu/loongarch/icBuffer_loongarch.cpp | 82 + + .../cpu/loongarch/icache_loongarch.cpp | 42 + + .../cpu/loongarch/icache_loongarch.hpp | 41 + + .../cpu/loongarch/interp_masm_loongarch.hpp | 272 + + .../loongarch/interp_masm_loongarch_64.cpp | 1965 ++ + .../cpu/loongarch/interpreterRT_loongarch.hpp | 62 + + .../loongarch/interpreterRT_loongarch_64.cpp | 264 + + .../loongarch/javaFrameAnchor_loongarch.hpp | 86 + + .../jniFastGetField_loongarch_64.cpp | 179 + + .../cpu/loongarch/jniTypes_loongarch.hpp | 143 + + .../jvmciCodeInstaller_loongarch.cpp | 194 + + src/hotspot/cpu/loongarch/loongarch.ad | 25 + + src/hotspot/cpu/loongarch/loongarch_64.ad | 15888 ++++++++++++++++ + .../loongarch/macroAssembler_loongarch.cpp | 4242 +++++ + .../loongarch/macroAssembler_loongarch.hpp | 809 + + .../macroAssembler_loongarch.inline.hpp | 937 + + .../macroAssembler_loongarch_chacha.cpp | 86 + + .../macroAssembler_loongarch_trig.cpp | 1626 ++ + .../cpu/loongarch/matcher_loongarch.hpp | 181 + + .../cpu/loongarch/methodHandles_loongarch.cpp | 568 + + .../cpu/loongarch/methodHandles_loongarch.hpp | 65 + + .../cpu/loongarch/nativeInst_loongarch.cpp | 537 + + .../cpu/loongarch/nativeInst_loongarch.hpp | 595 + + .../cpu/loongarch/registerMap_loongarch.hpp | 59 + + .../cpu/loongarch/register_loongarch.cpp | 61 + + .../cpu/loongarch/register_loongarch.hpp | 479 + + .../cpu/loongarch/relocInfo_loongarch.cpp | 133 + + .../cpu/loongarch/relocInfo_loongarch.hpp | 44 + + .../loongarch/sharedRuntime_loongarch_64.cpp | 2979 +++ + .../smallRegisterMap_loongarch.inline.hpp | 88 + + ...stackChunkFrameStream_loongarch.inline.hpp | 142 + + .../stackChunkOop_loongarch.inline.hpp | 43 + + .../loongarch/stubGenerator_loongarch_64.cpp | 5721 ++++++ + .../cpu/loongarch/stubRoutines_loongarch.hpp | 118 + + .../loongarch/stubRoutines_loongarch_64.cpp | 196 + + ...templateInterpreterGenerator_loongarch.cpp | 2106 ++ + .../cpu/loongarch/templateTable_loongarch.hpp | 43 + + .../loongarch/templateTable_loongarch_64.cpp | 4007 ++++ + .../loongarch/upcallLinker_loongarch_64.cpp | 351 + + .../cpu/loongarch/vmStructs_loongarch.hpp | 61 + + .../cpu/loongarch/vm_version_loongarch.cpp | 511 + + .../cpu/loongarch/vm_version_loongarch.hpp | 308 + + src/hotspot/cpu/loongarch/vmreg_loongarch.cpp | 54 + + src/hotspot/cpu/loongarch/vmreg_loongarch.hpp | 58 + + .../cpu/loongarch/vmreg_loongarch.inline.hpp | 38 + + .../cpu/loongarch/vmstorage_loongarch.hpp | 87 + + .../loongarch/vtableStubs_loongarch_64.cpp | 312 + + src/hotspot/os/linux/os_linux.cpp | 54 +- + src/hotspot/os/linux/os_linux.hpp | 8 + + .../os/linux/systemMemoryBarrier_linux.cpp | 8 + + .../assembler_linux_loongarch.cpp | 24 + + .../atomic_linux_loongarch.hpp | 499 + + .../copy_linux_loongarch.inline.hpp | 145 + + .../gc/x/xSyscall_linux_loongarch.hpp | 41 + + .../gc/z/zSyscall_linux_loongarch.hpp | 41 + + .../globals_linux_loongarch.hpp | 43 + + .../javaThread_linux_loongarch.cpp | 105 + + .../javaThread_linux_loongarch.hpp | 66 + + .../os_cpu/linux_loongarch/linux_loongarch.s | 25 + + .../orderAccess_linux_loongarch.hpp | 50 + + .../linux_loongarch/os_linux_loongarch.cpp | 474 + + .../os_linux_loongarch.inline.hpp | 29 + + .../prefetch_linux_loongarch.inline.hpp | 56 + + .../safefetch_linux_loongarch64.S | 56 + + .../vmStructs_linux_loongarch.hpp | 55 + + .../vm_version_linux_loongarch.cpp | 95 + + src/hotspot/share/adlc/formssel.cpp | 7 + + src/hotspot/share/c1/c1_Compiler.cpp | 8 +- + src/hotspot/share/c1/c1_LIR.cpp | 21 +- + src/hotspot/share/c1/c1_LIR.hpp | 25 +- + src/hotspot/share/c1/c1_LinearScan.cpp | 30 +- + src/hotspot/share/code/vtableStubs.cpp | 10 + + src/hotspot/share/gc/g1/g1Arguments.cpp | 20 + + .../gc/g1/g1ParScanThreadState.inline.hpp | 9 + + .../share/gc/parallel/parallelArguments.cpp | 12 + + .../share/gc/shared/barrierSetNMethod.cpp | 8 +- + .../share/gc/shared/c2/barrierSetC2.cpp | 15 + + .../gc/shenandoah/shenandoahArguments.cpp | 8 +- + src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp | 17 + + .../share/gc/z/zStoreBarrierBuffer.hpp | 10 +- + .../share/interpreter/interpreterRuntime.cpp | 8 +- + .../share/interpreter/interpreterRuntime.hpp | 8 +- + .../templateInterpreterGenerator.hpp | 10 +- + .../share/jfr/utilities/jfrBigEndian.hpp | 8 +- + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 17 + + src/hotspot/share/memory/metaspace.cpp | 15 +- + .../share/oops/stackChunkOop.inline.hpp | 10 +- + src/hotspot/share/opto/classes.hpp | 7 + + src/hotspot/share/opto/compile.cpp | 7 + + src/hotspot/share/opto/memnode.cpp | 7 + + src/hotspot/share/opto/memnode.hpp | 14 + + src/hotspot/share/opto/output.cpp | 22 + + src/hotspot/share/runtime/arguments.cpp | 10 +- + src/hotspot/share/runtime/continuation.cpp | 8 +- + .../share/runtime/continuationFreezeThaw.cpp | 16 +- + .../share/runtime/javaThread.inline.hpp | 10 +- + src/hotspot/share/runtime/objectMonitor.cpp | 10 + + src/hotspot/share/runtime/os.cpp | 9 +- + src/hotspot/share/runtime/sharedRuntime.cpp | 8 +- + .../share/runtime/sharedRuntimeTrig.cpp | 16 + + src/hotspot/share/runtime/synchronizer.cpp | 8 +- + src/hotspot/share/runtime/vmStructs.cpp | 7 + + src/hotspot/share/utilities/macros.hpp | 18 + + .../classes/jdk/internal/foreign/CABI.java | 13 +- + .../internal/foreign/abi/AbstractLinker.java | 8 + + .../jdk/internal/foreign/abi/SharedUtils.java | 8 + + .../loongarch64/LoongArch64Architecture.java | 179 + + .../linux/LinuxLoongArch64CallArranger.java | 472 + + .../linux/LinuxLoongArch64Linker.java | 65 + + .../abi/loongarch64/linux/TypeClass.java | 217 + + .../jdk/internal/util/Architecture.java | 8 + + .../internal/util/PlatformProps.java.template | 8 + + .../native/libsaproc/LinuxDebuggerLocal.cpp | 28 +- + .../linux/native/libsaproc/libproc.h | 9 +- + .../linux/native/libsaproc/ps_proc.c | 8 +- + .../classes/sun/jvm/hotspot/HotSpotAgent.java | 9 + + .../MachineDescriptionLOONGARCH64.java | 41 + + .../debugger/linux/LinuxCDebugger.java | 17 +- + .../linux/LinuxThreadContextFactory.java | 11 +- + .../loongarch64/LinuxLOONGARCH64CFrame.java | 92 + + .../LinuxLOONGARCH64ThreadContext.java | 47 + + .../loongarch64/LOONGARCH64ThreadContext.java | 128 + + .../hotspot/debugger/posix/elf/ELFHeader.java | 8 + + .../debugger/remote/RemoteDebuggerClient.java | 11 + + .../loongarch64/RemoteLOONGARCH64Thread.java | 54 + + .../RemoteLOONGARCH64ThreadContext.java | 51 + + .../RemoteLOONGARCH64ThreadFactory.java | 45 + + .../sun/jvm/hotspot/runtime/Threads.java | 9 + + .../LinuxLOONGARCH64JavaThreadPDAccess.java | 139 + + .../LOONGARCH64CurrentFrameGuess.java | 250 + + .../runtime/loongarch64/LOONGARCH64Frame.java | 540 + + .../LOONGARCH64JavaCallWrapper.java | 59 + + .../loongarch64/LOONGARCH64RegisterMap.java | 52 + + .../jvm/hotspot/utilities/PlatformInfo.java | 12 +- + ...LoongArch64HotSpotJVMCIBackendFactory.java | 142 + + .../LoongArch64HotSpotRegisterConfig.java | 297 + + .../LoongArch64HotSpotVMConfig.java | 79 + + .../ci/hotspot/loongarch64/package-info.java | 28 + + .../jdk/vm/ci/loongarch64/LoongArch64.java | 251 + + .../vm/ci/loongarch64/LoongArch64Kind.java | 163 + + .../jdk/vm/ci/loongarch64/package-info.java | 28 + + .../share/classes/module-info.java | 7 + + src/utils/hsdis/binutils/hsdis-binutils.c | 9 + + .../arguments/TestCodeEntryAlignment.java | 8 +- + .../arraycopy/stress/TestStressArrayCopy.java | 14 + + test/hotspot/jtreg/compiler/c2/TestBit.java | 8 +- + .../compiler/c2/irTests/CmpUWithZero.java | 8 +- + .../irTests/TestAutoVecCountingDownLoop.java | 8 +- + .../jtreg/compiler/c2/irTests/TestIRAbs.java | 8 +- + .../c2/irTests/TestVectorizationNotRun.java | 8 +- + .../irTests/TestVectorizeTypeConversion.java | 8 +- + .../irTests/TestVectorizeURShiftSubword.java | 8 +- + .../TestAESIntrinsicsOnSupportedConfig.java | 8 +- + .../TestAESIntrinsicsOnUnsupportedConfig.java | 8 +- + .../intrinsics/TestCompareUnsigned.java | 9 +- + .../intrinsics/TestDoubleIsFinite.java | 8 +- + .../intrinsics/TestDoubleIsInfinite.java | 8 +- + .../intrinsics/TestFloatIsFinite.java | 8 +- + .../intrinsics/TestFloatIsInfinite.java | 8 +- + .../intrinsics/TestIntegerUnsignedDivMod.java | 8 +- + .../intrinsics/TestLongUnsignedDivMod.java | 8 +- + .../intrinsics/chacha/TestChaCha20.java | 12 + + .../float16/Binary16Conversion.java | 8 +- + .../float16/Binary16ConversionNaN.java | 8 +- + .../float16/TestAllFloat16ToFloat.java | 8 +- + .../float16/TestConstFloat16ToFloat.java | 8 +- + .../testcases/GenericTestCaseForOtherCPU.java | 13 +- + .../intrinsics/string/TestCountPositives.java | 12 +- + .../TestStringCompareToDifferentLength.java | 8 +- + .../vm/ci/code/test/CodeInstallationTest.java | 11 + + .../jdk/vm/ci/code/test/DataPatchTest.java | 11 +- + .../code/test/InterpreterFrameSizeTest.java | 11 +- + .../code/test/MaxOopMapStackOffsetTest.java | 11 +- + .../jdk/vm/ci/code/test/NativeCallTest.java | 11 +- + .../code/test/SimpleCodeInstallationTest.java | 11 +- + .../vm/ci/code/test/SimpleDebugInfoTest.java | 11 +- + .../code/test/VirtualObjectDebugInfoTest.java | 11 +- + .../loongarch64/LoongArch64TestAssembler.java | 568 + + .../compiler/lib/ir_framework/IRNode.java | 10 +- + .../loopopts/superword/ReductionPerf.java | 8 +- + .../TestRangeCheckHoistingScaledIV.java | 8 +- + .../runtime/TestConstantsInError.java | 14 +- + .../sharedstubs/SharedStubToInterpTest.java | 8 +- + .../sha/predicate/IntrinsicPredicates.java | 17 +- + .../compiler/vectorapi/TestVectorTest.java | 9 +- + .../VectorLogicalOpIdentityTest.java | 8 +- + .../vectorapi/VectorReverseBytesTest.java | 8 +- + .../vectorization/TestAutoVecIntMinMax.java | 8 +- + .../TestBufferVectorization.java | 8 +- + .../TestFloatConversionsVector.java | 8 +- + .../vectorization/TestPopulateIndex.java | 9 +- + .../vectorization/TestReverseBytes.java | 9 +- + .../vectorization/TestSignumVector.java | 8 +- + .../runner/ArrayIndexFillTest.java | 8 +- + .../runner/ArrayInvariantFillTest.java | 8 +- + .../runner/ArrayShiftOpTest.java | 8 +- + .../runner/BasicDoubleOpTest.java | 8 +- + .../runner/BasicFloatOpTest.java | 8 +- + .../vectorization/runner/BasicLongOpTest.java | 8 +- + .../runner/LoopArrayIndexComputeTest.java | 8 +- + .../runner/LoopReductionOpTest.java | 8 +- + .../compiler/TestLinkToNativeRBP.java | 8 +- + .../jtreg/loongson/25064/NUMAHelper.java | 100 + + .../loongson/25064/TestUseNUMADefault.java | 152 + + .../loongson/25064/TestUseNUMADisabled.java | 94 + + .../loongson/25064/TestUseNUMAEnabled.java | 165 + + .../jtreg/loongson/25443/Test25443.java | 58 + + .../jtreg/loongson/26733/Test26733.java | 570 + + .../jtreg/loongson/30358/MEMBARType.java | 38 + + .../jtreg/loongson/30358/TEST.properties | 25 + + .../jtreg/loongson/30358/TestLoadLoad.java | 129 + + .../30358/TestNewObjectWithFinal.java | 247 + + .../jtreg/loongson/30358/TestVolatile.java | 358 + + .../hotspot/jtreg/loongson/7432/Test7423.java | 61 + + .../ReservedStack/ReservedStackTest.java | 8 +- + .../jtreg/runtime/os/TestTracePageSizes.java | 8 +- + .../MyPackage/ASGCTBaseTest.java | 8 +- + .../sa/TestJhsdbJstackLineNumbers.java | 8 +- + .../ir_framework/tests/TestIRMatching.java | 8 +- + .../nsk/share/jdi/ArgumentHandler.java | 178 +- + .../TestLoongArch64CallArranger.java | 521 + + .../platform/PlatformLayouts.java | 59 + + .../ConcurrentHashMap/MapLoops.java | 8 +- + .../jdk/jfr/event/os/TestCPUInformation.java | 10 +- + .../nameservice/simple/DefaultCaching.java | 11 +- + ...stMutuallyExclusivePlatformPredicates.java | 8 +- + test/lib/jdk/test/lib/Platform.java | 10 + + .../org/openjdk/bench/loongarch/C2Memory.java | 67 + + .../bench/loongarch/MisAlignVector.java | 63 + + 301 files changed, 79758 insertions(+), 219 deletions(-) + create mode 100644 src/hotspot/cpu/loongarch/abstractInterpreter_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/assembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/assembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/assembler_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/bytes_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_CodeStubs_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_Defs_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_FrameMap_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_FrameMap_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_LIRGenerator_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_LIR_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_LinearScan_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_LinearScan_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_Runtime1_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/c1_globals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c2_CodeStubs_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c2_globals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/c2_init_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/codeBuffer_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/codeBuffer_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/compiledIC_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/continuationEntry_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/continuationEntry_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/continuationFreezeThaw_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/continuationHelper_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/copy_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/copy_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/disassembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/downcallLinker_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/foreignGlobals_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/foreignGlobals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/frame_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/frame_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/frame_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/g1/g1Globals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/barrierSetNMethod_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shenandoah/c1/shenandoahBarrierSetC1_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/shenandoah/shenandoah_loongarch_64.ad + create mode 100644 src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/x/x_loongarch_64.ad + create mode 100644 src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/z/zGlobals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/gc/z/z_loongarch_64.ad + create mode 100644 src/hotspot/cpu/loongarch/globalDefinitions_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/globals_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/icBuffer_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/icache_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/icache_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/interp_masm_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/interp_masm_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/interpreterRT_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/interpreterRT_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/javaFrameAnchor_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/jniFastGetField_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/jniTypes_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/jvmciCodeInstaller_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/loongarch.ad + create mode 100644 src/hotspot/cpu/loongarch/loongarch_64.ad + create mode 100644 src/hotspot/cpu/loongarch/macroAssembler_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/macroAssembler_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/macroAssembler_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/macroAssembler_loongarch_chacha.cpp + create mode 100644 src/hotspot/cpu/loongarch/macroAssembler_loongarch_trig.cpp + create mode 100644 src/hotspot/cpu/loongarch/matcher_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/methodHandles_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/methodHandles_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/nativeInst_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/nativeInst_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/registerMap_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/register_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/register_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/relocInfo_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/relocInfo_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/sharedRuntime_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/smallRegisterMap_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/stackChunkFrameStream_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/stackChunkOop_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/stubGenerator_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/stubRoutines_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/stubRoutines_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/templateInterpreterGenerator_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/templateTable_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/templateTable_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/upcallLinker_loongarch_64.cpp + create mode 100644 src/hotspot/cpu/loongarch/vmStructs_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/vm_version_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/vm_version_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/vmreg_loongarch.cpp + create mode 100644 src/hotspot/cpu/loongarch/vmreg_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/vmreg_loongarch.inline.hpp + create mode 100644 src/hotspot/cpu/loongarch/vmstorage_loongarch.hpp + create mode 100644 src/hotspot/cpu/loongarch/vtableStubs_loongarch_64.cpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/assembler_linux_loongarch.cpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/atomic_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/copy_linux_loongarch.inline.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/gc/x/xSyscall_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/gc/z/zSyscall_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/globals_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.cpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/linux_loongarch.s + create mode 100644 src/hotspot/os_cpu/linux_loongarch/orderAccess_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.cpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.inline.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/prefetch_linux_loongarch.inline.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/safefetch_linux_loongarch64.S + create mode 100644 src/hotspot/os_cpu/linux_loongarch/vmStructs_linux_loongarch.hpp + create mode 100644 src/hotspot/os_cpu/linux_loongarch/vm_version_linux_loongarch.cpp + create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/LoongArch64Architecture.java + create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64CallArranger.java + create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64Linker.java + create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/TypeClass.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionLOONGARCH64.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64CFrame.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64ThreadContext.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/loongarch64/LOONGARCH64ThreadContext.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64Thread.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadContext.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadFactory.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_loongarch64/LinuxLOONGARCH64JavaThreadPDAccess.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64CurrentFrameGuess.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64Frame.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64JavaCallWrapper.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64RegisterMap.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotJVMCIBackendFactory.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotRegisterConfig.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotVMConfig.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/package-info.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64Kind.java + create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/package-info.java + create mode 100644 test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/loongarch64/LoongArch64TestAssembler.java + create mode 100644 test/hotspot/jtreg/loongson/25064/NUMAHelper.java + create mode 100644 test/hotspot/jtreg/loongson/25064/TestUseNUMADefault.java + create mode 100644 test/hotspot/jtreg/loongson/25064/TestUseNUMADisabled.java + create mode 100644 test/hotspot/jtreg/loongson/25064/TestUseNUMAEnabled.java + create mode 100644 test/hotspot/jtreg/loongson/25443/Test25443.java + create mode 100644 test/hotspot/jtreg/loongson/26733/Test26733.java + create mode 100644 test/hotspot/jtreg/loongson/30358/MEMBARType.java + create mode 100644 test/hotspot/jtreg/loongson/30358/TEST.properties + create mode 100644 test/hotspot/jtreg/loongson/30358/TestLoadLoad.java + create mode 100644 test/hotspot/jtreg/loongson/30358/TestNewObjectWithFinal.java + create mode 100644 test/hotspot/jtreg/loongson/30358/TestVolatile.java + create mode 100644 test/hotspot/jtreg/loongson/7432/Test7423.java + create mode 100644 test/jdk/java/foreign/callarranger/TestLoongArch64CallArranger.java + create mode 100644 test/micro/org/openjdk/bench/loongarch/C2Memory.java + create mode 100644 test/micro/org/openjdk/bench/loongarch/MisAlignVector.java + diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 -index 28801984862..c37c5c27429 100644 +index 288019848..c37c5c274 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -23,6 +23,12 @@ @@ -49,7 +530,7 @@ index 28801984862..c37c5c27429 100644 AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) AVAILABLE=false diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4 -index df610cc489b..9f773892ff1 100644 +index df610cc48..9f773892f 100644 --- a/make/autoconf/platform.m4 +++ b/make/autoconf/platform.m4 @@ -23,6 +23,12 @@ @@ -97,7 +578,7 @@ index df610cc489b..9f773892ff1 100644 elif test "x$OPENJDK_$1_CPU" = xsparc; then diff --git a/src/hotspot/cpu/loongarch/abstractInterpreter_loongarch.cpp b/src/hotspot/cpu/loongarch/abstractInterpreter_loongarch.cpp new file mode 100644 -index 00000000000..5423a479801 +index 000000000..5423a4798 --- /dev/null +++ b/src/hotspot/cpu/loongarch/abstractInterpreter_loongarch.cpp @@ -0,0 +1,155 @@ @@ -258,7 +739,7 @@ index 00000000000..5423a479801 + diff --git a/src/hotspot/cpu/loongarch/assembler_loongarch.cpp b/src/hotspot/cpu/loongarch/assembler_loongarch.cpp new file mode 100644 -index 00000000000..f9528680cf0 +index 000000000..f9528680c --- /dev/null +++ b/src/hotspot/cpu/loongarch/assembler_loongarch.cpp @@ -0,0 +1,820 @@ @@ -1084,7 +1565,7 @@ index 00000000000..f9528680cf0 +} diff --git a/src/hotspot/cpu/loongarch/assembler_loongarch.hpp b/src/hotspot/cpu/loongarch/assembler_loongarch.hpp new file mode 100644 -index 00000000000..dd936b41b8a +index 000000000..dd936b41b --- /dev/null +++ b/src/hotspot/cpu/loongarch/assembler_loongarch.hpp @@ -0,0 +1,3213 @@ @@ -4303,7 +4784,7 @@ index 00000000000..dd936b41b8a +#endif // CPU_LOONGARCH_ASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/assembler_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/assembler_loongarch.inline.hpp new file mode 100644 -index 00000000000..9ca0cd45047 +index 000000000..9ca0cd450 --- /dev/null +++ b/src/hotspot/cpu/loongarch/assembler_loongarch.inline.hpp @@ -0,0 +1,33 @@ @@ -4342,7 +4823,7 @@ index 00000000000..9ca0cd45047 +#endif // CPU_LOONGARCH_ASSEMBLER_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/bytes_loongarch.hpp b/src/hotspot/cpu/loongarch/bytes_loongarch.hpp new file mode 100644 -index 00000000000..763404473e1 +index 000000000..763404473 --- /dev/null +++ b/src/hotspot/cpu/loongarch/bytes_loongarch.hpp @@ -0,0 +1,64 @@ @@ -4412,7 +4893,7 @@ index 00000000000..763404473e1 +#endif // CPU_LOONGARCH_BYTES_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_CodeStubs_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_CodeStubs_loongarch_64.cpp new file mode 100644 -index 00000000000..e1cda84acc9 +index 000000000..e1cda84ac --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_CodeStubs_loongarch_64.cpp @@ -0,0 +1,338 @@ @@ -4756,7 +5237,7 @@ index 00000000000..e1cda84acc9 +#undef __ diff --git a/src/hotspot/cpu/loongarch/c1_Defs_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_Defs_loongarch.hpp new file mode 100644 -index 00000000000..65850bc2520 +index 000000000..65850bc25 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_Defs_loongarch.hpp @@ -0,0 +1,88 @@ @@ -4850,7 +5331,7 @@ index 00000000000..65850bc2520 +#endif // CPU_LOONGARCH_C1_DEFS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch.hpp new file mode 100644 -index 00000000000..bd8578c72a8 +index 000000000..bd8578c72 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch.hpp @@ -0,0 +1,32 @@ @@ -4888,7 +5369,7 @@ index 00000000000..bd8578c72a8 +#endif // CPU_LOONGARCH_C1_FPUSTACKSIM_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch_64.cpp new file mode 100644 -index 00000000000..1a89c437a83 +index 000000000..1a89c437a --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_FpuStackSim_loongarch_64.cpp @@ -0,0 +1,31 @@ @@ -4925,7 +5406,7 @@ index 00000000000..1a89c437a83 +#include "precompiled.hpp" diff --git a/src/hotspot/cpu/loongarch/c1_FrameMap_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_FrameMap_loongarch.hpp new file mode 100644 -index 00000000000..4f0cf053617 +index 000000000..4f0cf0536 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_FrameMap_loongarch.hpp @@ -0,0 +1,143 @@ @@ -5074,7 +5555,7 @@ index 00000000000..4f0cf053617 +#endif // CPU_LOONGARCH_C1_FRAMEMAP_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_FrameMap_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_FrameMap_loongarch_64.cpp new file mode 100644 -index 00000000000..f157536797b +index 000000000..f15753679 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_FrameMap_loongarch_64.cpp @@ -0,0 +1,345 @@ @@ -5425,7 +5906,7 @@ index 00000000000..f157536797b +} diff --git a/src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch.hpp new file mode 100644 -index 00000000000..2d489e691b9 +index 000000000..2d489e691 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch.hpp @@ -0,0 +1,84 @@ @@ -5515,7 +5996,7 @@ index 00000000000..2d489e691b9 +#endif // CPU_LOONGARCH_C1_LIRASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch_64.cpp new file mode 100644 -index 00000000000..5f3a52ac90b +index 000000000..5f3a52ac9 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_LIRAssembler_loongarch_64.cpp @@ -0,0 +1,3383 @@ @@ -8904,7 +9385,7 @@ index 00000000000..5f3a52ac90b +#undef __ diff --git a/src/hotspot/cpu/loongarch/c1_LIRGenerator_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_LIRGenerator_loongarch_64.cpp new file mode 100644 -index 00000000000..bf5fba7a100 +index 000000000..bf5fba7a1 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_LIRGenerator_loongarch_64.cpp @@ -0,0 +1,1393 @@ @@ -10303,7 +10784,7 @@ index 00000000000..bf5fba7a100 +} diff --git a/src/hotspot/cpu/loongarch/c1_LIR_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_LIR_loongarch_64.cpp new file mode 100644 -index 00000000000..45e189e4d51 +index 000000000..45e189e4d --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_LIR_loongarch_64.cpp @@ -0,0 +1,57 @@ @@ -10366,7 +10847,7 @@ index 00000000000..45e189e4d51 +#endif // PRODUCT diff --git a/src/hotspot/cpu/loongarch/c1_LinearScan_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_LinearScan_loongarch.hpp new file mode 100644 -index 00000000000..f15dacafeba +index 000000000..f15dacafe --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_LinearScan_loongarch.hpp @@ -0,0 +1,70 @@ @@ -10442,7 +10923,7 @@ index 00000000000..f15dacafeba +#endif // CPU_LOONGARCH_C1_LINEARSCAN_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_LinearScan_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_LinearScan_loongarch_64.cpp new file mode 100644 -index 00000000000..219b2e3671c +index 000000000..219b2e367 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_LinearScan_loongarch_64.cpp @@ -0,0 +1,33 @@ @@ -10481,7 +10962,7 @@ index 00000000000..219b2e3671c +} diff --git a/src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch.hpp new file mode 100644 -index 00000000000..d1c63b13896 +index 000000000..d1c63b138 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch.hpp @@ -0,0 +1,111 @@ @@ -10598,7 +11079,7 @@ index 00000000000..d1c63b13896 +#endif // CPU_LOONGARCH_C1_MACROASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch_64.cpp new file mode 100644 -index 00000000000..eaaaf464fe6 +index 000000000..eaaaf464f --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_MacroAssembler_loongarch_64.cpp @@ -0,0 +1,350 @@ @@ -10954,7 +11435,7 @@ index 00000000000..eaaaf464fe6 +#endif // ifndef PRODUCT diff --git a/src/hotspot/cpu/loongarch/c1_Runtime1_loongarch_64.cpp b/src/hotspot/cpu/loongarch/c1_Runtime1_loongarch_64.cpp new file mode 100644 -index 00000000000..21f7c6f2d00 +index 000000000..21f7c6f2d --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_Runtime1_loongarch_64.cpp @@ -0,0 +1,1049 @@ @@ -12009,7 +12490,7 @@ index 00000000000..21f7c6f2d00 +} diff --git a/src/hotspot/cpu/loongarch/c1_globals_loongarch.hpp b/src/hotspot/cpu/loongarch/c1_globals_loongarch.hpp new file mode 100644 -index 00000000000..a97091dda04 +index 000000000..a97091dda --- /dev/null +++ b/src/hotspot/cpu/loongarch/c1_globals_loongarch.hpp @@ -0,0 +1,64 @@ @@ -12079,7 +12560,7 @@ index 00000000000..a97091dda04 +#endif // CPU_LOONGARCH_C1_GLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c2_CodeStubs_loongarch.cpp b/src/hotspot/cpu/loongarch/c2_CodeStubs_loongarch.cpp new file mode 100644 -index 00000000000..4672c7b08a8 +index 000000000..4672c7b08 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c2_CodeStubs_loongarch.cpp @@ -0,0 +1,91 @@ @@ -12176,7 +12657,7 @@ index 00000000000..4672c7b08a8 +#undef __ diff --git a/src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.cpp new file mode 100644 -index 00000000000..d83d08e9549 +index 000000000..d83d08e95 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.cpp @@ -0,0 +1,1903 @@ @@ -14085,7 +14566,7 @@ index 00000000000..d83d08e9549 +} diff --git a/src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.hpp new file mode 100644 -index 00000000000..804e060f195 +index 000000000..804e060f1 --- /dev/null +++ b/src/hotspot/cpu/loongarch/c2_MacroAssembler_loongarch.hpp @@ -0,0 +1,141 @@ @@ -14232,7 +14713,7 @@ index 00000000000..804e060f195 +#endif // CPU_LOONGARCH_C2_MACROASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c2_globals_loongarch.hpp b/src/hotspot/cpu/loongarch/c2_globals_loongarch.hpp new file mode 100644 -index 00000000000..a1054036f2d +index 000000000..a1054036f --- /dev/null +++ b/src/hotspot/cpu/loongarch/c2_globals_loongarch.hpp @@ -0,0 +1,85 @@ @@ -14323,7 +14804,7 @@ index 00000000000..a1054036f2d +#endif // CPU_LOONGARCH_C2_GLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/c2_init_loongarch.cpp b/src/hotspot/cpu/loongarch/c2_init_loongarch.cpp new file mode 100644 -index 00000000000..ec78b942d40 +index 000000000..ec78b942d --- /dev/null +++ b/src/hotspot/cpu/loongarch/c2_init_loongarch.cpp @@ -0,0 +1,37 @@ @@ -14366,7 +14847,7 @@ index 00000000000..ec78b942d40 +} diff --git a/src/hotspot/cpu/loongarch/codeBuffer_loongarch.cpp b/src/hotspot/cpu/loongarch/codeBuffer_loongarch.cpp new file mode 100644 -index 00000000000..3fdfbb27cc0 +index 000000000..3fdfbb27c --- /dev/null +++ b/src/hotspot/cpu/loongarch/codeBuffer_loongarch.cpp @@ -0,0 +1,32 @@ @@ -14404,7 +14885,7 @@ index 00000000000..3fdfbb27cc0 +} diff --git a/src/hotspot/cpu/loongarch/codeBuffer_loongarch.hpp b/src/hotspot/cpu/loongarch/codeBuffer_loongarch.hpp new file mode 100644 -index 00000000000..c8041a57f96 +index 000000000..c8041a57f --- /dev/null +++ b/src/hotspot/cpu/loongarch/codeBuffer_loongarch.hpp @@ -0,0 +1,37 @@ @@ -14447,7 +14928,7 @@ index 00000000000..c8041a57f96 +#endif // CPU_LOONGARCH_CODEBUFFER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/compiledIC_loongarch.cpp b/src/hotspot/cpu/loongarch/compiledIC_loongarch.cpp new file mode 100644 -index 00000000000..17ee4b75f72 +index 000000000..17ee4b75f --- /dev/null +++ b/src/hotspot/cpu/loongarch/compiledIC_loongarch.cpp @@ -0,0 +1,138 @@ @@ -14591,7 +15072,7 @@ index 00000000000..17ee4b75f72 +#endif // !PRODUCT diff --git a/src/hotspot/cpu/loongarch/continuationEntry_loongarch.hpp b/src/hotspot/cpu/loongarch/continuationEntry_loongarch.hpp new file mode 100644 -index 00000000000..c2d91996000 +index 000000000..c2d919960 --- /dev/null +++ b/src/hotspot/cpu/loongarch/continuationEntry_loongarch.hpp @@ -0,0 +1,33 @@ @@ -14630,7 +15111,7 @@ index 00000000000..c2d91996000 +#endif // CPU_LOONGARCH_CONTINUATIONENTRY_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/continuationEntry_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/continuationEntry_loongarch.inline.hpp new file mode 100644 -index 00000000000..d1c01ee42f0 +index 000000000..d1c01ee42 --- /dev/null +++ b/src/hotspot/cpu/loongarch/continuationEntry_loongarch.inline.hpp @@ -0,0 +1,52 @@ @@ -14688,7 +15169,7 @@ index 00000000000..d1c01ee42f0 +#endif // CPU_LOONGARCH_CONTINUATIONENTRY_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/continuationFreezeThaw_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/continuationFreezeThaw_loongarch.inline.hpp new file mode 100644 -index 00000000000..c4c49842464 +index 000000000..dc61283c1 --- /dev/null +++ b/src/hotspot/cpu/loongarch/continuationFreezeThaw_loongarch.inline.hpp @@ -0,0 +1,284 @@ @@ -14904,7 +15385,7 @@ index 00000000000..c4c49842464 + intptr_t* heap_sp = hf.unextended_sp(); + // If caller is interpreted it already made room for the callee arguments + int overlap = caller.is_interpreted_frame() ? ContinuationHelper::InterpretedFrame::stack_argsize(hf) : 0; -+ const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp() - overlap; ++ const int fsize = (int)(ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp() - overlap); + const int locals = hf.interpreter_frame_method()->max_locals(); + intptr_t* frame_sp = caller.unextended_sp() - fsize; + intptr_t* fp = frame_sp + (hf.fp() - heap_sp); @@ -14978,7 +15459,7 @@ index 00000000000..c4c49842464 +#endif // CPU_LOONGARCH_CONTINUATIONFREEZETHAW_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/continuationHelper_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/continuationHelper_loongarch.inline.hpp new file mode 100644 -index 00000000000..b36584a968a +index 000000000..b36584a96 --- /dev/null +++ b/src/hotspot/cpu/loongarch/continuationHelper_loongarch.inline.hpp @@ -0,0 +1,145 @@ @@ -15129,7 +15610,7 @@ index 00000000000..b36584a968a +#endif // CPU_LOONGARCH_CONTINUATIONFRAMEHELPERS_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/copy_loongarch.cpp b/src/hotspot/cpu/loongarch/copy_loongarch.cpp new file mode 100644 -index 00000000000..68f3bae9ef3 +index 000000000..68f3bae9e --- /dev/null +++ b/src/hotspot/cpu/loongarch/copy_loongarch.cpp @@ -0,0 +1,147 @@ @@ -15282,7 +15763,7 @@ index 00000000000..68f3bae9ef3 +Copy::FillByte Copy::_fill_to_bytes = c_fill_to_bytes; diff --git a/src/hotspot/cpu/loongarch/copy_loongarch.hpp b/src/hotspot/cpu/loongarch/copy_loongarch.hpp new file mode 100644 -index 00000000000..4ed4766e6e2 +index 000000000..4ed4766e6 --- /dev/null +++ b/src/hotspot/cpu/loongarch/copy_loongarch.hpp @@ -0,0 +1,65 @@ @@ -15353,7 +15834,7 @@ index 00000000000..4ed4766e6e2 +#endif //CPU_LOONGARCH_COPY_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/disassembler_loongarch.hpp b/src/hotspot/cpu/loongarch/disassembler_loongarch.hpp new file mode 100644 -index 00000000000..6fdd1bd1915 +index 000000000..6fdd1bd19 --- /dev/null +++ b/src/hotspot/cpu/loongarch/disassembler_loongarch.hpp @@ -0,0 +1,49 @@ @@ -15408,7 +15889,7 @@ index 00000000000..6fdd1bd1915 +#endif // CPU_LOONGARCH_DISASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/downcallLinker_loongarch_64.cpp b/src/hotspot/cpu/loongarch/downcallLinker_loongarch_64.cpp new file mode 100644 -index 00000000000..4f936060b6b +index 000000000..4f936060b --- /dev/null +++ b/src/hotspot/cpu/loongarch/downcallLinker_loongarch_64.cpp @@ -0,0 +1,360 @@ @@ -15774,7 +16255,7 @@ index 00000000000..4f936060b6b +} diff --git a/src/hotspot/cpu/loongarch/foreignGlobals_loongarch.cpp b/src/hotspot/cpu/loongarch/foreignGlobals_loongarch.cpp new file mode 100644 -index 00000000000..c0837e64d80 +index 000000000..c0837e64d --- /dev/null +++ b/src/hotspot/cpu/loongarch/foreignGlobals_loongarch.cpp @@ -0,0 +1,195 @@ @@ -15975,7 +16456,7 @@ index 00000000000..c0837e64d80 +} diff --git a/src/hotspot/cpu/loongarch/foreignGlobals_loongarch.hpp b/src/hotspot/cpu/loongarch/foreignGlobals_loongarch.hpp new file mode 100644 -index 00000000000..7e4d0d79e44 +index 000000000..7e4d0d79e --- /dev/null +++ b/src/hotspot/cpu/loongarch/foreignGlobals_loongarch.hpp @@ -0,0 +1,50 @@ @@ -16031,10 +16512,10 @@ index 00000000000..7e4d0d79e44 +#endif // CPU_LOONGARCH_FOREIGN_GLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/frame_loongarch.cpp b/src/hotspot/cpu/loongarch/frame_loongarch.cpp new file mode 100644 -index 00000000000..b2c3d9e02f1 +index 000000000..3b4c0884f --- /dev/null +++ b/src/hotspot/cpu/loongarch/frame_loongarch.cpp -@@ -0,0 +1,626 @@ +@@ -0,0 +1,629 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Loongson Technology. All rights reserved. @@ -16097,8 +16578,11 @@ index 00000000000..b2c3d9e02f1 + return false; + } + -+ // unextended sp must be within the stack and above or equal sp -+ if (!thread->is_in_stack_range_incl(unextended_sp, sp)) { ++ // unextended sp must be within the stack ++ // Note: sp can be greater than unextended_sp in the case of ++ // interpreted -> interpreted calls that go through a method handle linker, ++ // since those pop the last argument (the appendix) from the stack. ++ if (!thread->is_in_stack_range_incl(unextended_sp, sp - Interpreter::stackElementSize)) { + return false; + } + @@ -16663,7 +17147,7 @@ index 00000000000..b2c3d9e02f1 +} diff --git a/src/hotspot/cpu/loongarch/frame_loongarch.hpp b/src/hotspot/cpu/loongarch/frame_loongarch.hpp new file mode 100644 -index 00000000000..36dd89ff08f +index 000000000..36dd89ff0 --- /dev/null +++ b/src/hotspot/cpu/loongarch/frame_loongarch.hpp @@ -0,0 +1,200 @@ @@ -16869,7 +17353,7 @@ index 00000000000..36dd89ff08f +#endif // CPU_LOONGARCH_FRAME_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/frame_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/frame_loongarch.inline.hpp new file mode 100644 -index 00000000000..a740b3b1df3 +index 000000000..02f7eb198 --- /dev/null +++ b/src/hotspot/cpu/loongarch/frame_loongarch.inline.hpp @@ -0,0 +1,472 @@ @@ -17099,13 +17583,13 @@ index 00000000000..a740b3b1df3 + +inline int frame::frame_size() const { + return is_interpreted_frame() -+ ? sender_sp() - sp() ++ ? pointer_delta_as_int(sender_sp(), sp()) + : cb()->frame_size(); +} + +inline int frame::compiled_frame_stack_argsize() const { + assert(cb()->is_compiled(), ""); -+ return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; ++ return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; +} + +inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { @@ -17347,7 +17831,7 @@ index 00000000000..a740b3b1df3 +#endif // CPU_LOONGARCH_FRAME_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..fd125f141f4 +index 000000000..fd125f141 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.cpp @@ -0,0 +1,491 @@ @@ -17844,7 +18328,7 @@ index 00000000000..fd125f141f4 +#endif // COMPILER1 diff --git a/src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..b3725301da2 +index 000000000..b3725301d --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/g1/g1BarrierSetAssembler_loongarch.hpp @@ -0,0 +1,72 @@ @@ -17922,7 +18406,7 @@ index 00000000000..b3725301da2 +#endif // CPU_LOONGARCH_GC_G1_G1BARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/g1/g1Globals_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/g1/g1Globals_loongarch.hpp new file mode 100644 -index 00000000000..44b7ff1485f +index 000000000..44b7ff148 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/g1/g1Globals_loongarch.hpp @@ -0,0 +1,30 @@ @@ -17958,7 +18442,7 @@ index 00000000000..44b7ff1485f +#endif // CPU_LOONGARCH_GC_G1_G1GLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..8b45eb5131c +index 000000000..8b45eb513 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.cpp @@ -0,0 +1,453 @@ @@ -18417,7 +18901,7 @@ index 00000000000..8b45eb5131c +} diff --git a/src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..0562518663f +index 000000000..056251866 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/barrierSetAssembler_loongarch.hpp @@ -0,0 +1,147 @@ @@ -18570,7 +19054,7 @@ index 00000000000..0562518663f +#endif // CPU_LOONGARCH_GC_SHARED_BARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/shared/barrierSetNMethod_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/shared/barrierSetNMethod_loongarch.cpp new file mode 100644 -index 00000000000..6fd8fac976c +index 000000000..6fd8fac97 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/barrierSetNMethod_loongarch.cpp @@ -0,0 +1,222 @@ @@ -18798,7 +19282,7 @@ index 00000000000..6fd8fac976c +#endif diff --git a/src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..d04be97df4c +index 000000000..d04be97df --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.cpp @@ -0,0 +1,117 @@ @@ -18921,7 +19405,7 @@ index 00000000000..d04be97df4c +} diff --git a/src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..bd91d0623db +index 000000000..bd91d0623 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/cardTableBarrierSetAssembler_loongarch.hpp @@ -0,0 +1,44 @@ @@ -18971,7 +19455,7 @@ index 00000000000..bd91d0623db +#endif // CPU_LOONGARCH_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..53799c0678a +index 000000000..53799c067 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.cpp @@ -0,0 +1,53 @@ @@ -19030,7 +19514,7 @@ index 00000000000..53799c0678a +} diff --git a/src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..825a8f9d0ea +index 000000000..825a8f9d0 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shared/modRefBarrierSetAssembler_loongarch.hpp @@ -0,0 +1,54 @@ @@ -19090,7 +19574,7 @@ index 00000000000..825a8f9d0ea +#endif // CPU_LOONGARCH_GC_SHARED_MODREFBARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/shenandoah/c1/shenandoahBarrierSetC1_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/shenandoah/c1/shenandoahBarrierSetC1_loongarch.cpp new file mode 100644 -index 00000000000..1fd8cff3904 +index 000000000..1fd8cff39 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shenandoah/c1/shenandoahBarrierSetC1_loongarch.cpp @@ -0,0 +1,130 @@ @@ -19226,7 +19710,7 @@ index 00000000000..1fd8cff3904 +} diff --git a/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..d9377db5503 +index 000000000..d9377db55 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.cpp @@ -0,0 +1,783 @@ @@ -20015,7 +20499,7 @@ index 00000000000..d9377db5503 +#endif // COMPILER1 diff --git a/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..133bbbb0b89 +index 000000000..133bbbb0b --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoahBarrierSetAssembler_loongarch.hpp @@ -0,0 +1,88 @@ @@ -20109,7 +20593,7 @@ index 00000000000..133bbbb0b89 +#endif // CPU_LOONGARCH_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoah_loongarch_64.ad b/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoah_loongarch_64.ad new file mode 100644 -index 00000000000..2608ef13576 +index 000000000..2608ef135 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/shenandoah/shenandoah_loongarch_64.ad @@ -0,0 +1,232 @@ @@ -20347,7 +20831,7 @@ index 00000000000..2608ef13576 +%} diff --git a/src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..0be4ef7c6bc +index 000000000..0be4ef7c6 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.cpp @@ -0,0 +1,471 @@ @@ -20824,7 +21308,7 @@ index 00000000000..0be4ef7c6bc +#undef __ diff --git a/src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..dfe62190ff6 +index 000000000..dfe62190f --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/x/xBarrierSetAssembler_loongarch.hpp @@ -0,0 +1,105 @@ @@ -20935,7 +21419,7 @@ index 00000000000..dfe62190ff6 +#endif // CPU_LOONGARCH_GC_X_XBARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.cpp new file mode 100644 -index 00000000000..2acac4cfd31 +index 000000000..2acac4cfd --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.cpp @@ -0,0 +1,211 @@ @@ -21152,7 +21636,7 @@ index 00000000000..2acac4cfd31 +} diff --git a/src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.hpp new file mode 100644 -index 00000000000..3134c3d07f8 +index 000000000..3134c3d07 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/x/xGlobals_loongarch.hpp @@ -0,0 +1,34 @@ @@ -21192,7 +21676,7 @@ index 00000000000..3134c3d07f8 +#endif // CPU_LOONGARCH_GC_X_XGLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/x/x_loongarch_64.ad b/src/hotspot/cpu/loongarch/gc/x/x_loongarch_64.ad new file mode 100644 -index 00000000000..c4e77f08b4f +index 000000000..c4e77f08b --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/x/x_loongarch_64.ad @@ -0,0 +1,256 @@ @@ -21454,7 +21938,7 @@ index 00000000000..c4e77f08b4f +%} diff --git a/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.cpp new file mode 100644 -index 00000000000..9caa23354c1 +index 000000000..9caa23354 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.cpp @@ -0,0 +1,109 @@ @@ -21569,7 +22053,7 @@ index 00000000000..9caa23354c1 +} diff --git a/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.hpp new file mode 100644 -index 00000000000..8f82152db59 +index 000000000..8f82152db --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.hpp @@ -0,0 +1,35 @@ @@ -21610,7 +22094,7 @@ index 00000000000..8f82152db59 +#endif // CPU_LOONGARCH64_GC_Z_ZADDRESS_LOONGARCH64_HPP diff --git a/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.inline.hpp new file mode 100644 -index 00000000000..93ea4144072 +index 000000000..93ea41440 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/zAddress_loongarch.inline.hpp @@ -0,0 +1,38 @@ @@ -21654,7 +22138,7 @@ index 00000000000..93ea4144072 +#endif // CPU_LOONGARCH64_GC_Z_ZADDRESS_LOONGARCH64_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.cpp new file mode 100644 -index 00000000000..427a6f9c24a +index 000000000..427a6f9c2 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.cpp @@ -0,0 +1,1226 @@ @@ -22886,7 +23370,7 @@ index 00000000000..427a6f9c24a +#endif // COMPILER2 diff --git a/src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.hpp new file mode 100644 -index 00000000000..754f042f749 +index 000000000..754f042f7 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/zBarrierSetAssembler_loongarch.hpp @@ -0,0 +1,192 @@ @@ -23084,7 +23568,7 @@ index 00000000000..754f042f749 +#endif // CPU_LOONGARCH_GC_Z_ZBARRIERSETASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/z/zGlobals_loongarch.hpp b/src/hotspot/cpu/loongarch/gc/z/zGlobals_loongarch.hpp new file mode 100644 -index 00000000000..3e012e31420 +index 000000000..3e012e314 --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/zGlobals_loongarch.hpp @@ -0,0 +1,30 @@ @@ -23120,7 +23604,7 @@ index 00000000000..3e012e31420 +#endif // CPU_LOONGARCH_GC_Z_ZGLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/gc/z/z_loongarch_64.ad b/src/hotspot/cpu/loongarch/gc/z/z_loongarch_64.ad new file mode 100644 -index 00000000000..7a50810acda +index 000000000..7a50810ac --- /dev/null +++ b/src/hotspot/cpu/loongarch/gc/z/z_loongarch_64.ad @@ -0,0 +1,250 @@ @@ -23376,10 +23860,10 @@ index 00000000000..7a50810acda +%} diff --git a/src/hotspot/cpu/loongarch/globalDefinitions_loongarch.hpp b/src/hotspot/cpu/loongarch/globalDefinitions_loongarch.hpp new file mode 100644 -index 00000000000..441882dcaa0 +index 000000000..2306c5bc6 --- /dev/null +++ b/src/hotspot/cpu/loongarch/globalDefinitions_loongarch.hpp -@@ -0,0 +1,57 @@ +@@ -0,0 +1,58 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Loongson Technology. All rights reserved. @@ -23411,6 +23895,7 @@ index 00000000000..441882dcaa0 +const int BytesPerInstWord = 4; + +const int StackAlignmentInBytes = (2*wordSize); ++const size_t pd_segfault_address = 1024; + +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are properly extended to 64 bits. @@ -23439,7 +23924,7 @@ index 00000000000..441882dcaa0 +#endif // CPU_LOONGARCH_GLOBALDEFINITIONS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/globals_loongarch.hpp b/src/hotspot/cpu/loongarch/globals_loongarch.hpp new file mode 100644 -index 00000000000..e38b0401bee +index 000000000..e38b0401b --- /dev/null +++ b/src/hotspot/cpu/loongarch/globals_loongarch.hpp @@ -0,0 +1,125 @@ @@ -23570,7 +24055,7 @@ index 00000000000..e38b0401bee +#endif // CPU_LOONGARCH_GLOBALS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/icBuffer_loongarch.cpp b/src/hotspot/cpu/loongarch/icBuffer_loongarch.cpp new file mode 100644 -index 00000000000..c53d50d78f6 +index 000000000..c53d50d78 --- /dev/null +++ b/src/hotspot/cpu/loongarch/icBuffer_loongarch.cpp @@ -0,0 +1,82 @@ @@ -23658,7 +24143,7 @@ index 00000000000..c53d50d78f6 +} diff --git a/src/hotspot/cpu/loongarch/icache_loongarch.cpp b/src/hotspot/cpu/loongarch/icache_loongarch.cpp new file mode 100644 -index 00000000000..59906711428 +index 000000000..599067114 --- /dev/null +++ b/src/hotspot/cpu/loongarch/icache_loongarch.cpp @@ -0,0 +1,42 @@ @@ -23706,7 +24191,7 @@ index 00000000000..59906711428 +} diff --git a/src/hotspot/cpu/loongarch/icache_loongarch.hpp b/src/hotspot/cpu/loongarch/icache_loongarch.hpp new file mode 100644 -index 00000000000..3a180549fc6 +index 000000000..3a180549f --- /dev/null +++ b/src/hotspot/cpu/loongarch/icache_loongarch.hpp @@ -0,0 +1,41 @@ @@ -23753,7 +24238,7 @@ index 00000000000..3a180549fc6 +#endif // CPU_LOONGARCH_ICACHE_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/interp_masm_loongarch.hpp b/src/hotspot/cpu/loongarch/interp_masm_loongarch.hpp new file mode 100644 -index 00000000000..a632f7b881e +index 000000000..a632f7b88 --- /dev/null +++ b/src/hotspot/cpu/loongarch/interp_masm_loongarch.hpp @@ -0,0 +1,272 @@ @@ -24031,7 +24516,7 @@ index 00000000000..a632f7b881e +#endif // CPU_LOONGARCH_INTERP_MASM_LOONGARCH_64_HPP diff --git a/src/hotspot/cpu/loongarch/interp_masm_loongarch_64.cpp b/src/hotspot/cpu/loongarch/interp_masm_loongarch_64.cpp new file mode 100644 -index 00000000000..3790af7406c +index 000000000..3790af740 --- /dev/null +++ b/src/hotspot/cpu/loongarch/interp_masm_loongarch_64.cpp @@ -0,0 +1,1965 @@ @@ -26002,7 +26487,7 @@ index 00000000000..3790af7406c +} diff --git a/src/hotspot/cpu/loongarch/interpreterRT_loongarch.hpp b/src/hotspot/cpu/loongarch/interpreterRT_loongarch.hpp new file mode 100644 -index 00000000000..d53d951a160 +index 000000000..d53d951a1 --- /dev/null +++ b/src/hotspot/cpu/loongarch/interpreterRT_loongarch.hpp @@ -0,0 +1,62 @@ @@ -26070,7 +26555,7 @@ index 00000000000..d53d951a160 +#endif // CPU_LOONGARCH_INTERPRETERRT_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/interpreterRT_loongarch_64.cpp b/src/hotspot/cpu/loongarch/interpreterRT_loongarch_64.cpp new file mode 100644 -index 00000000000..46e634599e7 +index 000000000..46e634599 --- /dev/null +++ b/src/hotspot/cpu/loongarch/interpreterRT_loongarch_64.cpp @@ -0,0 +1,264 @@ @@ -26340,7 +26825,7 @@ index 00000000000..46e634599e7 +JRT_END diff --git a/src/hotspot/cpu/loongarch/javaFrameAnchor_loongarch.hpp b/src/hotspot/cpu/loongarch/javaFrameAnchor_loongarch.hpp new file mode 100644 -index 00000000000..b912250dce2 +index 000000000..b912250dc --- /dev/null +++ b/src/hotspot/cpu/loongarch/javaFrameAnchor_loongarch.hpp @@ -0,0 +1,86 @@ @@ -26432,7 +26917,7 @@ index 00000000000..b912250dce2 +#endif // CPU_LOONGARCH_JAVAFRAMEANCHOR_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/jniFastGetField_loongarch_64.cpp b/src/hotspot/cpu/loongarch/jniFastGetField_loongarch_64.cpp new file mode 100644 -index 00000000000..8e8e548e610 +index 000000000..8e8e548e6 --- /dev/null +++ b/src/hotspot/cpu/loongarch/jniFastGetField_loongarch_64.cpp @@ -0,0 +1,179 @@ @@ -26617,7 +27102,7 @@ index 00000000000..8e8e548e610 +} diff --git a/src/hotspot/cpu/loongarch/jniTypes_loongarch.hpp b/src/hotspot/cpu/loongarch/jniTypes_loongarch.hpp new file mode 100644 -index 00000000000..3388ddb9db7 +index 000000000..3388ddb9d --- /dev/null +++ b/src/hotspot/cpu/loongarch/jniTypes_loongarch.hpp @@ -0,0 +1,143 @@ @@ -26766,7 +27251,7 @@ index 00000000000..3388ddb9db7 +#endif // CPU_LOONGARCH_JNITYPES_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/jvmciCodeInstaller_loongarch.cpp b/src/hotspot/cpu/loongarch/jvmciCodeInstaller_loongarch.cpp new file mode 100644 -index 00000000000..1a983e338a4 +index 000000000..1a983e338 --- /dev/null +++ b/src/hotspot/cpu/loongarch/jvmciCodeInstaller_loongarch.cpp @@ -0,0 +1,194 @@ @@ -26966,7 +27451,7 @@ index 00000000000..1a983e338a4 +} diff --git a/src/hotspot/cpu/loongarch/loongarch.ad b/src/hotspot/cpu/loongarch/loongarch.ad new file mode 100644 -index 00000000000..80dff0c7626 +index 000000000..80dff0c76 --- /dev/null +++ b/src/hotspot/cpu/loongarch/loongarch.ad @@ -0,0 +1,25 @@ @@ -26997,10 +27482,10 @@ index 00000000000..80dff0c7626 + diff --git a/src/hotspot/cpu/loongarch/loongarch_64.ad b/src/hotspot/cpu/loongarch/loongarch_64.ad new file mode 100644 -index 00000000000..366df18eb9c +index 000000000..47904e7b8 --- /dev/null +++ b/src/hotspot/cpu/loongarch/loongarch_64.ad -@@ -0,0 +1,15833 @@ +@@ -0,0 +1,15888 @@ +// +// Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2015, 2023, Loongson Technology. All rights reserved. @@ -27595,6 +28080,10 @@ index 00000000000..366df18eb9c + return _NO_CR_REG_mask; +%} + ++reg_class no_FP_reg %{ ++ return _NO_FP_REG_mask; ++%} ++ +reg_class p_has_s6_reg %{ + return _PTR_HAS_S6_REG_mask; +%} @@ -27802,6 +28291,7 @@ index 00000000000..366df18eb9c +extern RegMask _ANY_REG_mask; +extern RegMask _PTR_REG_mask; +extern RegMask _NO_CR_REG_mask; ++extern RegMask _NO_FP_REG_mask; +extern RegMask _PTR_HAS_S6_REG_mask; + +class CallStubImpl { @@ -27881,6 +28371,7 @@ index 00000000000..366df18eb9c +RegMask _ANY_REG_mask; +RegMask _PTR_REG_mask; +RegMask _NO_CR_REG_mask; ++RegMask _NO_FP_REG_mask; +RegMask _PTR_HAS_S6_REG_mask; + +void reg_mask_init() { @@ -27913,6 +28404,9 @@ index 00000000000..366df18eb9c + _NO_CR_REG_mask = _PTR_REG_mask; + _NO_CR_REG_mask.SUBTRACT(_T0_LONG_REG_mask); + ++ _NO_FP_REG_mask = _PTR_REG_mask; ++ _NO_FP_REG_mask.Remove(OptoReg::as_OptoReg(r22->as_VMReg())); ++ + _PTR_HAS_S6_REG_mask.OR(_S6_LONG_REG_mask); +} + @@ -30651,6 +31145,17 @@ index 00000000000..366df18eb9c + interface(REG_INTER); +%} + ++// This operand is not allowed to use FP even if ++// FP is not used to hold the frame pointer. ++operand no_FP_mRegP() %{ ++ constraint(ALLOC_IN_RC(no_FP_reg)); ++ match(RegP); ++ match(mRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ +operand p_has_s6_mRegP() %{ + constraint(ALLOC_IN_RC(p_has_s6_reg)); + match(RegP); @@ -32387,7 +32892,9 @@ index 00000000000..366df18eb9c +// Also known as an 'interprocedural jump'. +// Target of jump will eventually return to caller. +// TailJump below removes the return address. -+instruct TailCalljmpInd(mRegP jump_target, s3_RegP method_ptr) %{ ++// Don't use FP for 'jump_target' because a MachEpilogNode has already been ++// emitted just above the TailCall which has reset FP to the caller state. ++instruct TailCalljmpInd(no_FP_mRegP jump_target, s3_RegP method_ptr) %{ + match(TailCall jump_target method_ptr); + + format %{ "JMP $jump_target \t# @TailCalljmpInd" %} @@ -38223,7 +38730,7 @@ index 00000000000..366df18eb9c +// "restore" before this instruction (in Epilogue), we need to materialize it +// in %i0. +//FIXME -+instruct tailjmpInd(mRegP jump_target, a0_RegP ex_oop, mA1RegI exception_pc) %{ ++instruct tailjmpInd(no_FP_mRegP jump_target, a0_RegP ex_oop, mA1RegI exception_pc) %{ + match( TailJump jump_target ex_oop ); + ins_cost(200); + format %{ "Jmp $jump_target ; ex_oop = $ex_oop #@tailjmpInd" %} @@ -42732,6 +43239,39 @@ index 00000000000..366df18eb9c + ins_pipe(pipe_slow); +%} + ++// ------------------------------ ReverseBytesV -------------------------------- ++ ++instruct reverseBytesV(vReg dst, vReg src) %{ ++ match(Set dst (ReverseBytesV src)); ++ format %{ "(x)vreverse_byte $dst, $src\t# @reverseBytesV" %} ++ ins_encode %{ ++ if (Matcher::vector_length_in_bytes(this) > 16) { ++ switch (Matcher::vector_element_basic_type(this)) { ++ case T_BYTE : if ($dst$$FloatRegister != $src$$FloatRegister) ++ __ xvori_b($dst$$FloatRegister, $src$$FloatRegister, 0); break; ++ case T_SHORT : __ xvshuf4i_b($dst$$FloatRegister, $src$$FloatRegister, 0b10110001); break; ++ case T_INT : __ xvshuf4i_b($dst$$FloatRegister, $src$$FloatRegister, 0b00011011); break; ++ case T_LONG : __ xvshuf4i_w($dst$$FloatRegister, $src$$FloatRegister, 0b10110001); ++ __ xvshuf4i_b($dst$$FloatRegister, $dst$$FloatRegister, 0b00011011); break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { ++ switch (Matcher::vector_element_basic_type(this)) { ++ case T_BYTE : if ($dst$$FloatRegister != $src$$FloatRegister) ++ __ vori_b($dst$$FloatRegister, $src$$FloatRegister, 0); break; ++ case T_SHORT : __ vshuf4i_b($dst$$FloatRegister, $src$$FloatRegister, 0b10110001); break; ++ case T_INT : __ vshuf4i_b($dst$$FloatRegister, $src$$FloatRegister, 0b00011011); break; ++ case T_LONG : __ vshuf4i_w($dst$$FloatRegister, $src$$FloatRegister, 0b10110001); ++ __ vshuf4i_b($dst$$FloatRegister, $dst$$FloatRegister, 0b00011011); break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } ++ %} ++ ins_pipe(pipe_slow); ++%} ++ + +//----------PEEPHOLE RULES----------------------------------------------------- +// These must follow all instruction definitions as they use the names @@ -42836,10 +43376,10 @@ index 00000000000..366df18eb9c + diff --git a/src/hotspot/cpu/loongarch/macroAssembler_loongarch.cpp b/src/hotspot/cpu/loongarch/macroAssembler_loongarch.cpp new file mode 100644 -index 00000000000..e1c033e7085 +index 000000000..e2f69cea3 --- /dev/null +++ b/src/hotspot/cpu/loongarch/macroAssembler_loongarch.cpp -@@ -0,0 +1,4238 @@ +@@ -0,0 +1,4242 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Loongson Technology. All rights reserved. @@ -46164,12 +46704,16 @@ index 00000000000..e1c033e7085 + address prev = pc() - NativeInstruction::sync_instruction_size; + address last = code()->last_insn(); + if (last != nullptr && ((NativeInstruction*)last)->is_sync() && prev == last) { -+ code()->set_last_insn(nullptr); + NativeMembar *membar = (NativeMembar*)prev; ++#ifndef PRODUCT ++ char buf[50]; ++ snprintf(buf, sizeof(buf), "merged membar 0x%x 0x%x => 0x%x", ++ (Ordering | membar->get_hint()), (Ordering | (~hint & 0xF)), (Ordering | (membar->get_hint() & (~hint & 0xF)))); ++ block_comment(buf); ++#endif + // merged membar + // e.g. LoadLoad and LoadLoad|LoadStore to LoadLoad|LoadStore + membar->set_hint(membar->get_hint() & (~hint & 0xF)); -+ block_comment("merged membar"); + } else { + code()->set_last_insn(pc()); + Assembler::membar(hint); @@ -47080,7 +47624,7 @@ index 00000000000..e1c033e7085 +#endif diff --git a/src/hotspot/cpu/loongarch/macroAssembler_loongarch.hpp b/src/hotspot/cpu/loongarch/macroAssembler_loongarch.hpp new file mode 100644 -index 00000000000..6727de3aa7a +index 000000000..6727de3aa --- /dev/null +++ b/src/hotspot/cpu/loongarch/macroAssembler_loongarch.hpp @@ -0,0 +1,809 @@ @@ -47895,7 +48439,7 @@ index 00000000000..6727de3aa7a +#endif // CPU_LOONGARCH_MACROASSEMBLER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/macroAssembler_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/macroAssembler_loongarch.inline.hpp new file mode 100644 -index 00000000000..43b388a2c4b +index 000000000..43b388a2c --- /dev/null +++ b/src/hotspot/cpu/loongarch/macroAssembler_loongarch.inline.hpp @@ -0,0 +1,937 @@ @@ -48838,7 +49382,7 @@ index 00000000000..43b388a2c4b +#endif // CPU_LOONGARCH_MACROASSEMBLER_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/macroAssembler_loongarch_chacha.cpp b/src/hotspot/cpu/loongarch/macroAssembler_loongarch_chacha.cpp new file mode 100644 -index 00000000000..ea4d5a2ac4c +index 000000000..ea4d5a2ac --- /dev/null +++ b/src/hotspot/cpu/loongarch/macroAssembler_loongarch_chacha.cpp @@ -0,0 +1,86 @@ @@ -48930,13 +49474,13 @@ index 00000000000..ea4d5a2ac4c +} diff --git a/src/hotspot/cpu/loongarch/macroAssembler_loongarch_trig.cpp b/src/hotspot/cpu/loongarch/macroAssembler_loongarch_trig.cpp new file mode 100644 -index 00000000000..b4a1b09b375 +index 000000000..0c31904a3 --- /dev/null +++ b/src/hotspot/cpu/loongarch/macroAssembler_loongarch_trig.cpp -@@ -0,0 +1,1625 @@ +@@ -0,0 +1,1626 @@ +/* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Cavium. All rights reserved. (By BELLSOFT) -+ * Copyright (c) 2022, Loongson Technology. All rights reserved. ++ * Copyright (c) 2022, 2024, Loongson Technology. 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 @@ -49830,7 +50374,7 @@ index 00000000000..b4a1b09b375 + b(Q_DONE); + bind(JX_IS_0); + if (UseLASX) { -+ xvfmul_d(v28, v18, v6); // f[0,1] * x[0] ++ xvfmul_d(v28, v18, v6); // f[0,3] * x[0] + fmul_d(v30, v19, v6); // f[4] * x[0] + } else { + vfmul_d(v28, v18, v6); // f[0,1] * x[0] @@ -50064,6 +50608,7 @@ index 00000000000..b4a1b09b375 + st_w(tmp2, SCR2, 0); + addi_w(SCR1, SCR1, 24); + addi_w(jz, jz, 1); ++ alsl_d(SCR2, jz, iqBase, 2 - 1); + st_w(tmp3, SCR2, 0); // iq[jz] = (int) fw + b(Z_ZERO_CHECK_DONE); + bind(Z_IS_LESS_THAN_TWO24B); @@ -50561,7 +51106,7 @@ index 00000000000..b4a1b09b375 +} diff --git a/src/hotspot/cpu/loongarch/matcher_loongarch.hpp b/src/hotspot/cpu/loongarch/matcher_loongarch.hpp new file mode 100644 -index 00000000000..79b5d4157a8 +index 000000000..79b5d4157 --- /dev/null +++ b/src/hotspot/cpu/loongarch/matcher_loongarch.hpp @@ -0,0 +1,181 @@ @@ -50748,7 +51293,7 @@ index 00000000000..79b5d4157a8 +#endif // CPU_LOONGARCH_MATCHER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/methodHandles_loongarch.cpp b/src/hotspot/cpu/loongarch/methodHandles_loongarch.cpp new file mode 100644 -index 00000000000..4b5d41aea07 +index 000000000..4b5d41aea --- /dev/null +++ b/src/hotspot/cpu/loongarch/methodHandles_loongarch.cpp @@ -0,0 +1,568 @@ @@ -51322,7 +51867,7 @@ index 00000000000..4b5d41aea07 +#endif //PRODUCT diff --git a/src/hotspot/cpu/loongarch/methodHandles_loongarch.hpp b/src/hotspot/cpu/loongarch/methodHandles_loongarch.hpp new file mode 100644 -index 00000000000..8e129225509 +index 000000000..8e1292255 --- /dev/null +++ b/src/hotspot/cpu/loongarch/methodHandles_loongarch.hpp @@ -0,0 +1,65 @@ @@ -51393,7 +51938,7 @@ index 00000000000..8e129225509 + } diff --git a/src/hotspot/cpu/loongarch/nativeInst_loongarch.cpp b/src/hotspot/cpu/loongarch/nativeInst_loongarch.cpp new file mode 100644 -index 00000000000..c298cda5de7 +index 000000000..c298cda5d --- /dev/null +++ b/src/hotspot/cpu/loongarch/nativeInst_loongarch.cpp @@ -0,0 +1,537 @@ @@ -51936,7 +52481,7 @@ index 00000000000..c298cda5de7 +} diff --git a/src/hotspot/cpu/loongarch/nativeInst_loongarch.hpp b/src/hotspot/cpu/loongarch/nativeInst_loongarch.hpp new file mode 100644 -index 00000000000..3a322a218a3 +index 000000000..3a322a218 --- /dev/null +++ b/src/hotspot/cpu/loongarch/nativeInst_loongarch.hpp @@ -0,0 +1,595 @@ @@ -52537,7 +53082,7 @@ index 00000000000..3a322a218a3 +#endif // CPU_LOONGARCH_NATIVEINST_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/registerMap_loongarch.hpp b/src/hotspot/cpu/loongarch/registerMap_loongarch.hpp new file mode 100644 -index 00000000000..9b0ff3eae76 +index 000000000..9b0ff3eae --- /dev/null +++ b/src/hotspot/cpu/loongarch/registerMap_loongarch.hpp @@ -0,0 +1,59 @@ @@ -52602,7 +53147,7 @@ index 00000000000..9b0ff3eae76 +#endif // CPU_LOONGARCH_REGISTERMAP_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/register_loongarch.cpp b/src/hotspot/cpu/loongarch/register_loongarch.cpp new file mode 100644 -index 00000000000..5378fce5cd2 +index 000000000..5378fce5c --- /dev/null +++ b/src/hotspot/cpu/loongarch/register_loongarch.cpp @@ -0,0 +1,61 @@ @@ -52669,7 +53214,7 @@ index 00000000000..5378fce5cd2 +} diff --git a/src/hotspot/cpu/loongarch/register_loongarch.hpp b/src/hotspot/cpu/loongarch/register_loongarch.hpp new file mode 100644 -index 00000000000..25f7abfe75e +index 000000000..6ffdd41a5 --- /dev/null +++ b/src/hotspot/cpu/loongarch/register_loongarch.hpp @@ -0,0 +1,479 @@ @@ -52730,7 +53275,7 @@ index 00000000000..25f7abfe75e + + public: + // accessors -+ constexpr int raw_encoding() const { return this - first(); } ++ constexpr int raw_encoding() const { return checked_cast(this - first()); } + constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } + constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } + @@ -52900,7 +53445,7 @@ index 00000000000..25f7abfe75e + + public: + // accessors -+ constexpr int raw_encoding() const { return this - first(); } ++ constexpr int raw_encoding() const { return checked_cast(this - first()); } + constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } + constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } + @@ -53061,7 +53606,7 @@ index 00000000000..25f7abfe75e + + public: + // accessors -+ int raw_encoding() const { return this - first(); } ++ int raw_encoding() const { return checked_cast(this - first()); } + int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } + bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } + @@ -53154,7 +53699,7 @@ index 00000000000..25f7abfe75e +#endif //CPU_LOONGARCH_REGISTER_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/relocInfo_loongarch.cpp b/src/hotspot/cpu/loongarch/relocInfo_loongarch.cpp new file mode 100644 -index 00000000000..d7011d57525 +index 000000000..d7011d575 --- /dev/null +++ b/src/hotspot/cpu/loongarch/relocInfo_loongarch.cpp @@ -0,0 +1,133 @@ @@ -53293,7 +53838,7 @@ index 00000000000..d7011d57525 +} diff --git a/src/hotspot/cpu/loongarch/relocInfo_loongarch.hpp b/src/hotspot/cpu/loongarch/relocInfo_loongarch.hpp new file mode 100644 -index 00000000000..c85ca4963f3 +index 000000000..c85ca4963 --- /dev/null +++ b/src/hotspot/cpu/loongarch/relocInfo_loongarch.hpp @@ -0,0 +1,44 @@ @@ -53343,13 +53888,13 @@ index 00000000000..c85ca4963f3 +#endif // CPU_LOONGARCH_RELOCINFO_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/sharedRuntime_loongarch_64.cpp b/src/hotspot/cpu/loongarch/sharedRuntime_loongarch_64.cpp new file mode 100644 -index 00000000000..930b1c18841 +index 000000000..834a1e7ff --- /dev/null +++ b/src/hotspot/cpu/loongarch/sharedRuntime_loongarch_64.cpp -@@ -0,0 +1,2975 @@ +@@ -0,0 +1,2979 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2015, 2023, Loongson Technology. All rights reserved. ++ * Copyright (c) 2015, 2024, Loongson Technology. 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 @@ -53697,7 +54242,7 @@ index 00000000000..930b1c18841 + + uint int_args = 0; + uint fp_args = 0; -+ uint stk_args = 0; // inc by 2 each time ++ uint stk_args = 0; + + for (int i = 0; i < total_args_passed; i++) { + switch (sig_bt[i]) { @@ -53714,8 +54259,9 @@ index 00000000000..930b1c18841 + if (int_args < Argument::n_int_register_parameters_j) { + regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); + } else { ++ stk_args = align_up(stk_args, 2); + regs[i].set1(VMRegImpl::stack2reg(stk_args)); -+ stk_args += 2; ++ stk_args += 1; + } + break; + case T_LONG: @@ -53727,6 +54273,7 @@ index 00000000000..930b1c18841 + if (int_args < Argument::n_int_register_parameters_j) { + regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); + } else { ++ stk_args = align_up(stk_args, 2); + regs[i].set2(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } @@ -53735,8 +54282,9 @@ index 00000000000..930b1c18841 + if (fp_args < Argument::n_float_register_parameters_j) { + regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); + } else { ++ stk_args = align_up(stk_args, 2); + regs[i].set1(VMRegImpl::stack2reg(stk_args)); -+ stk_args += 2; ++ stk_args += 1; + } + break; + case T_DOUBLE: @@ -53744,6 +54292,7 @@ index 00000000000..930b1c18841 + if (fp_args < Argument::n_float_register_parameters_j) { + regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); + } else { ++ stk_args = align_up(stk_args, 2); + regs[i].set2(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } @@ -53754,7 +54303,7 @@ index 00000000000..930b1c18841 + } + } + -+ return align_up(stk_args, 2); ++ return stk_args; +} + +// Patch the callers callsite with entry to compiled code if it exists. @@ -56324,13 +56873,13 @@ index 00000000000..930b1c18841 +extern "C" int SpinPause() {return 0;} diff --git a/src/hotspot/cpu/loongarch/smallRegisterMap_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/smallRegisterMap_loongarch.inline.hpp new file mode 100644 -index 00000000000..ebd11807b24 +index 000000000..7417ece8f --- /dev/null +++ b/src/hotspot/cpu/loongarch/smallRegisterMap_loongarch.inline.hpp -@@ -0,0 +1,92 @@ +@@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2022, Loongson Technology. All rights reserved. ++ * Copyright (c) 2022, 2024, Loongson Technology. 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 @@ -56361,8 +56910,15 @@ index 00000000000..ebd11807b24 + +// Java frames don't have callee saved registers (except for FP), so we can use a smaller RegisterMap +class SmallRegisterMap { ++ constexpr SmallRegisterMap() = default; ++ ~SmallRegisterMap() = default; ++ NONCOPYABLE(SmallRegisterMap); ++ +public: -+ static constexpr SmallRegisterMap* instance = nullptr; ++ static const SmallRegisterMap* instance() { ++ static constexpr SmallRegisterMap the_instance{}; ++ return &the_instance; ++ } +private: + static void assert_is_fp(VMReg r) NOT_DEBUG_RETURN + DEBUG_ONLY({ assert (r == FP->as_VMReg() || r == FP->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -56379,17 +56935,6 @@ index 00000000000..ebd11807b24 + return map; + } + -+ SmallRegisterMap() {} -+ -+ SmallRegisterMap(const RegisterMap* map) { -+ #ifdef ASSERT -+ for(int i = 0; i < RegisterMap::reg_count; i++) { -+ VMReg r = VMRegImpl::as_VMReg(i); -+ if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_fp(r); -+ } -+ #endif -+ } -+ + inline address location(VMReg reg, intptr_t* sp) const { + assert_is_fp(reg); + return (address)(sp - 2); @@ -56422,7 +56967,7 @@ index 00000000000..ebd11807b24 +#endif // CPU_LOONGARCH_SMALLREGISTERMAP_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/stackChunkFrameStream_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/stackChunkFrameStream_loongarch.inline.hpp new file mode 100644 -index 00000000000..d329c43d661 +index 000000000..0be80eb3e --- /dev/null +++ b/src/hotspot/cpu/loongarch/stackChunkFrameStream_loongarch.inline.hpp @@ -0,0 +1,142 @@ @@ -56463,7 +57008,7 @@ index 00000000000..d329c43d661 +inline bool StackChunkFrameStream::is_in_frame(void* p0) const { + assert(!is_done(), ""); + intptr_t* p = (intptr_t*)p0; -+ int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; ++ int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int frame_size = _cb->frame_size() + argsize; + return p == sp() - 2 || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); +} @@ -56543,8 +57088,8 @@ index 00000000000..d329c43d661 + f.interpreted_frame_oop_map(&mask); + return mask.num_oops() + + 1 // for the mirror oop -+ + ((intptr_t*)f.interpreter_frame_monitor_begin() -+ - (intptr_t*)f.interpreter_frame_monitor_end()) / BasicObjectLock::size(); ++ + pointer_delta_as_int((intptr_t*)f.interpreter_frame_monitor_begin(), ++ (intptr_t*)f.interpreter_frame_monitor_end()) / BasicObjectLock::size(); +} + +template<> @@ -56570,7 +57115,7 @@ index 00000000000..d329c43d661 +#endif // CPU_LOONGARCH_STACKCHUNKFRAMESTREAM_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/stackChunkOop_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/stackChunkOop_loongarch.inline.hpp new file mode 100644 -index 00000000000..3e6b0e2a5cb +index 000000000..3e6b0e2a5 --- /dev/null +++ b/src/hotspot/cpu/loongarch/stackChunkOop_loongarch.inline.hpp @@ -0,0 +1,43 @@ @@ -56619,7 +57164,7 @@ index 00000000000..3e6b0e2a5cb +#endif // CPU_LOONGARCH_STACKCHUNKOOP_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/stubGenerator_loongarch_64.cpp b/src/hotspot/cpu/loongarch/stubGenerator_loongarch_64.cpp new file mode 100644 -index 00000000000..87bfcb3f58f +index 000000000..87bfcb3f5 --- /dev/null +++ b/src/hotspot/cpu/loongarch/stubGenerator_loongarch_64.cpp @@ -0,0 +1,5721 @@ @@ -62346,7 +62891,7 @@ index 00000000000..87bfcb3f58f +} diff --git a/src/hotspot/cpu/loongarch/stubRoutines_loongarch.hpp b/src/hotspot/cpu/loongarch/stubRoutines_loongarch.hpp new file mode 100644 -index 00000000000..2614bbd6832 +index 000000000..2614bbd68 --- /dev/null +++ b/src/hotspot/cpu/loongarch/stubRoutines_loongarch.hpp @@ -0,0 +1,118 @@ @@ -62470,7 +63015,7 @@ index 00000000000..2614bbd6832 +#endif // CPU_LOONGARCH_STUBROUTINES_LOONGARCH_64_HPP diff --git a/src/hotspot/cpu/loongarch/stubRoutines_loongarch_64.cpp b/src/hotspot/cpu/loongarch/stubRoutines_loongarch_64.cpp new file mode 100644 -index 00000000000..4d8fe415483 +index 000000000..4d8fe4154 --- /dev/null +++ b/src/hotspot/cpu/loongarch/stubRoutines_loongarch_64.cpp @@ -0,0 +1,196 @@ @@ -62672,7 +63217,7 @@ index 00000000000..4d8fe415483 +}; diff --git a/src/hotspot/cpu/loongarch/templateInterpreterGenerator_loongarch.cpp b/src/hotspot/cpu/loongarch/templateInterpreterGenerator_loongarch.cpp new file mode 100644 -index 00000000000..f625f9b43b9 +index 000000000..f625f9b43 --- /dev/null +++ b/src/hotspot/cpu/loongarch/templateInterpreterGenerator_loongarch.cpp @@ -0,0 +1,2106 @@ @@ -64784,7 +65329,7 @@ index 00000000000..f625f9b43b9 +#endif // !PRODUCT diff --git a/src/hotspot/cpu/loongarch/templateTable_loongarch.hpp b/src/hotspot/cpu/loongarch/templateTable_loongarch.hpp new file mode 100644 -index 00000000000..ddb38faf446 +index 000000000..ddb38faf4 --- /dev/null +++ b/src/hotspot/cpu/loongarch/templateTable_loongarch.hpp @@ -0,0 +1,43 @@ @@ -64833,7 +65378,7 @@ index 00000000000..ddb38faf446 +#endif // CPU_LOONGARCH_TEMPLATETABLE_LOONGARCH_64_HPP diff --git a/src/hotspot/cpu/loongarch/templateTable_loongarch_64.cpp b/src/hotspot/cpu/loongarch/templateTable_loongarch_64.cpp new file mode 100644 -index 00000000000..7d308d998dd +index 000000000..7d308d998 --- /dev/null +++ b/src/hotspot/cpu/loongarch/templateTable_loongarch_64.cpp @@ -0,0 +1,4007 @@ @@ -68846,13 +69391,13 @@ index 00000000000..7d308d998dd +} diff --git a/src/hotspot/cpu/loongarch/upcallLinker_loongarch_64.cpp b/src/hotspot/cpu/loongarch/upcallLinker_loongarch_64.cpp new file mode 100644 -index 00000000000..ccaa16bb6b1 +index 000000000..da902dda7 --- /dev/null +++ b/src/hotspot/cpu/loongarch/upcallLinker_loongarch_64.cpp -@@ -0,0 +1,347 @@ +@@ -0,0 +1,351 @@ +/* + * Copyright (c) 2020, Red Hat, Inc. All rights reserved. -+ * Copyright (c) 2021, 2023, Loongson Technology. All rights reserved. ++ * Copyright (c) 2021, 2024, Loongson Technology. 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 @@ -69092,9 +69637,13 @@ index 00000000000..ccaa16bb6b1 + __ mov_metadata(Rmethod, entry); + __ st_d(Rmethod, TREG, in_bytes(JavaThread::callee_target_offset())); // just in case callee is deoptimized + ++ __ push_cont_fastpath(TREG); ++ + __ ld_d(T4, Rmethod, in_bytes(Method::from_compiled_offset())); + __ jalr(T4); + ++ __ pop_cont_fastpath(TREG); ++ + // return value shuffle + if (!needs_return_buffer) { +#ifdef ASSERT @@ -69199,7 +69748,7 @@ index 00000000000..ccaa16bb6b1 +} diff --git a/src/hotspot/cpu/loongarch/vmStructs_loongarch.hpp b/src/hotspot/cpu/loongarch/vmStructs_loongarch.hpp new file mode 100644 -index 00000000000..5b9f7b78981 +index 000000000..5b9f7b789 --- /dev/null +++ b/src/hotspot/cpu/loongarch/vmStructs_loongarch.hpp @@ -0,0 +1,61 @@ @@ -69266,7 +69815,7 @@ index 00000000000..5b9f7b78981 +#endif // CPU_LOONGARCH_VMSTRUCTS_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/vm_version_loongarch.cpp b/src/hotspot/cpu/loongarch/vm_version_loongarch.cpp new file mode 100644 -index 00000000000..44bca90d2c2 +index 000000000..44bca90d2 --- /dev/null +++ b/src/hotspot/cpu/loongarch/vm_version_loongarch.cpp @@ -0,0 +1,511 @@ @@ -69783,7 +70332,7 @@ index 00000000000..44bca90d2c2 +} diff --git a/src/hotspot/cpu/loongarch/vm_version_loongarch.hpp b/src/hotspot/cpu/loongarch/vm_version_loongarch.hpp new file mode 100644 -index 00000000000..04bd6942dc2 +index 000000000..04bd6942d --- /dev/null +++ b/src/hotspot/cpu/loongarch/vm_version_loongarch.hpp @@ -0,0 +1,308 @@ @@ -70097,7 +70646,7 @@ index 00000000000..04bd6942dc2 +#endif // CPU_LOONGARCH_VM_VERSION_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/vmreg_loongarch.cpp b/src/hotspot/cpu/loongarch/vmreg_loongarch.cpp new file mode 100644 -index 00000000000..3433ca028fe +index 000000000..3433ca028 --- /dev/null +++ b/src/hotspot/cpu/loongarch/vmreg_loongarch.cpp @@ -0,0 +1,54 @@ @@ -70157,7 +70706,7 @@ index 00000000000..3433ca028fe +} diff --git a/src/hotspot/cpu/loongarch/vmreg_loongarch.hpp b/src/hotspot/cpu/loongarch/vmreg_loongarch.hpp new file mode 100644 -index 00000000000..ff79e91f60d +index 000000000..ff79e91f6 --- /dev/null +++ b/src/hotspot/cpu/loongarch/vmreg_loongarch.hpp @@ -0,0 +1,58 @@ @@ -70221,7 +70770,7 @@ index 00000000000..ff79e91f60d +#endif // CPU_LOONGARCH_VMREG_LOONGARCH_HPP diff --git a/src/hotspot/cpu/loongarch/vmreg_loongarch.inline.hpp b/src/hotspot/cpu/loongarch/vmreg_loongarch.inline.hpp new file mode 100644 -index 00000000000..3f158bd9bae +index 000000000..3f158bd9b --- /dev/null +++ b/src/hotspot/cpu/loongarch/vmreg_loongarch.inline.hpp @@ -0,0 +1,38 @@ @@ -70265,7 +70814,7 @@ index 00000000000..3f158bd9bae +#endif // CPU_LOONGARCH_VMREG_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/vmstorage_loongarch.hpp b/src/hotspot/cpu/loongarch/vmstorage_loongarch.hpp new file mode 100644 -index 00000000000..03b53dc81f8 +index 000000000..03b53dc81 --- /dev/null +++ b/src/hotspot/cpu/loongarch/vmstorage_loongarch.hpp @@ -0,0 +1,87 @@ @@ -70358,7 +70907,7 @@ index 00000000000..03b53dc81f8 +#endif // CPU_LOONGARCH_VMSTORAGE_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/cpu/loongarch/vtableStubs_loongarch_64.cpp b/src/hotspot/cpu/loongarch/vtableStubs_loongarch_64.cpp new file mode 100644 -index 00000000000..ab12021832d +index 000000000..ab1202183 --- /dev/null +++ b/src/hotspot/cpu/loongarch/vtableStubs_loongarch_64.cpp @@ -0,0 +1,312 @@ @@ -70675,7 +71224,7 @@ index 00000000000..ab12021832d + return icache_line_size; +} diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp -index aa8be1d897d..f71a20207c5 100644 +index 5ebd57fb3..f74969e66 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -23,6 +23,12 @@ @@ -70691,7 +71240,7 @@ index aa8be1d897d..f71a20207c5 100644 // no precompiled headers #include "classfile/vmSymbols.hpp" #include "code/icBuffer.hpp" -@@ -2191,6 +2197,12 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { +@@ -2236,6 +2242,12 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { return false; } @@ -70704,7 +71253,7 @@ index aa8be1d897d..f71a20207c5 100644 #ifdef __GLIBC__ // For Glibc, print a one-liner with the malloc tunables. // Most important and popular is MALLOC_ARENA_MAX, but we are -@@ -2407,7 +2419,7 @@ void os::print_memory_info(outputStream* st) { +@@ -2452,7 +2464,7 @@ void os::print_memory_info(outputStream* st) { // before "flags" so if we find a second "model name", then the // "flags" field is considered missing. static bool print_model_name_and_flags(outputStream* st, char* buf, size_t buflen) { @@ -70713,7 +71262,7 @@ index aa8be1d897d..f71a20207c5 100644 // Other platforms have less repetitive cpuinfo files FILE *fp = os::fopen("/proc/cpuinfo", "r"); if (fp) { -@@ -2519,7 +2531,7 @@ void os::jfr_report_memory_info() { +@@ -2564,7 +2576,7 @@ void os::jfr_report_memory_info() { #endif // INCLUDE_JFR @@ -70722,7 +71271,7 @@ index aa8be1d897d..f71a20207c5 100644 const char* search_string = "model name"; #elif defined(M68K) const char* search_string = "CPU"; -@@ -4490,6 +4502,44 @@ void os::Linux::numa_init() { +@@ -4567,6 +4579,44 @@ void os::Linux::numa_init() { // If there's only one node (they start from 0) or if the process // is bound explicitly to a single node using membind, disable NUMA UseNUMA = false; @@ -70768,7 +71317,7 @@ index aa8be1d897d..f71a20207c5 100644 LogTarget(Info,os) log; LogStream ls(log); diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp -index ace7e4ab2dd..4baf381b2f2 100644 +index 029f2aa7a..78bf68a72 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -22,6 +22,12 @@ @@ -70784,7 +71333,7 @@ index ace7e4ab2dd..4baf381b2f2 100644 #ifndef OS_LINUX_OS_LINUX_HPP #define OS_LINUX_OS_LINUX_HPP -@@ -193,6 +199,8 @@ class os::Linux { +@@ -195,6 +201,8 @@ class os::Linux { // none present @@ -70794,7 +71343,7 @@ index ace7e4ab2dd..4baf381b2f2 100644 static void numa_init(); diff --git a/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp b/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp -index 609967128fb..d67deeda164 100644 +index 51397b139..96269fef5 100644 --- a/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp +++ b/src/hotspot/os/linux/systemMemoryBarrier_linux.cpp @@ -22,6 +22,12 @@ @@ -70809,9 +71358,9 @@ index 609967128fb..d67deeda164 100644 + #include "precompiled.hpp" #include "logging/log.hpp" - #include "runtime/os.hpp" -@@ -43,6 +49,8 @@ - #define SYS_membarrier 283 + #include "os_linux.hpp" +@@ -45,6 +51,8 @@ + #define SYS_membarrier 389 #elif defined(ALPHA) #define SYS_membarrier 517 + #elif defined(LOONGARCH) @@ -70819,182 +71368,9 @@ index 609967128fb..d67deeda164 100644 #else #error define SYS_membarrier for the arch #endif -diff --git a/src/hotspot/os_cpu/linux_loongarch/amcas_asm.h b/src/hotspot/os_cpu/linux_loongarch/amcas_asm.h -new file mode 100644 -index 00000000000..305974a178f ---- /dev/null -+++ b/src/hotspot/os_cpu/linux_loongarch/amcas_asm.h -@@ -0,0 +1,167 @@ -+/* -+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2023, Loongson Technology. 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 __AMCAS_ASM_H__ -+#define __AMCAS_ASM_H__ -+ asm( -+ ".macro parse_r var r \n\t" -+ "\\var = -1 \n\t" -+ ".ifc \\r, $r0 \n\t" -+ "\\var = 0 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r1 \n\t" -+ "\\var = 1 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r2 \n\t" -+ "\\var = 2 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r3 \n\t" -+ "\\var = 3 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r4 \n\t" -+ "\\var = 4 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r5 \n\t" -+ "\\var = 5 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r6 \n\t" -+ "\\var = 6 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r7 \n\t" -+ "\\var = 7 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r8 \n\t" -+ "\\var = 8 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r9 \n\t" -+ "\\var = 9 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r10 \n\t" -+ "\\var = 10 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r11 \n\t" -+ "\\var = 11 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r12 \n\t" -+ "\\var = 12 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r13 \n\t" -+ "\\var = 13 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r14 \n\t" -+ "\\var = 14 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r15 \n\t" -+ "\\var = 15 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r16 \n\t" -+ "\\var = 16 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r17 \n\t" -+ "\\var = 17 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r18 \n\t" -+ "\\var = 18 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r19 \n\t" -+ "\\var = 19 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r20 \n\t" -+ "\\var = 20 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r21 \n\t" -+ "\\var = 21 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r22 \n\t" -+ "\\var = 22 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r23 \n\t" -+ "\\var = 23 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r24 \n\t" -+ "\\var = 24 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r25 \n\t" -+ "\\var = 25 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r26 \n\t" -+ "\\var = 26 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r27 \n\t" -+ "\\var = 27 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r28 \n\t" -+ "\\var = 28 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r29 \n\t" -+ "\\var = 29 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r30 \n\t" -+ "\\var = 30 \n\t" -+ ".endif \n\t" -+ ".ifc \\r, $r31 \n\t" -+ "\\var = 31 \n\t" -+ ".endif \n\t" -+ ".iflt \\var \n\t" -+ ".error \n\t" -+ ".endif \n\t" -+ ".endm \n\t" -+ -+ ".macro amcas_w rd, rk, rj \n\t" -+ "parse_r d, \\rd \n\t" -+ "parse_r j, \\rj \n\t" -+ "parse_r k, \\rk \n\t" -+ ".word ((0b00111000010110010 << 15) | (k << 10) | (j << 5) | d) \n\t" -+ ".endm \n\t" -+ -+ ".macro amcas_d rd, rk, rj \n\t" -+ "parse_r d, \\rd \n\t" -+ "parse_r j, \\rj \n\t" -+ "parse_r k, \\rk \n\t" -+ ".word ((0b00111000010110011 << 15) | (k << 10) | (j << 5) | d) \n\t" -+ ".endm \n\t" -+ -+ ".macro amcas_db_b rd, rk, rj \n\t" -+ "parse_r d, \\rd \n\t" -+ "parse_r j, \\rj \n\t" -+ "parse_r k, \\rk \n\t" -+ ".word ((0b00111000010110100 << 15) | (k << 10) | (j << 5) | d) \n\t" -+ ".endm \n\t" -+ -+ ".macro amcas_db_w rd, rk, rj \n\t" -+ "parse_r d, \\rd \n\t" -+ "parse_r j, \\rj \n\t" -+ "parse_r k, \\rk \n\t" -+ ".word ((0b00111000010110110 << 15) | (k << 10) | (j << 5) | d) \n\t" -+ ".endm \n\t" -+ -+ ".macro amcas_db_d rd, rk, rj \n\t" -+ "parse_r d, \\rd \n\t" -+ "parse_r j, \\rj \n\t" -+ "parse_r k, \\rk \n\t" -+ ".word ((0b00111000010110111 << 15) | (k << 10) | (j << 5) | d) \n\t" -+ ".endm \n\t" -+ ); -+#endif /* __AMCAS_ASM_H__ */ diff --git a/src/hotspot/os_cpu/linux_loongarch/assembler_linux_loongarch.cpp b/src/hotspot/os_cpu/linux_loongarch/assembler_linux_loongarch.cpp new file mode 100644 -index 00000000000..30719a0340b +index 000000000..30719a034 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/assembler_linux_loongarch.cpp @@ -0,0 +1,24 @@ @@ -71024,13 +71400,13 @@ index 00000000000..30719a0340b + */ diff --git a/src/hotspot/os_cpu/linux_loongarch/atomic_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/atomic_linux_loongarch.hpp new file mode 100644 -index 00000000000..bb820b5e5ae +index 000000000..f0c7a7e3a --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/atomic_linux_loongarch.hpp -@@ -0,0 +1,361 @@ +@@ -0,0 +1,499 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2015, 2023, Loongson Technology. All rights reserved. ++ * Copyright (c) 2015, 2024, Loongson Technology. 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 @@ -71057,10 +71433,146 @@ index 00000000000..bb820b5e5ae +#define OS_CPU_LINUX_LOONGARCH_ATOMIC_LINUX_LOONGARCH_HPP + +#include "runtime/vm_version.hpp" -+#include "amcas_asm.h" + +// Implementation of class atomic + ++#define AMCAS_MACRO asm volatile ( \ ++ ".ifndef _ASM_ASMMACRO_ \n\t" \ ++ ".set _ASM_ASMMACRO_, 1 \n\t" \ ++ ".macro parse_r var r \n\t" \ ++ "\\var = -1 \n\t" \ ++ ".ifc \\r, $r0 \n\t" \ ++ "\\var = 0 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r1 \n\t" \ ++ "\\var = 1 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r2 \n\t" \ ++ "\\var = 2 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r3 \n\t" \ ++ "\\var = 3 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r4 \n\t" \ ++ "\\var = 4 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r5 \n\t" \ ++ "\\var = 5 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r6 \n\t" \ ++ "\\var = 6 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r7 \n\t" \ ++ "\\var = 7 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r8 \n\t" \ ++ "\\var = 8 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r9 \n\t" \ ++ "\\var = 9 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r10 \n\t" \ ++ "\\var = 10 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r11 \n\t" \ ++ "\\var = 11 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r12 \n\t" \ ++ "\\var = 12 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r13 \n\t" \ ++ "\\var = 13 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r14 \n\t" \ ++ "\\var = 14 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r15 \n\t" \ ++ "\\var = 15 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r16 \n\t" \ ++ "\\var = 16 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r17 \n\t" \ ++ "\\var = 17 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r18 \n\t" \ ++ "\\var = 18 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r19 \n\t" \ ++ "\\var = 19 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r20 \n\t" \ ++ "\\var = 20 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r21 \n\t" \ ++ "\\var = 21 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r22 \n\t" \ ++ "\\var = 22 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r23 \n\t" \ ++ "\\var = 23 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r24 \n\t" \ ++ "\\var = 24 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r25 \n\t" \ ++ "\\var = 25 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r26 \n\t" \ ++ "\\var = 26 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r27 \n\t" \ ++ "\\var = 27 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r28 \n\t" \ ++ "\\var = 28 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r29 \n\t" \ ++ "\\var = 29 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r30 \n\t" \ ++ "\\var = 30 \n\t" \ ++ ".endif \n\t" \ ++ ".ifc \\r, $r31 \n\t" \ ++ "\\var = 31 \n\t" \ ++ ".endif \n\t" \ ++ ".iflt \\var \n\t" \ ++ ".endif \n\t" \ ++ ".endm \n\t" \ ++ ".macro amcas_w rd, rk, rj \n\t" \ ++ "parse_r d, \\rd \n\t" \ ++ "parse_r j, \\rj \n\t" \ ++ "parse_r k, \\rk \n\t" \ ++ ".word ((0b00111000010110010 << 15) | (k << 10) | (j << 5) | d) \n\t" \ ++ ".endm \n\t" \ ++ ".macro amcas_d rd, rk, rj \n\t" \ ++ "parse_r d, \\rd \n\t" \ ++ "parse_r j, \\rj \n\t" \ ++ "parse_r k, \\rk \n\t" \ ++ ".word ((0b00111000010110011 << 15) | (k << 10) | (j << 5) | d) \n\t" \ ++ ".endm \n\t" \ ++ ".macro amcas_db_b rd, rk, rj \n\t" \ ++ "parse_r d, \\rd \n\t" \ ++ "parse_r j, \\rj \n\t" \ ++ "parse_r k, \\rk \n\t" \ ++ ".word ((0b00111000010110100 << 15) | (k << 10) | (j << 5) | d) \n\t" \ ++ ".endm \n\t" \ ++ ".macro amcas_db_w rd, rk, rj \n\t" \ ++ "parse_r d, \\rd \n\t" \ ++ "parse_r j, \\rj \n\t" \ ++ "parse_r k, \\rk \n\t" \ ++ ".word ((0b00111000010110110 << 15) | (k << 10) | (j << 5) | d) \n\t" \ ++ ".endm \n\t" \ ++ ".macro amcas_db_d rd, rk, rj \n\t" \ ++ "parse_r d, \\rd \n\t" \ ++ "parse_r j, \\rj \n\t" \ ++ "parse_r k, \\rk \n\t" \ ++ ".word ((0b00111000010110111 << 15) | (k << 10) | (j << 5) | d) \n\t" \ ++ ".endm \n\t" \ ++ ".endif \n\t" \ ++ ); ++ +template +struct Atomic::PlatformAdd { + template @@ -71197,6 +71709,7 @@ index 00000000000..bb820b5e5ae + T prev, temp; + + if (UseAMCAS) { ++ AMCAS_MACRO + switch (order) { + case memory_order_relaxed: + asm volatile ( @@ -71280,6 +71793,7 @@ index 00000000000..bb820b5e5ae + T prev, temp; + + if (UseAMCAS) { ++ AMCAS_MACRO + switch (order) { + case memory_order_relaxed: + asm volatile ( @@ -71391,7 +71905,7 @@ index 00000000000..bb820b5e5ae +#endif // OS_CPU_LINUX_LOONGARCH_ATOMIC_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/copy_linux_loongarch.inline.hpp b/src/hotspot/os_cpu/linux_loongarch/copy_linux_loongarch.inline.hpp new file mode 100644 -index 00000000000..37587b6bf72 +index 000000000..37587b6bf --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/copy_linux_loongarch.inline.hpp @@ -0,0 +1,145 @@ @@ -71542,7 +72056,7 @@ index 00000000000..37587b6bf72 +#endif // OS_CPU_LINUX_LOONGARCH_COPY_LINUX_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/gc/x/xSyscall_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/gc/x/xSyscall_linux_loongarch.hpp new file mode 100644 -index 00000000000..3ebb1327cd7 +index 000000000..3ebb1327c --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/gc/x/xSyscall_linux_loongarch.hpp @@ -0,0 +1,41 @@ @@ -71589,7 +72103,7 @@ index 00000000000..3ebb1327cd7 +#endif // OS_CPU_LINUX_LOONGARCH_GC_X_XSYSCALL_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/gc/z/zSyscall_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/gc/z/zSyscall_linux_loongarch.hpp new file mode 100644 -index 00000000000..46d5d5a268b +index 000000000..46d5d5a26 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/gc/z/zSyscall_linux_loongarch.hpp @@ -0,0 +1,41 @@ @@ -71636,7 +72150,7 @@ index 00000000000..46d5d5a268b +#endif // OS_CPU_LINUX_LOONGARCH_GC_Z_ZSYSCALL_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/globals_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/globals_linux_loongarch.hpp new file mode 100644 -index 00000000000..0b5247aa0b6 +index 000000000..0b5247aa0 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/globals_linux_loongarch.hpp @@ -0,0 +1,43 @@ @@ -71685,7 +72199,7 @@ index 00000000000..0b5247aa0b6 +#endif // OS_CPU_LINUX_LOONGARCH_GLOBALS_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.cpp b/src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.cpp new file mode 100644 -index 00000000000..76a662afe87 +index 000000000..76a662afe --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.cpp @@ -0,0 +1,105 @@ @@ -71796,7 +72310,7 @@ index 00000000000..76a662afe87 +void JavaThread::cache_global_variables() { } diff --git a/src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.hpp new file mode 100644 -index 00000000000..ea14dd335a5 +index 000000000..ea14dd335 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/javaThread_linux_loongarch.hpp @@ -0,0 +1,66 @@ @@ -71868,7 +72382,7 @@ index 00000000000..ea14dd335a5 +#endif // OS_CPU_LINUX_LOONGARCH_JAVATHREAD_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/linux_loongarch.s b/src/hotspot/os_cpu/linux_loongarch/linux_loongarch.s new file mode 100644 -index 00000000000..ebd73af0c53 +index 000000000..ebd73af0c --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/linux_loongarch.s @@ -0,0 +1,25 @@ @@ -71899,7 +72413,7 @@ index 00000000000..ebd73af0c53 + diff --git a/src/hotspot/os_cpu/linux_loongarch/orderAccess_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/orderAccess_linux_loongarch.hpp new file mode 100644 -index 00000000000..2d096943ae8 +index 000000000..2d096943a --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/orderAccess_linux_loongarch.hpp @@ -0,0 +1,50 @@ @@ -71955,10 +72469,10 @@ index 00000000000..2d096943ae8 +#endif // OS_CPU_LINUX_LOONGARCH_ORDERACCESS_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.cpp b/src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.cpp new file mode 100644 -index 00000000000..31bfcba8db6 +index 000000000..304ceb7b3 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.cpp -@@ -0,0 +1,491 @@ +@@ -0,0 +1,474 @@ +/* + * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Loongson Technology. All rights reserved. @@ -72419,23 +72933,6 @@ index 00000000000..31bfcba8db6 + st->cr(); +} + -+void os::print_tos_pc(outputStream *st, const void *context) { -+ if (context == nullptr) return; -+ -+ const ucontext_t* uc = (const ucontext_t*)context; -+ -+ address sp = (address)os::Linux::ucontext_get_sp(uc); -+ print_tos(st, sp); -+ st->cr(); -+ -+ // Note: it may be unsafe to inspect memory near pc. For example, pc may -+ // point to garbage if entry point in an nmethod is corrupted. Leave -+ // this at the end, and hope for the best. -+ address pc = os::fetch_frame_from_context(uc).pc(); -+ print_instructions(st, pc); -+ st->cr(); -+} -+ +void os::setup_fpu() { + // no use for LA +} @@ -72452,7 +72949,7 @@ index 00000000000..31bfcba8db6 +} diff --git a/src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.inline.hpp b/src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.inline.hpp new file mode 100644 -index 00000000000..43071194ac1 +index 000000000..43071194a --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/os_linux_loongarch.inline.hpp @@ -0,0 +1,29 @@ @@ -72487,7 +72984,7 @@ index 00000000000..43071194ac1 +#endif // OS_CPU_LINUX_LOONGARCH_OS_LINUX_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/prefetch_linux_loongarch.inline.hpp b/src/hotspot/os_cpu/linux_loongarch/prefetch_linux_loongarch.inline.hpp new file mode 100644 -index 00000000000..5fe74ccd97c +index 000000000..5fe74ccd9 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/prefetch_linux_loongarch.inline.hpp @@ -0,0 +1,56 @@ @@ -72549,7 +73046,7 @@ index 00000000000..5fe74ccd97c +#endif // OS_CPU_LINUX_LOONGARCH_PREFETCH_LINUX_LOONGARCH_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/safefetch_linux_loongarch64.S b/src/hotspot/os_cpu/linux_loongarch/safefetch_linux_loongarch64.S new file mode 100644 -index 00000000000..fdc6da358e5 +index 000000000..fdc6da358 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/safefetch_linux_loongarch64.S @@ -0,0 +1,56 @@ @@ -72611,7 +73108,7 @@ index 00000000000..fdc6da358e5 + jr $r1 diff --git a/src/hotspot/os_cpu/linux_loongarch/vmStructs_linux_loongarch.hpp b/src/hotspot/os_cpu/linux_loongarch/vmStructs_linux_loongarch.hpp new file mode 100644 -index 00000000000..a39cb79bb1e +index 000000000..a39cb79bb --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/vmStructs_linux_loongarch.hpp @@ -0,0 +1,55 @@ @@ -72672,7 +73169,7 @@ index 00000000000..a39cb79bb1e +#endif // OS_CPU_LINUX_LOONGARCH_VMSTRUCTS_LINUX_LOONGARCH_HPP diff --git a/src/hotspot/os_cpu/linux_loongarch/vm_version_linux_loongarch.cpp b/src/hotspot/os_cpu/linux_loongarch/vm_version_linux_loongarch.cpp new file mode 100644 -index 00000000000..3711a7036a1 +index 000000000..3711a7036 --- /dev/null +++ b/src/hotspot/os_cpu/linux_loongarch/vm_version_linux_loongarch.cpp @@ -0,0 +1,95 @@ @@ -72772,7 +73269,7 @@ index 00000000000..3711a7036a1 + HWCAP_LOONGARCH_LBT_MIPS); +} diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp -index be4ee3a3acf..9eb3b3a9dc7 100644 +index be4ee3a3a..9eb3b3a9d 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -22,6 +22,12 @@ @@ -72797,7 +73294,7 @@ index be4ee3a3acf..9eb3b3a9dc7 100644 } diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp -index 22299b4051b..573ce8ff7b0 100644 +index 22299b405..573ce8ff7 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -43,6 +43,12 @@ @@ -72823,7 +73320,7 @@ index 22299b4051b..573ce8ff7b0 100644 case vmIntrinsics::_updateDirectByteBufferCRC32C: #endif diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp -index dee208c11be..c147ee8f66a 100644 +index dee208c11..c147ee8f6 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -22,6 +22,12 @@ @@ -72900,7 +73397,7 @@ index dee208c11be..c147ee8f66a 100644 void LIR_OpConvert::print_bytecode(outputStream* out, Bytecodes::Code code) { diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp -index 6f527135fbe..2e2910bdb5c 100644 +index 6f527135f..2e2910bdb 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -22,6 +22,12 @@ @@ -72985,7 +73482,7 @@ index 6f527135fbe..2e2910bdb5c 100644 void call_runtime_leaf(address routine, LIR_Opr tmp, LIR_Opr result, LIR_OprList* arguments) { append(new LIR_OpRTCall(routine, tmp, result, arguments)); diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp -index 0634d970c26..f7797935846 100644 +index 0634d970c..f77979358 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -22,6 +22,12 @@ @@ -73072,7 +73569,7 @@ index 0634d970c26..f7797935846 100644 } } diff --git a/src/hotspot/share/code/vtableStubs.cpp b/src/hotspot/share/code/vtableStubs.cpp -index 934f805eefc..774a81f569b 100644 +index eed3dc8e7..c8b58dd45 100644 --- a/src/hotspot/share/code/vtableStubs.cpp +++ b/src/hotspot/share/code/vtableStubs.cpp @@ -22,6 +22,12 @@ @@ -73088,7 +73585,7 @@ index 934f805eefc..774a81f569b 100644 #include "precompiled.hpp" #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" -@@ -102,7 +108,11 @@ int VtableStubs::_itab_stub_size = 0; +@@ -101,7 +107,11 @@ int VtableStubs::_itab_stub_size = 0; #if defined(PRODUCT) // These values are good for the PRODUCT case (no tracing). @@ -73101,7 +73598,7 @@ index 934f805eefc..774a81f569b 100644 #else // These values are good for the non-PRODUCT case (when tracing can be switched on). diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp -index 28f850938c4..626bfee16a9 100644 +index 28f850938..626bfee16 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -23,6 +23,12 @@ @@ -73139,7 +73636,7 @@ index 28f850938c4..626bfee16a9 100644 if (ParallelGCThreads == 0) { assert(!FLAG_IS_DEFAULT(ParallelGCThreads), "The default value for ParallelGCThreads should not be 0."); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp -index 41553e6bf19..d426a240c7e 100644 +index 41553e6bf..d426a240c 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -22,6 +22,12 @@ @@ -73166,7 +73663,7 @@ index 41553e6bf19..d426a240c7e 100644 } diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp -index 468dc7bdfaf..c331cbf2be6 100644 +index 468dc7bdf..c331cbf2b 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -23,6 +23,12 @@ @@ -73196,7 +73693,7 @@ index 468dc7bdfaf..c331cbf2be6 100644 // of the physical memory, up to a maximum of 1GB. FLAG_SET_DEFAULT(ParallelGCThreads, diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp -index adf0527681b..a1a76917f39 100644 +index adf052768..a1a76917f 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -22,6 +22,12 @@ @@ -73222,7 +73719,7 @@ index adf0527681b..a1a76917f39 100644 // the counter won't overflow. BarrierSetAssembler::clear_patching_epoch(); diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp -index 41bd15ab000..508e37fa2c4 100644 +index 41bd15ab0..508e37fa2 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -22,6 +22,12 @@ @@ -73262,7 +73759,7 @@ index 41bd15ab000..508e37fa2c4 100644 } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp -index 7d31ff02e1a..07dac06aecf 100644 +index 7d31ff02e..07dac06ae 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -22,6 +22,12 @@ @@ -73288,7 +73785,7 @@ index 7d31ff02e1a..07dac06aecf 100644 #endif diff --git a/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp b/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp -index aefec771871..95c0b16d8c6 100644 +index aefec7718..95c0b16d8 100644 --- a/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp +++ b/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp @@ -21,6 +21,12 @@ @@ -73336,7 +73833,7 @@ index aefec771871..95c0b16d8c6 100644 return result; } diff --git a/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp b/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp -index f917a6c3e7b..a851a673f98 100644 +index f917a6c3e..a851a673f 100644 --- a/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp +++ b/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp @@ -21,6 +21,12 @@ @@ -73364,7 +73861,7 @@ index f917a6c3e7b..a851a673f98 100644 ZStoreBarrierEntry _buffer[_buffer_length]; diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp -index ddb6ca32108..0365b9023a0 100644 +index ddb6ca321..0365b9023 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -22,6 +22,12 @@ @@ -73390,7 +73887,7 @@ index ddb6ca32108..0365b9023a0 100644 assert(current == JavaThread::current(), "pre-condition"); if (src_address == dest_address) { diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp -index 97cfcb1eae6..622e49f2f77 100644 +index 97cfcb1ea..622e49f2f 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -22,6 +22,12 @@ @@ -73416,7 +73913,7 @@ index 97cfcb1eae6..622e49f2f77 100644 static void popframe_move_outgoing_args(JavaThread* current, void* src_address, void* dest_address); #endif diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp -index bcccff2fe82..5c836ab5114 100644 +index bcccff2fe..5c836ab51 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp @@ -22,6 +22,12 @@ @@ -73445,7 +73942,7 @@ index bcccff2fe82..5c836ab5114 100644 #ifdef ARM32 void generate_math_runtime_call(AbstractInterpreter::MethodKind kind); diff --git a/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp -index b3a3600deb6..59fd9d3416f 100644 +index b3a3600de..59fd9d341 100644 --- a/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp +++ b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp @@ -22,6 +22,12 @@ @@ -73471,7 +73968,7 @@ index b3a3600deb6..59fd9d3416f 100644 #else #warning "Unconfigured platform" diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp -index a4195a04f18..9394ed12b81 100644 +index a4195a04f..9394ed12b 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -22,6 +22,12 @@ @@ -73506,7 +74003,7 @@ index a4195a04f18..9394ed12b81 100644 #define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp -index f3008084254..5780d3f3ad6 100644 +index f30080842..5780d3f3a 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -23,6 +23,12 @@ @@ -73558,7 +74055,7 @@ index f3008084254..5780d3f3ad6 100644 #endif // _LP64 diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp -index 1d5bb7ffa81..37a41655672 100644 +index eac86b8d0..0c5ecb7c6 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -22,6 +22,12 @@ @@ -73574,7 +74071,7 @@ index 1d5bb7ffa81..37a41655672 100644 #ifndef SHARE_OOPS_STACKCHUNKOOP_INLINE_HPP #define SHARE_OOPS_STACKCHUNKOOP_INLINE_HPP -@@ -335,7 +341,7 @@ inline void stackChunkOopDesc::copy_from_stack_to_chunk(intptr_t* from, intptr_t +@@ -337,7 +343,7 @@ inline void stackChunkOopDesc::copy_from_stack_to_chunk(intptr_t* from, intptr_t assert(to >= start_address(), "Chunk underflow"); assert(to + size <= end_address(), "Chunk overflow"); @@ -73583,7 +74080,7 @@ index 1d5bb7ffa81..37a41655672 100644 // Suppress compilation warning-as-error on unimplemented architectures // that stub out arch-specific methods. Some compilers are smart enough // to figure out the argument is always null and then warn about it. -@@ -354,7 +360,7 @@ inline void stackChunkOopDesc::copy_from_chunk_to_stack(intptr_t* from, intptr_t +@@ -356,7 +362,7 @@ inline void stackChunkOopDesc::copy_from_chunk_to_stack(intptr_t* from, intptr_t assert(from >= start_address(), ""); assert(from + size <= end_address(), ""); @@ -73593,7 +74090,7 @@ index 1d5bb7ffa81..37a41655672 100644 // that stub out arch-specific methods. Some compilers are smart enough // to figure out the argument is always null and then warn about it. diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp -index 892ccc6b8ab..6c1b9affcbe 100644 +index 892ccc6b8..6c1b9affc 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -22,6 +22,12 @@ @@ -73618,7 +74115,7 @@ index 892ccc6b8ab..6c1b9affcbe 100644 macro(MinI) macro(MinL) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp -index c9b82face2d..40005a687f5 100644 +index def117afb..a2fca2de3 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -22,6 +22,12 @@ @@ -73634,7 +74131,7 @@ index c9b82face2d..40005a687f5 100644 #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" -@@ -3755,6 +3761,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f +@@ -3760,6 +3766,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f n->set_req(MemBarNode::Precedent, top()); } break; @@ -73643,7 +74140,7 @@ index c9b82face2d..40005a687f5 100644 if (n->as_MemBar()->trailing_load() && n->req() > MemBarNode::Precedent) { // At parse time, the trailing MemBarAcquire for a volatile load diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp -index 76ed95c4a78..e2fdbedd804 100644 +index d5c02b474..e0c5fa88f 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -22,6 +22,12 @@ @@ -73659,7 +74156,7 @@ index 76ed95c4a78..e2fdbedd804 100644 #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "compiler/compileLog.hpp" -@@ -3281,6 +3287,7 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) { +@@ -3318,6 +3324,7 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) { case Op_MemBarReleaseLock: return new MemBarReleaseLockNode(C, atp, pn); case Op_MemBarVolatile: return new MemBarVolatileNode(C, atp, pn); case Op_MemBarCPUOrder: return new MemBarCPUOrderNode(C, atp, pn); @@ -73668,7 +74165,7 @@ index 76ed95c4a78..e2fdbedd804 100644 case Op_Initialize: return new InitializeNode(C, atp, pn); default: ShouldNotReachHere(); return nullptr; diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp -index e511d64ca6f..23bc631434e 100644 +index f12e08f8f..d231fddd4 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -22,6 +22,12 @@ @@ -73684,7 +74181,7 @@ index e511d64ca6f..23bc631434e 100644 #ifndef SHARE_OPTO_MEMNODE_HPP #define SHARE_OPTO_MEMNODE_HPP -@@ -1289,6 +1295,14 @@ public: +@@ -1293,6 +1299,14 @@ public: virtual uint ideal_reg() const { return 0; } // not matched in the AD file }; @@ -73700,7 +74197,7 @@ index e511d64ca6f..23bc631434e 100644 public: OnSpinWaitNode(Compile* C, int alias_idx, Node* precedent) diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp -index 998be5e1225..c7c8db1dd4e 100644 +index 988e6e42b..3edac67f0 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -22,6 +22,12 @@ @@ -73716,7 +74213,7 @@ index 998be5e1225..c7c8db1dd4e 100644 #include "precompiled.hpp" #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" -@@ -1616,6 +1622,22 @@ void PhaseOutput::fill_buffer(CodeBuffer* cb, uint* blk_starts) { +@@ -1621,6 +1627,22 @@ void PhaseOutput::fill_buffer(CodeBuffer* cb, uint* blk_starts) { DEBUG_ONLY(uint instr_offset = cb->insts_size()); n->emit(*cb, C->regalloc()); current_offset = cb->insts_size(); @@ -73740,7 +74237,7 @@ index 998be5e1225..c7c8db1dd4e 100644 // Above we only verified that there is enough space in the instruction section. // However, the instruction may emit stubs that cause code buffer expansion. diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp -index 720a0e9ba29..6ae1766f7fa 100644 +index 720a0e9ba..6ae1766f7 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -22,6 +22,12 @@ @@ -73774,7 +74271,7 @@ index 720a0e9ba29..6ae1766f7fa 100644 jio_fprintf(defaultStream::error_stream(), "LockingMode == 0 (LM_MONITOR) is not fully implemented on this architecture"); diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp -index 03c0af1a572..7e468def61d 100644 +index 03c0af1a5..7e468def6 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -22,6 +22,12 @@ @@ -73800,7 +74297,7 @@ index 03c0af1a572..7e468def61d 100644 #else frame sender = frame(); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp -index 36ce7a532eb..51125dd80b1 100644 +index 5de00b773..12c076f64 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -22,6 +22,12 @@ @@ -73816,7 +74313,7 @@ index 36ce7a532eb..51125dd80b1 100644 #include "precompiled.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmSymbols.hpp" -@@ -774,7 +780,7 @@ frame FreezeBase::freeze_start_frame_yield_stub(frame f) { +@@ -799,7 +805,7 @@ frame FreezeBase::freeze_start_frame_yield_stub(frame f) { } frame FreezeBase::freeze_start_frame_safepoint_stub(frame f) { @@ -73825,7 +74322,7 @@ index 36ce7a532eb..51125dd80b1 100644 f.set_fp(f.real_fp()); // f.set_fp(*Frame::callee_link_address(f)); // ???? #else Unimplemented(); -@@ -832,7 +838,7 @@ inline freeze_result FreezeBase::recurse_freeze_java_frame(const frame& f, frame +@@ -857,7 +863,7 @@ inline freeze_result FreezeBase::recurse_freeze_java_frame(const frame& f, frame _freeze_size += fsize; NOT_PRODUCT(_frames++;) @@ -73834,7 +74331,7 @@ index 36ce7a532eb..51125dd80b1 100644 // We don't use FKind::frame_bottom(f) == _bottom_address because on x64 there's sometimes an extra word between // enterSpecial and an interpreted frame -@@ -1604,7 +1610,7 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi +@@ -1630,7 +1636,7 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi if (!safepoint) { f = f.sender(&map); // this is the yield frame } else { // safepoint yield @@ -73843,7 +74340,7 @@ index 36ce7a532eb..51125dd80b1 100644 f.set_fp(f.real_fp()); // Instead of this, maybe in ContinuationWrapper::set_last_frame always use the real_fp? #else Unimplemented(); -@@ -2224,8 +2230,8 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n +@@ -2269,8 +2275,8 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n // If we're the bottom-most thawed frame, we're writing to within one word from entrySP // (we might have one padding word for alignment) @@ -73855,7 +74352,7 @@ index 36ce7a532eb..51125dd80b1 100644 copy_from_chunk(from, to, sz); // copying good oops because we invoked barriers above diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp -index 7b1ad7e17e1..c7a0246e375 100644 +index 7b1ad7e17..c7a0246e3 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -23,6 +23,12 @@ @@ -73890,7 +74387,7 @@ index 7b1ad7e17e1..c7a0246e375 100644 // Threads::create_vm() for size checks. Atomic::release_store(&_thread_state, s); diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp -index c8952cf8af3..f2e7fb05d69 100644 +index ee0f754b8..e29e71641 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -22,6 +22,12 @@ @@ -73916,7 +74413,7 @@ index c8952cf8af3..f2e7fb05d69 100644 assert(_succ != current, "invariant"); assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); assert(current->thread_state() != _thread_blocked, "invariant"); -@@ -717,6 +726,7 @@ void ObjectMonitor::EnterI(JavaThread* current) { +@@ -707,6 +716,7 @@ void ObjectMonitor::EnterI(JavaThread* current) { } // The Spin failed -- Enqueue and park the thread ... @@ -73925,7 +74422,7 @@ index c8952cf8af3..f2e7fb05d69 100644 assert(owner_raw() != current, "invariant"); assert(_Responsible != current, "invariant"); diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp -index a5ea07d8c64..8adb584b769 100644 +index 286a148ac..17c94339a 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -22,6 +22,12 @@ @@ -73941,7 +74438,7 @@ index a5ea07d8c64..8adb584b769 100644 #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/moduleEntry.hpp" -@@ -1259,7 +1265,8 @@ bool os::is_first_C_frame(frame* fr) { +@@ -1331,7 +1337,8 @@ bool os::is_first_C_frame(frame* fr) { if ((uintptr_t)fr->sender_sp() == (uintptr_t)-1 || is_pointer_bad(fr->sender_sp())) return true; uintptr_t old_fp = (uintptr_t)fr->link_or_null(); @@ -73952,7 +74449,7 @@ index a5ea07d8c64..8adb584b769 100644 // stack grows downwards; if old_fp is below current fp or if the stack diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp -index edbdad4f24b..404d9113f48 100644 +index f8713f5bb..6e75e8f21 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -22,6 +22,12 @@ @@ -73978,7 +74475,7 @@ index edbdad4f24b..404d9113f48 100644 // in the constant pool to ensure ordering between the barrier and oops // accesses. For native_wrappers we need a constant. diff --git a/src/hotspot/share/runtime/sharedRuntimeTrig.cpp b/src/hotspot/share/runtime/sharedRuntimeTrig.cpp -index fac76262f3c..f41cf843d31 100644 +index fac76262f..f41cf843d 100644 --- a/src/hotspot/share/runtime/sharedRuntimeTrig.cpp +++ b/src/hotspot/share/runtime/sharedRuntimeTrig.cpp @@ -22,6 +22,13 @@ @@ -74019,7 +74516,7 @@ index fac76262f3c..f41cf843d31 100644 static double __kernel_sin(double x, double y, int iy) { diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp -index 6e6f2115e1e..fdd94b21883 100644 +index b5859ed27..312b68baf 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -22,6 +22,12 @@ @@ -74035,7 +74532,7 @@ index 6e6f2115e1e..fdd94b21883 100644 #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" #include "gc/shared/collectedHeap.hpp" -@@ -487,7 +493,7 @@ void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread +@@ -486,7 +492,7 @@ void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread } static bool useHeavyMonitors() { @@ -74045,7 +74542,7 @@ index 6e6f2115e1e..fdd94b21883 100644 #else return false; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp -index 37241534b2b..f7302bea5f7 100644 +index 827cb0cdf..0c1bc9041 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -22,6 +22,12 @@ @@ -74070,7 +74567,7 @@ index 37241534b2b..f7302bea5f7 100644 declare_c2_type(BlackholeNode, MultiNode) \ declare_c2_type(InitializeNode, MemBarNode) \ diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp -index bfbaaa58acc..74e56975081 100644 +index 244b18ecd..cdb392b5e 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -22,6 +22,12 @@ @@ -74106,7 +74603,7 @@ index bfbaaa58acc..74e56975081 100644 #ifndef PPC #define PPC diff --git a/src/java.base/share/classes/jdk/internal/foreign/CABI.java b/src/java.base/share/classes/jdk/internal/foreign/CABI.java -index d376a196333..5ceb511ec90 100644 +index d376a1963..5ceb511ec 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/CABI.java +++ b/src/java.base/share/classes/jdk/internal/foreign/CABI.java @@ -23,6 +23,12 @@ @@ -74144,7 +74641,7 @@ index d376a196333..5ceb511ec90 100644 return FALLBACK; // fallback linker } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java -index 8a322cdcf7a..4ab3845d35e 100644 +index 8a322cdcf..4ab3845d3 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java @@ -22,6 +22,12 @@ @@ -74177,7 +74674,7 @@ index 8a322cdcf7a..4ab3845d35e 100644 public interface UpcallStubFactory { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java -index 92d10a1dbdf..40cc94cda13 100644 +index 92d10a1db..40cc94cda 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -22,6 +22,12 @@ @@ -74211,7 +74708,7 @@ index 92d10a1dbdf..40cc94cda13 100644 }; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/LoongArch64Architecture.java b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/LoongArch64Architecture.java new file mode 100644 -index 00000000000..aec9e531708 +index 000000000..aec9e5317 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/LoongArch64Architecture.java @@ -0,0 +1,179 @@ @@ -74396,7 +74893,7 @@ index 00000000000..aec9e531708 +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64CallArranger.java new file mode 100644 -index 00000000000..97e84a28b64 +index 000000000..97e84a28b --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64CallArranger.java @@ -0,0 +1,472 @@ @@ -74874,7 +75371,7 @@ index 00000000000..97e84a28b64 +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64Linker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64Linker.java new file mode 100644 -index 00000000000..c231a91b1bb +index 000000000..c231a91b1 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/LinuxLoongArch64Linker.java @@ -0,0 +1,65 @@ @@ -74945,7 +75442,7 @@ index 00000000000..c231a91b1bb +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/TypeClass.java b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/TypeClass.java new file mode 100644 -index 00000000000..117eb529434 +index 000000000..117eb5294 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/loongarch64/linux/TypeClass.java @@ -0,0 +1,217 @@ @@ -75167,7 +75664,7 @@ index 00000000000..117eb529434 + } +} diff --git a/src/java.base/share/classes/jdk/internal/util/Architecture.java b/src/java.base/share/classes/jdk/internal/util/Architecture.java -index 5c861902743..f48d3a63204 100644 +index 5c8619027..f48d3a632 100644 --- a/src/java.base/share/classes/jdk/internal/util/Architecture.java +++ b/src/java.base/share/classes/jdk/internal/util/Architecture.java @@ -22,6 +22,14 @@ @@ -75186,7 +75683,7 @@ index 5c861902743..f48d3a63204 100644 import jdk.internal.vm.annotation.ForceInline; diff --git a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template -index 9c2a2c84511..c0720ad7b9d 100644 +index 9c2a2c845..c0720ad7b 100644 --- a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template +++ b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template @@ -22,6 +22,14 @@ @@ -75205,7 +75702,7 @@ index 9c2a2c84511..c0720ad7b9d 100644 /** diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp -index bebf8d0f05a..44d2a6342a1 100644 +index d2cfbf8e7..726170bd3 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp @@ -23,6 +23,13 @@ @@ -75242,7 +75739,7 @@ index bebf8d0f05a..44d2a6342a1 100644 extern "C" JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { -@@ -443,6 +454,9 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo +@@ -442,6 +453,9 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo #ifdef aarch64 #define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG #endif @@ -75252,7 +75749,7 @@ index bebf8d0f05a..44d2a6342a1 100644 #ifdef riscv64 #define NPRGREG sun_jvm_hotspot_debugger_riscv64_RISCV64ThreadContext_NPRGREG #endif -@@ -522,6 +536,18 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo +@@ -521,6 +535,18 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo } #endif /* aarch64 */ @@ -75272,7 +75769,7 @@ index bebf8d0f05a..44d2a6342a1 100644 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_riscv64_RISCV64ThreadContext_##reg diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h -index a69496e77a4..d2e77252769 100644 +index a69496e77..d2e772527 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h @@ -22,6 +22,13 @@ @@ -75299,7 +75796,7 @@ index a69496e77a4..d2e77252769 100644 #define user_regs_struct user_pt_regs #elif defined(arm) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c -index 3068f475626..d35cc73221f 100644 +index 3068f4756..d35cc7322 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c @@ -22,6 +22,12 @@ @@ -75325,7 +75822,7 @@ index 3068f475626..d35cc73221f 100644 print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp(%d) errno(%d) \"%s\"\n", pid, errno, strerror(errno)); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java -index 71ed978199c..194088c697a 100644 +index 71ed97819..194088c69 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java @@ -23,6 +23,12 @@ @@ -75360,7 +75857,7 @@ index 71ed978199c..194088c697a 100644 machDesc = (MachineDescription) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionLOONGARCH64.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionLOONGARCH64.java new file mode 100644 -index 00000000000..99cea8c7f14 +index 000000000..99cea8c7f --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionLOONGARCH64.java @@ -0,0 +1,41 @@ @@ -75406,7 +75903,7 @@ index 00000000000..99cea8c7f14 + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java -index c100c160947..0b87e7922e7 100644 +index c100c1609..0b87e7922 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -23,6 +23,12 @@ @@ -75454,7 +75951,7 @@ index c100c160947..0b87e7922e7 100644 Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); if (sp == null) return null; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java -index 69a34fe2afa..da07fe91258 100644 +index 69a34fe2a..da07fe912 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java @@ -22,6 +22,12 @@ @@ -75491,7 +75988,7 @@ index 69a34fe2afa..da07fe91258 100644 try { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64CFrame.java new file mode 100644 -index 00000000000..0e6caee5a49 +index 000000000..0e6caee5a --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64CFrame.java @@ -0,0 +1,92 @@ @@ -75589,7 +76086,7 @@ index 00000000000..0e6caee5a49 +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64ThreadContext.java new file mode 100644 -index 00000000000..604642598e0 +index 000000000..604642598 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/loongarch64/LinuxLOONGARCH64ThreadContext.java @@ -0,0 +1,47 @@ @@ -75642,7 +76139,7 @@ index 00000000000..604642598e0 +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/loongarch64/LOONGARCH64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/loongarch64/LOONGARCH64ThreadContext.java new file mode 100644 -index 00000000000..1de3cb1a472 +index 000000000..1de3cb1a4 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/loongarch64/LOONGARCH64ThreadContext.java @@ -0,0 +1,128 @@ @@ -75775,7 +76272,7 @@ index 00000000000..1de3cb1a472 + public abstract Address getRegisterAsAddress(int index); +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java -index 7113a3a497b..de47531db7c 100644 +index 7113a3a49..de47531db 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java @@ -22,6 +22,12 @@ @@ -75801,7 +76298,7 @@ index 7113a3a497b..de47531db7c 100644 /** Returns a file type which is defined by the file type constants. */ public short getFileType(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java -index d4a7c17dc85..1b3e5d5e971 100644 +index d4a7c17dc..1b3e5d5e9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java @@ -22,6 +22,12 @@ @@ -75838,7 +76335,7 @@ index d4a7c17dc85..1b3e5d5e971 100644 Class tf = Class.forName("sun.jvm.hotspot.debugger.remote." + diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64Thread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64Thread.java new file mode 100644 -index 00000000000..242dd279e1a +index 000000000..242dd279e --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64Thread.java @@ -0,0 +1,54 @@ @@ -75898,7 +76395,7 @@ index 00000000000..242dd279e1a +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadContext.java new file mode 100644 -index 00000000000..634d5ad049f +index 000000000..634d5ad04 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadContext.java @@ -0,0 +1,51 @@ @@ -75955,7 +76452,7 @@ index 00000000000..634d5ad049f +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadFactory.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadFactory.java new file mode 100644 -index 00000000000..4fb9cc7c069 +index 000000000..4fb9cc7c0 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/loongarch64/RemoteLOONGARCH64ThreadFactory.java @@ -0,0 +1,45 @@ @@ -76005,7 +76502,7 @@ index 00000000000..4fb9cc7c069 + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java -index a6f5da88ad4..2a220f9fd8b 100644 +index a6f5da88a..2a220f9fd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -22,6 +22,12 @@ @@ -76040,7 +76537,7 @@ index a6f5da88ad4..2a220f9fd8b 100644 access = (JavaThreadPDAccess) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_loongarch64/LinuxLOONGARCH64JavaThreadPDAccess.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_loongarch64/LinuxLOONGARCH64JavaThreadPDAccess.java new file mode 100644 -index 00000000000..b92c8eca74b +index 000000000..b92c8eca7 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_loongarch64/LinuxLOONGARCH64JavaThreadPDAccess.java @@ -0,0 +1,139 @@ @@ -76185,7 +76682,7 @@ index 00000000000..b92c8eca74b +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64CurrentFrameGuess.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64CurrentFrameGuess.java new file mode 100644 -index 00000000000..824270e1329 +index 000000000..824270e13 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64CurrentFrameGuess.java @@ -0,0 +1,250 @@ @@ -76441,7 +76938,7 @@ index 00000000000..824270e1329 +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64Frame.java new file mode 100644 -index 00000000000..9470781c48e +index 000000000..9470781c4 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64Frame.java @@ -0,0 +1,540 @@ @@ -76987,7 +77484,7 @@ index 00000000000..9470781c48e +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64JavaCallWrapper.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64JavaCallWrapper.java new file mode 100644 -index 00000000000..0ad9573a42d +index 000000000..0ad9573a4 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64JavaCallWrapper.java @@ -0,0 +1,59 @@ @@ -77052,7 +77549,7 @@ index 00000000000..0ad9573a42d +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64RegisterMap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64RegisterMap.java new file mode 100644 -index 00000000000..2cf904d3885 +index 000000000..2cf904d38 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/loongarch64/LOONGARCH64RegisterMap.java @@ -0,0 +1,52 @@ @@ -77109,7 +77606,7 @@ index 00000000000..2cf904d3885 + protected Address getLocationPD(VMReg reg) { return null; } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java -index f4cd4873207..622ddb7349e 100644 +index f4cd48732..622ddb734 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java @@ -22,6 +22,13 @@ @@ -77147,7 +77644,7 @@ index f4cd4873207..622ddb7349e 100644 } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotJVMCIBackendFactory.java new file mode 100644 -index 00000000000..1f54e9f3c59 +index 000000000..1f54e9f3c --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotJVMCIBackendFactory.java @@ -0,0 +1,142 @@ @@ -77295,7 +77792,7 @@ index 00000000000..1f54e9f3c59 +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotRegisterConfig.java new file mode 100644 -index 00000000000..e1a007000d2 +index 000000000..e1a007000 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotRegisterConfig.java @@ -0,0 +1,297 @@ @@ -77598,7 +78095,7 @@ index 00000000000..e1a007000d2 +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotVMConfig.java new file mode 100644 -index 00000000000..67173ecab48 +index 000000000..67173ecab --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/LoongArch64HotSpotVMConfig.java @@ -0,0 +1,79 @@ @@ -77683,7 +78180,7 @@ index 00000000000..67173ecab48 +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/package-info.java new file mode 100644 -index 00000000000..74c6ca9801f +index 000000000..74c6ca980 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/loongarch64/package-info.java @@ -0,0 +1,28 @@ @@ -77717,7 +78214,7 @@ index 00000000000..74c6ca9801f +package jdk.vm.ci.hotspot.loongarch64; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64.java new file mode 100644 -index 00000000000..c178ec21529 +index 000000000..c178ec215 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64.java @@ -0,0 +1,251 @@ @@ -77974,7 +78471,7 @@ index 00000000000..c178ec21529 +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64Kind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64Kind.java new file mode 100644 -index 00000000000..047a1dbbe36 +index 000000000..047a1dbbe --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/LoongArch64Kind.java @@ -0,0 +1,163 @@ @@ -78143,7 +78640,7 @@ index 00000000000..047a1dbbe36 +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/package-info.java new file mode 100644 -index 00000000000..6df1b7b3a92 +index 000000000..6df1b7b3a --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/loongarch64/package-info.java @@ -0,0 +1,28 @@ @@ -78176,7 +78673,7 @@ index 00000000000..6df1b7b3a92 + */ +package jdk.vm.ci.loongarch64; diff --git a/src/jdk.internal.vm.ci/share/classes/module-info.java b/src/jdk.internal.vm.ci/share/classes/module-info.java -index b4b93f6a747..68fa668e1bc 100644 +index b4b93f6a7..68fa668e1 100644 --- a/src/jdk.internal.vm.ci/share/classes/module-info.java +++ b/src/jdk.internal.vm.ci/share/classes/module-info.java @@ -23,6 +23,12 @@ @@ -78200,7 +78697,7 @@ index b4b93f6a747..68fa668e1bc 100644 jdk.vm.ci.hotspot.riscv64.RISCV64HotSpotJVMCIBackendFactory; } diff --git a/src/utils/hsdis/binutils/hsdis-binutils.c b/src/utils/hsdis/binutils/hsdis-binutils.c -index 279ed53ba5d..3281346aa23 100644 +index 279ed53ba..3281346aa 100644 --- a/src/utils/hsdis/binutils/hsdis-binutils.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -44,6 +44,12 @@ @@ -78227,7 +78724,7 @@ index 279ed53ba5d..3281346aa23 100644 if (res == NULL) res = "architecture not set in Makefile!"; diff --git a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java -index 465999eac7f..ba9629d5e77 100644 +index 465999eac..ba9629d5e 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java @@ -22,12 +22,18 @@ @@ -78251,7 +78748,7 @@ index 465999eac7f..ba9629d5e77 100644 * @summary Test large CodeEntryAlignments are accepted * @run driver compiler.arguments.TestCodeEntryAlignment diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java -index 55dfb0460a2..5f36747a394 100644 +index 55dfb0460..5f36747a3 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java @@ -21,6 +21,12 @@ @@ -78283,7 +78780,7 @@ index 55dfb0460a2..5f36747a394 100644 // Generic config. configs.add(new ArrayList()); diff --git a/test/hotspot/jtreg/compiler/c2/TestBit.java b/test/hotspot/jtreg/compiler/c2/TestBit.java -index a3c9421a3f9..aa02e31f712 100644 +index a3c9421a3..aa02e31f7 100644 --- a/test/hotspot/jtreg/compiler/c2/TestBit.java +++ b/test/hotspot/jtreg/compiler/c2/TestBit.java @@ -21,6 +21,12 @@ @@ -78309,7 +78806,7 @@ index a3c9421a3f9..aa02e31f712 100644 * * @run driver compiler.c2.TestBit diff --git a/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java b/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java -index f5b37f229d0..a0eddb2ef1f 100644 +index f5b37f229..a0eddb2ef 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java @@ -21,6 +21,12 @@ @@ -78335,7 +78832,7 @@ index f5b37f229d0..a0eddb2ef1f 100644 * @requires vm.compiler2.enabled * @run driver compiler.c2.irTests.CmpUWithZero diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVecCountingDownLoop.java b/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVecCountingDownLoop.java -index 994ec1e9cc0..5669a094212 100644 +index 994ec1e9c..5669a0942 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVecCountingDownLoop.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVecCountingDownLoop.java @@ -21,6 +21,12 @@ @@ -78361,7 +78858,7 @@ index 994ec1e9cc0..5669a094212 100644 * @run driver compiler.c2.irTests.TestAutoVecCountingDownLoop */ diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java -index 8ba786d6f20..da9106bf92e 100644 +index 8ba786d6f..da9106bf9 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java @@ -21,6 +21,12 @@ @@ -78387,7 +78884,7 @@ index 8ba786d6f20..da9106bf92e 100644 * @run driver compiler.c2.irTests.TestIRAbs */ diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationNotRun.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationNotRun.java -index 5968b7221c7..6bcdf4d189d 100644 +index 5968b7221..6bcdf4d18 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationNotRun.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationNotRun.java @@ -21,6 +21,12 @@ @@ -78413,7 +78910,7 @@ index 5968b7221c7..6bcdf4d189d 100644 * @library /test/lib / * @run driver compiler.c2.irTests.TestVectorizationNotRun diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java -index 67c26ecbddf..ba69c910ce6 100644 +index 899be4bbc..3aefead5d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java @@ -21,6 +21,12 @@ @@ -78439,7 +78936,7 @@ index 67c26ecbddf..ba69c910ce6 100644 * @run driver compiler.c2.irTests.TestVectorizeTypeConversion */ diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java -index ebe3fe63ccf..04ea3cccdef 100644 +index ebe3fe63c..04ea3cccd 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java @@ -22,6 +22,12 @@ @@ -78465,7 +78962,7 @@ index ebe3fe63ccf..04ea3cccdef 100644 * @run driver compiler.c2.irTests.TestVectorizeURShiftSubword */ diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java -index 4c56daebfb8..92836130408 100644 +index ac3a6d9a8..c17598902 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -21,12 +21,18 @@ @@ -78489,7 +78986,7 @@ index 4c56daebfb8..92836130408 100644 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java -index 03016ea3dd6..62ce6c1a7a5 100644 +index fdc8f63f9..993cf68d0 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -21,6 +21,12 @@ @@ -78514,35 +79011,8 @@ index 03016ea3dd6..62ce6c1a7a5 100644 * @requires vm.compiler1.enabled | !vm.graal.enabled * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java b/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java -index 46469777771..9be18a981ff 100644 ---- a/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java -+++ b/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java -@@ -21,6 +21,12 @@ - * questions. - */ - -+/* -+ * This file has been modified by Loongson Technology in 2023, These -+ * modifications are Copyright (c) 2023, Loongson Technology, and are made -+ * available on the same license terms set forth above. -+ */ -+ - /** - * @test - * @bug 8283894 -@@ -31,7 +37,8 @@ - * (vm.cpu.features ~= ".*bmi2.*" & vm.cpu.features ~= ".*bmi1.*" & - * vm.cpu.features ~= ".*sse2.*")) | - * ((vm.opt.UseSVE == "null" | vm.opt.UseSVE > 1) & -- * os.arch=="aarch64" & vm.cpu.features ~= ".*svebitperm.*")) -+ * os.arch=="aarch64" & vm.cpu.features ~= ".*svebitperm.*") | -+ * os.arch=="loongarch64") - * @library /test/lib / - * @run driver compiler.intrinsics.TestBitShuffleOpers - */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestCompareUnsigned.java b/test/hotspot/jtreg/compiler/intrinsics/TestCompareUnsigned.java -index 6d1943ca145..1d80230aa42 100644 +index 6d1943ca1..1d80230aa 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestCompareUnsigned.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestCompareUnsigned.java @@ -20,6 +20,13 @@ @@ -78569,7 +79039,7 @@ index 6d1943ca145..1d80230aa42 100644 * @library /test/lib / * @run driver compiler.intrinsics.TestCompareUnsigned diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsFinite.java b/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsFinite.java -index ab06e07a482..a6ca357dc92 100644 +index ab06e07a4..a6ca357dc 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsFinite.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsFinite.java @@ -22,10 +22,16 @@ @@ -78591,7 +79061,7 @@ index ab06e07a482..a6ca357dc92 100644 * @run driver compiler.intrinsics.TestDoubleIsFinite */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsInfinite.java b/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsInfinite.java -index b35b6cda3d2..630566360ac 100644 +index b35b6cda3..630566360 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsInfinite.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestDoubleIsInfinite.java @@ -22,10 +22,16 @@ @@ -78613,7 +79083,7 @@ index b35b6cda3d2..630566360ac 100644 * @run driver compiler.intrinsics.TestDoubleIsInfinite */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsFinite.java b/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsFinite.java -index 7fb0bebc516..e61f2febfcf 100644 +index 7fb0bebc5..e61f2febf 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsFinite.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsFinite.java @@ -22,10 +22,16 @@ @@ -78635,7 +79105,7 @@ index 7fb0bebc516..e61f2febfcf 100644 * @run driver compiler.intrinsics.TestFloatIsFinite */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsInfinite.java b/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsInfinite.java -index 54fa7657851..ec35129aae8 100644 +index 54fa76578..ec35129aa 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsInfinite.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestFloatIsInfinite.java @@ -22,10 +22,16 @@ @@ -78657,7 +79127,7 @@ index 54fa7657851..ec35129aae8 100644 * @run driver compiler.intrinsics.TestFloatIsInfinite */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestIntegerUnsignedDivMod.java b/test/hotspot/jtreg/compiler/intrinsics/TestIntegerUnsignedDivMod.java -index 1b214c32391..5f997a72c4a 100644 +index 9c82f5e75..69c92192e 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestIntegerUnsignedDivMod.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestIntegerUnsignedDivMod.java @@ -21,10 +21,16 @@ @@ -78672,14 +79142,14 @@ index 1b214c32391..5f997a72c4a 100644 + /** * @test - * @summary Test x86_64 intrinsic for divideUnsigned() and remainderUnsigned() methods for Integer --* @requires os.arch=="amd64" | os.arch=="x86_64" -+* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="loongarch64" + * @summary Test intrinsic for divideUnsigned() and remainderUnsigned() methods for Integer +-* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" ++* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="loongarch64" * @library /test/lib / * @run driver compiler.intrinsics.TestIntegerUnsignedDivMod */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java b/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java -index ee9c6499902..32b1d54a3e3 100644 +index 694860a2d..b2021b0b1 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java @@ -21,10 +21,16 @@ @@ -78694,14 +79164,14 @@ index ee9c6499902..32b1d54a3e3 100644 + /** * @test - * @summary Test x86_64 intrinsic for divideUnsigned() and remainderUnsigned() methods for Long --* @requires os.arch=="amd64" | os.arch=="x86_64" -+* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="loongarch64" + * @summary Test intrinsic for divideUnsigned() and remainderUnsigned() methods for Long +-* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" ++* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="loongarch64" * @library /test/lib / * @run driver compiler.intrinsics.TestLongUnsignedDivMod */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/chacha/TestChaCha20.java b/test/hotspot/jtreg/compiler/intrinsics/chacha/TestChaCha20.java -index c2275f6563e..b94e05fc1ff 100644 +index c2275f656..b94e05fc1 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/chacha/TestChaCha20.java +++ b/test/hotspot/jtreg/compiler/intrinsics/chacha/TestChaCha20.java @@ -22,6 +22,12 @@ @@ -78731,7 +79201,7 @@ index c2275f6563e..b94e05fc1ff 100644 // We only have ChaCha20 intrinsics on x64 and aarch64 // currently. If the platform is neither of these then diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java -index eeba614de4f..5a2f293e259 100644 +index 0541121c1..d9fe8c91d 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java @@ -21,11 +21,17 @@ @@ -78754,7 +79224,7 @@ index eeba614de4f..5a2f293e259 100644 * @requires vm.compMode != "Xcomp" * @comment default run diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java -index 38060dfb504..151caa94346 100644 +index 38060dfb5..151caa943 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java @@ -21,11 +21,17 @@ @@ -78777,7 +79247,7 @@ index 38060dfb504..151caa94346 100644 * @requires vm.compMode != "Xcomp" * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java -index 4afda120709..230aef2fb58 100644 +index 492901f00..e95554fa9 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java @@ -21,11 +21,17 @@ @@ -78800,7 +79270,7 @@ index 4afda120709..230aef2fb58 100644 * @requires vm.compMode != "Xcomp" * @comment default run: diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java -index 062e6804897..42a9d239e06 100644 +index b4ba578c9..27e6b86ab 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java @@ -21,11 +21,17 @@ @@ -78823,7 +79293,7 @@ index 062e6804897..42a9d239e06 100644 * @requires vm.compMode != "Xcomp" * @comment default run: diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java -index 468cd83d7a2..40d2b03e301 100644 +index 468cd83d7..40d2b03e3 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java @@ -21,6 +21,12 @@ @@ -78867,7 +79337,7 @@ index 468cd83d7a2..40d2b03e301 100644 this.checkUseSHA = checkUseSHA; } diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java -index afc308c37dd..5b949dfa19a 100644 +index afc308c37..5b949dfa1 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java @@ -21,13 +21,21 @@ @@ -78903,7 +79373,7 @@ index afc308c37dd..5b949dfa19a 100644 // but only if we're not expecting the full length (no // negative bytes) diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java -index 26bc03c271b..606f0d4f17d 100644 +index 26bc03c27..606f0d4f1 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java @@ -22,9 +22,15 @@ @@ -78924,7 +79394,7 @@ index 26bc03c271b..606f0d4f17d 100644 * different string length. This test creates string with specified * size and longer string, which is same at beginning. diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java -index 7483c45a654..68c280f1f39 100644 +index 7483c45a6..68c280f1f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java @@ -20,10 +20,18 @@ @@ -78964,7 +79434,7 @@ index 7483c45a654..68c280f1f39 100644 Assert.fail("unsupported architecture"); return null; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java -index adbad3e0b4d..e1ce622af2b 100644 +index adbad3e0b..e1ce622af 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java @@ -21,10 +21,16 @@ @@ -78998,7 +79468,7 @@ index adbad3e0b4d..e1ce622af2b 100644 */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java -index 879e6f86058..fcf7c058232 100644 +index 879e6f860..fcf7c0582 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java @@ -21,10 +21,16 @@ @@ -79032,7 +79502,7 @@ index 879e6f86058..fcf7c058232 100644 */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java -index 3d49a4f3575..8a0427d3da2 100644 +index 3d49a4f35..8a0427d3d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java @@ -21,10 +21,16 @@ @@ -79066,7 +79536,7 @@ index 3d49a4f3575..8a0427d3da2 100644 */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java -index ebd57b6faaf..ed15dff3a5e 100644 +index ebd57b6fa..ed15dff3a 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java @@ -21,10 +21,16 @@ @@ -79100,7 +79570,7 @@ index ebd57b6faaf..ed15dff3a5e 100644 */ package jdk.vm.ci.code.test; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java -index 80c63392b6e..f667c799773 100644 +index 80c63392b..f667c7997 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java @@ -21,10 +21,16 @@ @@ -79134,7 +79604,7 @@ index 80c63392b6e..f667c799773 100644 */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java -index c7d8d2cf830..6c4b6506ee5 100644 +index c7d8d2cf8..6c4b6506e 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java @@ -21,10 +21,16 @@ @@ -79168,7 +79638,7 @@ index c7d8d2cf830..6c4b6506ee5 100644 */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java -index 543128e932c..4aa99f24060 100644 +index 543128e93..4aa99f240 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java @@ -21,10 +21,16 @@ @@ -79203,7 +79673,7 @@ index 543128e932c..4aa99f24060 100644 diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/loongarch64/LoongArch64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/loongarch64/LoongArch64TestAssembler.java new file mode 100644 -index 00000000000..4c76868453a +index 000000000..4c7686845 --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/loongarch64/LoongArch64TestAssembler.java @@ -0,0 +1,568 @@ @@ -79776,7 +80246,7 @@ index 00000000000..4c76868453a + +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java -index a555249637b..85cb1cb639b 100644 +index 8eb1af01d..151c422f9 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -21,6 +21,12 @@ @@ -79809,7 +80279,7 @@ index a555249637b..85cb1cb639b 100644 } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java -index b1495d00548..61a9eacdf48 100644 +index b1495d005..61a9eacdf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java @@ -21,12 +21,18 @@ @@ -79833,10 +80303,10 @@ index b1495d00548..61a9eacdf48 100644 * @run main/othervm -Xbatch -XX:LoopUnrollLimit=250 * -XX:CompileCommand=exclude,compiler.loopopts.superword.ReductionPerf::main diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java -index 390a0dcdd3f..d7baa9bfb75 100644 +index e8759a2be..0a22efb68 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java -@@ -21,12 +21,18 @@ +@@ -21,13 +21,19 @@ * questions. */ @@ -79851,13 +80321,14 @@ index 390a0dcdd3f..d7baa9bfb75 100644 * @bug 8289996 * @summary Test range check hoisting for some scaled iv at array index * @library /test/lib / + * @requires vm.flagless - * @requires vm.debug & vm.compiler2.enabled & (os.simpleArch == "x64" | os.arch == "aarch64") + * @requires vm.debug & vm.compiler2.enabled & (os.simpleArch == "x64" | os.arch == "aarch64" | os.arch == "loongarch64") * @modules jdk.incubator.vector * @compile --enable-preview -source ${jdk.version} TestRangeCheckHoistingScaledIV.java * @run main/othervm --enable-preview compiler.rangechecks.TestRangeCheckHoistingScaledIV diff --git a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java -index df221959bb5..a15ac48e3fa 100644 +index 3daf12df8..31018941a 100644 --- a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java +++ b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java @@ -21,6 +21,12 @@ @@ -79910,7 +80381,7 @@ index df221959bb5..a15ac48e3fa 100644 .shouldMatch("Test_CD2.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_CD3.*::test \\(3 bytes\\) made not entrant") diff --git a/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java b/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java -index 682198672f7..c62956d467f 100644 +index 5dd938442..2ec4cab8f 100644 --- a/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java +++ b/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java @@ -22,6 +22,12 @@ @@ -79936,7 +80407,7 @@ index 682198672f7..c62956d467f 100644 * @run driver compiler.sharedstubs.SharedStubToInterpTest -XX:-TieredCompilation * diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java -index 689c7c8cc2f..f734c1baa3f 100644 +index 689c7c8cc..f734c1baa 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -21,6 +21,12 @@ @@ -79994,7 +80465,7 @@ index 689c7c8cc2f..f734c1baa3f 100644 public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha512" }, null), diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java -index 35f357c22f2..e0643272e83 100644 +index 35f357c22..e0643272e 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java @@ -20,6 +20,13 @@ @@ -80021,7 +80492,7 @@ index 35f357c22f2..e0643272e83 100644 */ public class TestVectorTest { diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java -index b0037973ad1..3ed2735c525 100644 +index 426dec670..ea25a81a3 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java @@ -22,6 +22,12 @@ @@ -80047,7 +80518,7 @@ index b0037973ad1..3ed2735c525 100644 * * @run driver compiler.vectorapi.VectorLogicalOpIdentityTest diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorReverseBytesTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorReverseBytesTest.java -index 154567922bd..d81a90f2fcb 100644 +index 154567922..d81a90f2f 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorReverseBytesTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorReverseBytesTest.java @@ -21,6 +21,12 @@ @@ -80073,7 +80544,7 @@ index 154567922bd..d81a90f2fcb 100644 * * @run driver compiler.vectorapi.VectorReverseBytesTest diff --git a/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java b/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java -index e3baed37804..18b9333b1d1 100644 +index e3baed378..18b9333b1 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java @@ -21,6 +21,12 @@ @@ -80099,7 +80570,7 @@ index e3baed37804..18b9333b1d1 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java b/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java -index 95970256c48..3fcb0c999cb 100644 +index 95970256c..3fcb0c999 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java @@ -21,6 +21,12 @@ @@ -80125,7 +80596,7 @@ index 95970256c48..3fcb0c999cb 100644 * @run driver compiler.vectorization.TestBufferVectorization array * @run driver compiler.vectorization.TestBufferVectorization arrayOffset diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java -index 4452e576867..7fc996888cd 100644 +index 4452e5768..7fc996888 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java @@ -21,12 +21,18 @@ @@ -80148,34 +80619,8 @@ index 4452e576867..7fc996888cd 100644 * @library /test/lib / * @run driver compiler.vectorization.TestFloatConversionsVector */ -diff --git a/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java b/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java -index c64b851096d..8dcfbad3994 100644 ---- a/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java -+++ b/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java -@@ -21,13 +21,20 @@ - * questions. - */ - -+/* -+ * This file has been modified by Loongson Technology in 2023, These -+ * modifications are Copyright (c) 2023, Loongson Technology, and are made -+ * available on the same license terms set forth above. -+ */ -+ - /** - * @test - * @key randomness - * @summary Test vectorization of numberOfTrailingZeros/numberOfLeadingZeros for Long - * @requires vm.compiler2.enabled - * @requires (os.simpleArch == "x64" & vm.cpu.features ~= ".*avx2.*") | --* (os.simpleArch == "aarch64" & vm.cpu.features ~= ".*sve.*" & (vm.opt.UseSVE == "null" | vm.opt.UseSVE > 0)) -+* (os.simpleArch == "aarch64" & vm.cpu.features ~= ".*sve.*" & (vm.opt.UseSVE == "null" | vm.opt.UseSVE > 0)) | -+* (os.simpleArch == "loongarch64") - * @library /test/lib / - * @run driver compiler.vectorization.TestNumberOfContinuousZeros - */ diff --git a/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java b/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java -index 6a709849b9c..0a209d2519a 100644 +index 6a709849b..0a209d251 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java @@ -21,13 +21,20 @@ @@ -80200,33 +80645,8 @@ index 6a709849b9c..0a209d2519a 100644 * @library /test/lib / * @run driver compiler.vectorization.TestPopulateIndex */ -diff --git a/test/hotspot/jtreg/compiler/vectorization/TestReverseBitsVector.java b/test/hotspot/jtreg/compiler/vectorization/TestReverseBitsVector.java -index 1144186d8e5..f36bb209a6b 100644 ---- a/test/hotspot/jtreg/compiler/vectorization/TestReverseBitsVector.java -+++ b/test/hotspot/jtreg/compiler/vectorization/TestReverseBitsVector.java -@@ -20,12 +20,19 @@ - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -+ -+/* -+ * This file has been modified by Loongson Technology in 2023, These -+ * modifications are Copyright (c) 2023, Loongson Technology, and are made -+ * available on the same license terms set forth above. -+ */ -+ - /** - * @test - * @bug 8290034 - * @summary Auto-vectorization of Reverse bit operation. - * @requires vm.compiler2.enabled -- * @requires (os.simpleArch == "x64" & vm.cpu.features ~= ".*avx2.*") | os.arch == "aarch64" -+ * @requires (os.simpleArch == "x64" & vm.cpu.features ~= ".*avx2.*") | os.arch == "aarch64" | os.arch=="loongarch64" - * @library /test/lib / - * @run driver compiler.vectorization.TestReverseBitsVector - */ diff --git a/test/hotspot/jtreg/compiler/vectorization/TestReverseBytes.java b/test/hotspot/jtreg/compiler/vectorization/TestReverseBytes.java -index 47813e2790e..d30f2d3d177 100644 +index 47813e279..d30f2d3d1 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestReverseBytes.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestReverseBytes.java @@ -20,12 +20,19 @@ @@ -80251,7 +80671,7 @@ index 47813e2790e..d30f2d3d177 100644 * @run driver compiler.vectorization.TestReverseBytes */ diff --git a/test/hotspot/jtreg/compiler/vectorization/TestSignumVector.java b/test/hotspot/jtreg/compiler/vectorization/TestSignumVector.java -index bf6a10b855f..b97c0461eaa 100644 +index bf6a10b85..b97c0461e 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestSignumVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestSignumVector.java @@ -21,12 +21,18 @@ @@ -80275,10 +80695,10 @@ index bf6a10b855f..b97c0461eaa 100644 * @run driver compiler.vectorization.TestSignumVector */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java -index a4eca0fe8dd..de44f60520a 100644 +index 5c9fc7d4f..ea6ccc8df 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java -@@ -21,6 +21,12 @@ +@@ -22,6 +22,12 @@ * questions. */ @@ -80291,7 +80711,7 @@ index a4eca0fe8dd..de44f60520a 100644 /* * @test * @summary Vectorization test on array index fill -@@ -35,7 +41,7 @@ +@@ -36,7 +42,7 @@ * -XX:+WhiteBoxAPI * compiler.vectorization.runner.ArrayIndexFillTest * @@ -80301,7 +80721,7 @@ index a4eca0fe8dd..de44f60520a 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayInvariantFillTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayInvariantFillTest.java -index 2e7302bba05..964c03955d1 100644 +index 2e7302bba..964c03955 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayInvariantFillTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayInvariantFillTest.java @@ -21,6 +21,12 @@ @@ -80327,10 +80747,10 @@ index 2e7302bba05..964c03955d1 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java -index 74262142247..920f0418e10 100644 +index 44f9286c6..bf90e9ef7 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java -@@ -21,6 +21,12 @@ +@@ -22,6 +22,12 @@ * questions. */ @@ -80342,8 +80762,8 @@ index 74262142247..920f0418e10 100644 + /* * @test - * @summary Vectorization test on bug-prone shift operation -@@ -35,7 +41,7 @@ + * @bug 8183390 8332905 +@@ -37,7 +43,7 @@ * -XX:+WhiteBoxAPI * compiler.vectorization.runner.ArrayShiftOpTest * @@ -80353,7 +80773,7 @@ index 74262142247..920f0418e10 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java -index 2410ebe8554..1f0876eec56 100644 +index 2410ebe85..1f0876eec 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java @@ -21,6 +21,12 @@ @@ -80379,7 +80799,7 @@ index 2410ebe8554..1f0876eec56 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicFloatOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicFloatOpTest.java -index c9eda7d7650..dd267e0ae4b 100644 +index c9eda7d76..dd267e0ae 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicFloatOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicFloatOpTest.java @@ -21,6 +21,12 @@ @@ -80405,7 +80825,7 @@ index c9eda7d7650..dd267e0ae4b 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java -index 80ebd7b64d0..22b92e861c5 100644 +index 80ebd7b64..22b92e861 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java @@ -22,6 +22,12 @@ @@ -80431,7 +80851,7 @@ index 80ebd7b64d0..22b92e861c5 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java -index 2bf59814b4f..f0bd2d2ffb4 100644 +index 2bf59814b..f0bd2d2ff 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java @@ -22,6 +22,12 @@ @@ -80457,7 +80877,7 @@ index 2bf59814b4f..f0bd2d2ffb4 100644 */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/LoopReductionOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/LoopReductionOpTest.java -index f1c8fea059b..9cf2023fa7d 100644 +index f1c8fea05..9cf2023fa 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/LoopReductionOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/LoopReductionOpTest.java @@ -21,6 +21,12 @@ @@ -80483,7 +80903,7 @@ index f1c8fea059b..9cf2023fa7d 100644 * */ diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java -index a0dff95a23f..fd0fcbd3a90 100644 +index a0dff95a2..fd0fcbd3a 100644 --- a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java @@ -21,6 +21,12 @@ @@ -80510,7 +80930,7 @@ index a0dff95a23f..fd0fcbd3a90 100644 * @run main/othervm --enable-native-access=ALL-UNNAMED -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/loongson/25064/NUMAHelper.java b/test/hotspot/jtreg/loongson/25064/NUMAHelper.java new file mode 100644 -index 00000000000..ee0c4387eb3 +index 000000000..ee0c4387e --- /dev/null +++ b/test/hotspot/jtreg/loongson/25064/NUMAHelper.java @@ -0,0 +1,100 @@ @@ -80616,7 +81036,7 @@ index 00000000000..ee0c4387eb3 +} diff --git a/test/hotspot/jtreg/loongson/25064/TestUseNUMADefault.java b/test/hotspot/jtreg/loongson/25064/TestUseNUMADefault.java new file mode 100644 -index 00000000000..9f7263f5081 +index 000000000..9f7263f50 --- /dev/null +++ b/test/hotspot/jtreg/loongson/25064/TestUseNUMADefault.java @@ -0,0 +1,152 @@ @@ -80774,7 +81194,7 @@ index 00000000000..9f7263f5081 +} diff --git a/test/hotspot/jtreg/loongson/25064/TestUseNUMADisabled.java b/test/hotspot/jtreg/loongson/25064/TestUseNUMADisabled.java new file mode 100644 -index 00000000000..e21dffa418a +index 000000000..e21dffa41 --- /dev/null +++ b/test/hotspot/jtreg/loongson/25064/TestUseNUMADisabled.java @@ -0,0 +1,94 @@ @@ -80874,7 +81294,7 @@ index 00000000000..e21dffa418a +} diff --git a/test/hotspot/jtreg/loongson/25064/TestUseNUMAEnabled.java b/test/hotspot/jtreg/loongson/25064/TestUseNUMAEnabled.java new file mode 100644 -index 00000000000..c05b91e1dcf +index 000000000..c05b91e1d --- /dev/null +++ b/test/hotspot/jtreg/loongson/25064/TestUseNUMAEnabled.java @@ -0,0 +1,165 @@ @@ -81045,7 +81465,7 @@ index 00000000000..c05b91e1dcf +} diff --git a/test/hotspot/jtreg/loongson/25443/Test25443.java b/test/hotspot/jtreg/loongson/25443/Test25443.java new file mode 100644 -index 00000000000..200485d1fdc +index 000000000..200485d1f --- /dev/null +++ b/test/hotspot/jtreg/loongson/25443/Test25443.java @@ -0,0 +1,58 @@ @@ -81109,7 +81529,7 @@ index 00000000000..200485d1fdc +} diff --git a/test/hotspot/jtreg/loongson/26733/Test26733.java b/test/hotspot/jtreg/loongson/26733/Test26733.java new file mode 100644 -index 00000000000..83ba5912879 +index 000000000..83ba59128 --- /dev/null +++ b/test/hotspot/jtreg/loongson/26733/Test26733.java @@ -0,0 +1,570 @@ @@ -81685,7 +82105,7 @@ index 00000000000..83ba5912879 +} diff --git a/test/hotspot/jtreg/loongson/30358/MEMBARType.java b/test/hotspot/jtreg/loongson/30358/MEMBARType.java new file mode 100644 -index 00000000000..71636057901 +index 000000000..716360579 --- /dev/null +++ b/test/hotspot/jtreg/loongson/30358/MEMBARType.java @@ -0,0 +1,38 @@ @@ -81729,7 +82149,7 @@ index 00000000000..71636057901 +} diff --git a/test/hotspot/jtreg/loongson/30358/TEST.properties b/test/hotspot/jtreg/loongson/30358/TEST.properties new file mode 100644 -index 00000000000..9cfabdea488 +index 000000000..9cfabdea4 --- /dev/null +++ b/test/hotspot/jtreg/loongson/30358/TEST.properties @@ -0,0 +1,25 @@ @@ -81760,7 +82180,7 @@ index 00000000000..9cfabdea488 +maxOutputSize = 2500000 diff --git a/test/hotspot/jtreg/loongson/30358/TestLoadLoad.java b/test/hotspot/jtreg/loongson/30358/TestLoadLoad.java new file mode 100644 -index 00000000000..92a4f00c247 +index 000000000..92a4f00c2 --- /dev/null +++ b/test/hotspot/jtreg/loongson/30358/TestLoadLoad.java @@ -0,0 +1,129 @@ @@ -81895,7 +82315,7 @@ index 00000000000..92a4f00c247 +} diff --git a/test/hotspot/jtreg/loongson/30358/TestNewObjectWithFinal.java b/test/hotspot/jtreg/loongson/30358/TestNewObjectWithFinal.java new file mode 100644 -index 00000000000..2bc9ada7ce8 +index 000000000..2bc9ada7c --- /dev/null +++ b/test/hotspot/jtreg/loongson/30358/TestNewObjectWithFinal.java @@ -0,0 +1,247 @@ @@ -82148,7 +82568,7 @@ index 00000000000..2bc9ada7ce8 +} diff --git a/test/hotspot/jtreg/loongson/30358/TestVolatile.java b/test/hotspot/jtreg/loongson/30358/TestVolatile.java new file mode 100644 -index 00000000000..9fefa381c38 +index 000000000..9fefa381c --- /dev/null +++ b/test/hotspot/jtreg/loongson/30358/TestVolatile.java @@ -0,0 +1,358 @@ @@ -82512,7 +82932,7 @@ index 00000000000..9fefa381c38 +} diff --git a/test/hotspot/jtreg/loongson/7432/Test7423.java b/test/hotspot/jtreg/loongson/7432/Test7423.java new file mode 100644 -index 00000000000..defa026410b +index 000000000..defa02641 --- /dev/null +++ b/test/hotspot/jtreg/loongson/7432/Test7423.java @@ -0,0 +1,61 @@ @@ -82578,7 +82998,7 @@ index 00000000000..defa026410b + +} diff --git a/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java b/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java -index e75e6643809..88bd67d6b39 100644 +index e75e66438..88bd67d6b 100644 --- a/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java +++ b/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java @@ -21,6 +21,12 @@ @@ -82604,7 +83024,7 @@ index e75e6643809..88bd67d6b39 100644 } diff --git a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java -index a7faed10e02..8d326d428e6 100644 +index b772e2eb6..be7733d5f 100644 --- a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java +++ b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java @@ -21,6 +21,12 @@ @@ -82620,7 +83040,7 @@ index a7faed10e02..8d326d428e6 100644 /* * @test id=no-options * @summary Run test with no arguments apart from the ones required by -@@ -38,7 +44,7 @@ +@@ -39,7 +45,7 @@ * @library /test/lib * @build jdk.test.lib.Platform * @requires os.family == "linux" @@ -82630,7 +83050,7 @@ index a7faed10e02..8d326d428e6 100644 * @run main/othervm -XX:+AlwaysPreTouch -Xmx128m -Xlog:pagesize:ps-%p.log -XX:+UseLargePages -XX:LargePageSizeInBytes=2m TestTracePageSizes * @run main/othervm -XX:+AlwaysPreTouch -Xmx2g -Xlog:pagesize:ps-%p.log -XX:+UseLargePages -XX:LargePageSizeInBytes=1g TestTracePageSizes diff --git a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java -index 5c41565db8d..ec9499d92a9 100644 +index 5c41565db..ec9499d92 100644 --- a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java +++ b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java @@ -22,6 +22,12 @@ @@ -82656,7 +83076,7 @@ index 5c41565db8d..ec9499d92a9 100644 * @run main/othervm/native -agentlib:AsyncGetCallTraceTest MyPackage.ASGCTBaseTest */ diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java -index 5d9c3982fb6..f346e763db5 100644 +index 5d9c3982f..f346e763d 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java @@ -21,6 +21,12 @@ @@ -82682,7 +83102,7 @@ index 5d9c3982fb6..f346e763db5 100644 * @requires vm.flagless * @library /test/lib diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java -index 4794a9c8127..cc4e5c0b64f 100644 +index 0fd262bd1..0fee3041f 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -21,6 +21,12 @@ @@ -82708,7 +83128,7 @@ index 4794a9c8127..cc4e5c0b64f 100644 } else if (Platform.isS390x()){ cmp = "CLFI"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java -index 16863189500..e2f3a13473b 100644 +index 168631895..e2f3a1347 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java @@ -21,6 +21,12 @@ @@ -82938,7 +83358,7 @@ index 16863189500..e2f3a13473b 100644 } diff --git a/test/jdk/java/foreign/callarranger/TestLoongArch64CallArranger.java b/test/jdk/java/foreign/callarranger/TestLoongArch64CallArranger.java new file mode 100644 -index 00000000000..399cdbb252e +index 000000000..399cdbb25 --- /dev/null +++ b/test/jdk/java/foreign/callarranger/TestLoongArch64CallArranger.java @@ -0,0 +1,521 @@ @@ -83464,7 +83884,7 @@ index 00000000000..399cdbb252e + } +} diff --git a/test/jdk/java/foreign/callarranger/platform/PlatformLayouts.java b/test/jdk/java/foreign/callarranger/platform/PlatformLayouts.java -index 97856075bef..c6d6fa8efb5 100644 +index 97856075b..c6d6fa8ef 100644 --- a/test/jdk/java/foreign/callarranger/platform/PlatformLayouts.java +++ b/test/jdk/java/foreign/callarranger/platform/PlatformLayouts.java @@ -23,6 +23,13 @@ @@ -83539,7 +83959,7 @@ index 97856075bef..c6d6fa8efb5 100644 + } } diff --git a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java -index ca1292afd3a..a8052f06143 100644 +index ca1292afd..a8052f061 100644 --- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java +++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java @@ -31,6 +31,12 @@ @@ -83565,7 +83985,7 @@ index ca1292afd3a..a8052f06143 100644 * @library /test/lib * @run main/othervm/timeout=1600 -XX:+UnlockExperimentalVMOptions -XX:LockingMode=0 -XX:+VerifyHeavyMonitors MapLoops diff --git a/test/jdk/jdk/jfr/event/os/TestCPUInformation.java b/test/jdk/jdk/jfr/event/os/TestCPUInformation.java -index c5166580010..f51a1468754 100644 +index c51665800..f51a14687 100644 --- a/test/jdk/jdk/jfr/event/os/TestCPUInformation.java +++ b/test/jdk/jdk/jfr/event/os/TestCPUInformation.java @@ -21,6 +21,12 @@ @@ -83593,7 +84013,7 @@ index c5166580010..f51a1468754 100644 } } diff --git a/test/jdk/sun/net/InetAddress/nameservice/simple/DefaultCaching.java b/test/jdk/sun/net/InetAddress/nameservice/simple/DefaultCaching.java -index 37d770b62a5..1c3df61b8a7 100644 +index 37d770b62..1c3df61b8 100644 --- a/test/jdk/sun/net/InetAddress/nameservice/simple/DefaultCaching.java +++ b/test/jdk/sun/net/InetAddress/nameservice/simple/DefaultCaching.java @@ -21,12 +21,19 @@ @@ -83627,7 +84047,7 @@ index 37d770b62a5..1c3df61b8a7 100644 test("foo", "10.5.18.22", true, 5); test("theclub", "129.156.220.1", true, 6); diff --git a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java -index f8ce856bddd..84b7ecba37f 100644 +index e78e200ac..0a6abfd08 100644 --- a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java +++ b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java @@ -33,6 +33,12 @@ import java.util.HashSet; @@ -83653,7 +84073,7 @@ index f8ce856bddd..84b7ecba37f 100644 OS("isAix", "isLinux", "isOSX", "isWindows"), VM_TYPE("isClient", "isServer", "isMinimal", "isZero", "isEmbedded"), diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java -index 92663c65d0f..311facd8ee1 100644 +index 4a4b164cd..ad6b11c3e 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -21,6 +21,12 @@ @@ -83669,7 +84089,7 @@ index 92663c65d0f..311facd8ee1 100644 package jdk.test.lib; import java.io.BufferedReader; -@@ -234,6 +240,10 @@ public class Platform { +@@ -235,6 +241,10 @@ public class Platform { return isArch("(i386)|(x86(?!_64))"); } @@ -83682,7 +84102,7 @@ index 92663c65d0f..311facd8ee1 100644 } diff --git a/test/micro/org/openjdk/bench/loongarch/C2Memory.java b/test/micro/org/openjdk/bench/loongarch/C2Memory.java new file mode 100644 -index 00000000000..65cf1773d09 +index 000000000..65cf1773d --- /dev/null +++ b/test/micro/org/openjdk/bench/loongarch/C2Memory.java @@ -0,0 +1,67 @@ @@ -83755,7 +84175,7 @@ index 00000000000..65cf1773d09 +} diff --git a/test/micro/org/openjdk/bench/loongarch/MisAlignVector.java b/test/micro/org/openjdk/bench/loongarch/MisAlignVector.java new file mode 100644 -index 00000000000..1ee6649cda3 +index 000000000..1ee6649cd --- /dev/null +++ b/test/micro/org/openjdk/bench/loongarch/MisAlignVector.java @@ -0,0 +1,63 @@ @@ -83822,3 +84242,6 @@ index 00000000000..1ee6649cda3 + } + } +} +-- +2.43.0 + diff --git a/backport-of-8339298-Remove-unused-function-declarati.patch b/backport-of-8339298-Remove-unused-function-declarati.patch new file mode 100644 index 0000000000000000000000000000000000000000..1090411253f493fa26fff61c445a819270e6a9ac --- /dev/null +++ b/backport-of-8339298-Remove-unused-function-declarati.patch @@ -0,0 +1,36 @@ +Subject: backport of 8339298: Remove unused function declaration poll_for_safepoint + +--- + src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp | 2 -- + src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp | 2 -- + 2 files changed, 4 deletions(-) + +diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +index 43ec18925..fcb6d2943 100644 +--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp ++++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +@@ -60,8 +60,6 @@ friend class ArrayCopyStub; + void casw(Register addr, Register newval, Register cmpval); + void casl(Register addr, Register newval, Register cmpval); + +- void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = nullptr); +- + static const int max_tableswitches = 20; + struct tableswitch switches[max_tableswitches]; + int tableswitch_count; +diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp +index 04e76796c..a74bf1611 100644 +--- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp ++++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp +@@ -62,8 +62,6 @@ private: + void caswu(Register addr, Register newval, Register cmpval); + void casl(Register addr, Register newval, Register cmpval); + +- void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = nullptr); +- + void deoptimize_trap(CodeEmitInfo *info); + + enum { +-- +2.33.0 + diff --git a/heapdump-bug-fix.patch b/heapdump-bug-fix.patch new file mode 100644 index 0000000000000000000000000000000000000000..0533acba80c92a36469c34c991c6542bbf21d3be --- /dev/null +++ b/heapdump-bug-fix.patch @@ -0,0 +1,103 @@ +From 04681c0e50c884ef1835af026cee6ce8d8a826bc Mon Sep 17 00:00:00 2001 +Date: Wed, 14 May 2025 16:34:14 +0800 +Subject: heapdump bug fix + +--- + make/common/NativeCompilation.gmk | 4 ++-- + src/hotspot/os_cpu/linux_arm/linux_arm_32.S | 2 ++ + src/hotspot/share/services/heapDumper.cpp | 21 ++++++++++++++------- + 3 files changed, 18 insertions(+), 9 deletions(-) + +diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk +index fbf2f62e0..4106c9de8 100644 +--- a/make/common/NativeCompilation.gmk ++++ b/make/common/NativeCompilation.gmk +@@ -795,7 +795,7 @@ define SetupNativeCompilationBody + ifeq ($$($1_COMPILE_WITH_DEBUG_SYMBOLS), true) + $1_EXTRA_CFLAGS += $$(CFLAGS_DEBUG_SYMBOLS) + $1_EXTRA_CXXFLAGS += $$(CFLAGS_DEBUG_SYMBOLS) +- ifeq ($(findstring $(OPENJDK_TARGET_CPU), arm), ) ++ ifneq ($(findstring $(OPENJDK_TARGET_CPU), arm), ) + $1_EXTRA_CFLAGS := $(filter-out -gdwarf-aranges,$(1_EXTRA_CFLAGS)) + $1_EXTRA_CXXFLAGS := $(filter-out -gdwarf-aranges,$(1_EXTRA_CXXFLAGS)) + endif +@@ -904,7 +904,7 @@ define SetupNativeCompilationBody + $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).gch + $1_USE_PCH_FLAGS := -I$$($1_OBJECT_DIR)/precompiled + else ifeq ($(TOOLCHAIN_TYPE), clang) +- ifeq ($(findstring $(OPENJDK_TARGET_CPU), arm), ) ++ ifneq ($(findstring $(OPENJDK_TARGET_CPU), arm), ) + $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).gch + $1_USE_PCH_FLAGS := -I$$($1_OBJECT_DIR)/precompiled + else +diff --git a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S +index cfac173b1..aa839a1e3 100644 +--- a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S ++++ b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S +@@ -28,6 +28,8 @@ + # point or use it in the same manner as does the server + # compiler. + ++ .globl _Copy_conjoint_bytes ++ .type _Copy_conjoint_bytes, %function + .globl _Copy_arrayof_conjoint_bytes + .type _Copy_arrayof_conjoint_bytes, %function + .globl _Copy_disjoint_words +diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp +index bbef3bfa1..6f7f9afdc 100644 +--- a/src/hotspot/share/services/heapDumper.cpp ++++ b/src/hotspot/share/services/heapDumper.cpp +@@ -2492,8 +2492,20 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { + assert(_global_writer == nullptr, "Error"); + _global_writer = _local_writer; + } ++ void set_dump_instance_fields_descriptors() { ++ assert(_dump_instance_fields_descriptors == nullptr, "Error"); ++ assert(_global_writer != nullptr, "Error"); ++ if(_global_writer->getHeapDumpRedactLevel() == REDACT_ANNOTATION) { ++ _dump_instance_fields_descriptors = DumperSupport::dump_instance_annotation_field_descriptors; ++ } else if(_global_writer->getHeapDumpRedactLevel() == REDACT_DIYRULES) { ++ _dump_instance_fields_descriptors = DumperSupport::dump_instance_diyrules_field_descriptors; ++ } else { ++ _dump_instance_fields_descriptors = DumperSupport::dump_instance_field_descriptors; ++ } ++ } + void clear_global_dumper() { _global_dumper = nullptr; } + void clear_global_writer() { _global_writer = nullptr; } ++ void clear_dump_instance_fields_descriptors() { _dump_instance_fields_descriptors = nullptr; } + + bool skip_operation() const; + +@@ -2536,13 +2548,6 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { + _dumper_controller = nullptr; + _poi = nullptr; + _large_object_list = new (std::nothrow) HeapDumpLargeObjectList(); +- if(writer->getHeapDumpRedactLevel() == REDACT_ANNOTATION) { +- _dump_instance_fields_descriptors = DumperSupport::dump_instance_annotation_field_descriptors; +- } else if(writer->getHeapDumpRedactLevel() == REDACT_DIYRULES) { +- _dump_instance_fields_descriptors = DumperSupport::dump_instance_diyrules_field_descriptors; +- } else { +- _dump_instance_fields_descriptors = DumperSupport::dump_instance_field_descriptors; +- } + + if (oome) { + assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread"); +@@ -2807,6 +2812,7 @@ void VM_HeapDumper::doit() { + // the following should be safe. + set_global_dumper(); + set_global_writer(); ++ set_dump_instance_fields_descriptors(); + + WorkerThreads* workers = ch->safepoint_workers(); + if (workers == nullptr) { +@@ -2832,6 +2838,7 @@ void VM_HeapDumper::doit() { + // Now we clear the global variables, so that a future dumper can run. + clear_global_dumper(); + clear_global_writer(); ++ clear_dump_instance_fields_descriptors(); + } + + void VM_HeapDumper::work(uint worker_id) { +-- +2.43.0.windows.1 + diff --git a/huawei-1-add-port-jbolt-feature.patch b/huawei-1-add-port-jbolt-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..92b5101a238f1ad8b6b1aaf4138825811a5fd5c4 --- /dev/null +++ b/huawei-1-add-port-jbolt-feature.patch @@ -0,0 +1,5391 @@ +Date: Fri, 14 Mar 2025 07:02:01 +0000 +Subject: !1 add port jbolt feature * add port jbolt feature + +--- + make/hotspot/lib/JvmFeatures.gmk | 2 + + make/hotspot/lib/JvmFlags.gmk | 6 + + make/hotspot/lib/JvmMapfile.gmk | 6 + + src/hotspot/os/linux/os_linux.cpp | 40 + + src/hotspot/os/linux/os_linux.hpp | 30 +- + src/hotspot/share/ci/ciEnv.cpp | 41 +- + src/hotspot/share/code/codeBlob.hpp | 9 +- + src/hotspot/share/code/codeCache.cpp | 33 + + src/hotspot/share/code/codeCache.hpp | 16 +- + src/hotspot/share/code/nmethod.cpp | 19 + + src/hotspot/share/code/nmethod.hpp | 8 + + src/hotspot/share/compiler/compileBroker.cpp | 9 + + src/hotspot/share/compiler/compileBroker.hpp | 3 + + src/hotspot/share/compiler/compileTask.hpp | 12 + + src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 8 + + src/hotspot/share/jbolt/jBoltCallGraph.cpp | 480 ++++++ + src/hotspot/share/jbolt/jBoltCallGraph.hpp | 277 ++++ + .../share/jbolt/jBoltControlThread.cpp | 220 +++ + .../share/jbolt/jBoltControlThread.hpp | 69 + + src/hotspot/share/jbolt/jBoltDcmds.cpp | 221 +++ + src/hotspot/share/jbolt/jBoltDcmds.hpp | 129 ++ + src/hotspot/share/jbolt/jBoltManager.cpp | 1429 +++++++++++++++++ + src/hotspot/share/jbolt/jBoltManager.hpp | 335 ++++ + src/hotspot/share/jbolt/jBoltUtils.cpp | 38 + + src/hotspot/share/jbolt/jBoltUtils.hpp | 55 + + src/hotspot/share/jbolt/jBoltUtils.inline.hpp | 38 + + src/hotspot/share/jbolt/jbolt_globals.hpp | 62 + + src/hotspot/share/jfr/metadata/metadata.xml | 2 + + .../share/jfr/periodic/jfrPeriodic.cpp | 7 + + .../periodic/sampling/jfrThreadSampler.cpp | 13 +- + .../jfr/recorder/stacktrace/jfrStackTrace.cpp | 12 +- + .../jfr/recorder/stacktrace/jfrStackTrace.hpp | 29 + + .../stacktrace/jfrStackTraceRepository.cpp | 114 ++ + .../stacktrace/jfrStackTraceRepository.hpp | 23 + + src/hotspot/share/logging/logTag.hpp | 1 + + src/hotspot/share/opto/doCall.cpp | 4 +- + src/hotspot/share/opto/parse1.cpp | 2 +- + src/hotspot/share/runtime/flags/allFlags.hpp | 15 +- + src/hotspot/share/runtime/java.cpp | 9 + + src/hotspot/share/runtime/threads.cpp | 19 + + src/hotspot/share/utilities/growableArray.hpp | 7 + + src/hotspot/share/utilities/macros.hpp | 15 + + .../cli/common/CodeCacheCLITestCase.java | 12 +- + .../cli/common/CodeCacheOptions.java | 62 +- + .../codecache/jbolt/JBoltDumpModeTest.java | 187 +++ + .../codecache/jbolt/JBoltVMOptionsTest.java | 291 ++++ + .../jtreg/compiler/codecache/jbolt/o1.log | 2 + + .../jtreg/compiler/codecache/jbolt/o2.log | 2 + + .../jtreg/compiler/codecache/jbolt/o3.log | 4 + + .../jtreg/compiler/codecache/jbolt/o4.log | 12 + + .../runtime/cds/appcds/ClassLoaderTest.java | 2 +- + test/lib/jdk/test/whitebox/code/BlobType.java | 24 +- + 52 files changed, 4428 insertions(+), 37 deletions(-) + create mode 100644 src/hotspot/share/jbolt/jBoltCallGraph.cpp + create mode 100644 src/hotspot/share/jbolt/jBoltCallGraph.hpp + create mode 100644 src/hotspot/share/jbolt/jBoltControlThread.cpp + create mode 100644 src/hotspot/share/jbolt/jBoltControlThread.hpp + create mode 100644 src/hotspot/share/jbolt/jBoltDcmds.cpp + create mode 100644 src/hotspot/share/jbolt/jBoltDcmds.hpp + create mode 100644 src/hotspot/share/jbolt/jBoltManager.cpp + create mode 100644 src/hotspot/share/jbolt/jBoltManager.hpp + create mode 100644 src/hotspot/share/jbolt/jBoltUtils.cpp + create mode 100644 src/hotspot/share/jbolt/jBoltUtils.hpp + create mode 100644 src/hotspot/share/jbolt/jBoltUtils.inline.hpp + create mode 100644 src/hotspot/share/jbolt/jbolt_globals.hpp + create mode 100644 test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java + create mode 100644 test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java + create mode 100644 test/hotspot/jtreg/compiler/codecache/jbolt/o1.log + create mode 100644 test/hotspot/jtreg/compiler/codecache/jbolt/o2.log + create mode 100644 test/hotspot/jtreg/compiler/codecache/jbolt/o3.log + create mode 100644 test/hotspot/jtreg/compiler/codecache/jbolt/o4.log + +diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk +index cbe60fde2..f57406dc1 100644 +--- a/make/hotspot/lib/JvmFeatures.gmk ++++ b/make/hotspot/lib/JvmFeatures.gmk +@@ -160,6 +160,8 @@ endif + ifneq ($(call check-jvm-feature, jfr), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_JFR=0 + JVM_EXCLUDE_PATTERNS += jfr ++ JVM_CFLAGS_FEATURES += -DINCLUDE_JBOLT=0 ++ JVM_EXCLUDE_PATTERNS += jbolt + JVM_EXCLUDE_FILES += compilerEvent.cpp + endif + +diff --git a/make/hotspot/lib/JvmFlags.gmk b/make/hotspot/lib/JvmFlags.gmk +index 1fadd5331..b77f1e3a6 100644 +--- a/make/hotspot/lib/JvmFlags.gmk ++++ b/make/hotspot/lib/JvmFlags.gmk +@@ -41,6 +41,12 @@ JVM_SRC_DIRS += $(call uniq, $(wildcard $(foreach d, $(JVM_SRC_ROOTS), \ + $(JVM_VARIANT_OUTPUTDIR)/gensrc + # + ++JVM_ACC_PLUGIN_DIR := $(call FindSrcDirsForLib, java.base, jplugin) ++JVM_ACC_PLUGIN_SRC := $(JVM_ACC_PLUGIN_DIR)/feature ++ifeq ($(wildcard $(JVM_ACC_PLUGIN_SRC)), $(JVM_ACC_PLUGIN_SRC)) ++ JVM_SRC_DIRS += $(JVM_ACC_PLUGIN_SRC) ++endif ++ + JVM_CFLAGS_INCLUDES += \ + $(patsubst %,-I%,$(JVM_SRC_DIRS)) \ + -I$(TOPDIR)/src/hotspot/share/precompiled \ +diff --git a/make/hotspot/lib/JvmMapfile.gmk b/make/hotspot/lib/JvmMapfile.gmk +index 2808ac2af..916aff4a3 100644 +--- a/make/hotspot/lib/JvmMapfile.gmk ++++ b/make/hotspot/lib/JvmMapfile.gmk +@@ -48,6 +48,12 @@ ifneq ($(findstring debug, $(DEBUG_LEVEL)), ) + endif + endif + ++JVM_ACC_PLUGIN_DIR := $(call FindSrcDirsForLib, java.base, jplugin) ++JVM_ACC_PLUGIN_SYMBOLS_SRC := $(JVM_ACC_PLUGIN_DIR)/make/hotspot-symbols ++ifeq ($(wildcard $(JVM_ACC_PLUGIN_SYMBOLS_SRC)), $(JVM_ACC_PLUGIN_SYMBOLS_SRC)) ++ SYMBOLS_SRC += $(JVM_ACC_PLUGIN_SYMBOLS_SRC)/symbols-plugin ++endif ++ + ################################################################################ + # Create a dynamic list of symbols from the built object files. This is highly + # platform dependent. +diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp +index ddfa97ecb..3cb529bc8 100644 +--- a/src/hotspot/os/linux/os_linux.cpp ++++ b/src/hotspot/os/linux/os_linux.cpp +@@ -4582,6 +4582,46 @@ void os::Linux::numa_init() { + } + } + ++#if INCLUDE_JBOLT ++os::Linux::jboltLog_precalc_t os::Linux::_jboltLog_precalc; ++os::Linux::jboltLog_do_t os::Linux::_jboltLog_do; ++os::Linux::jboltMerge_judge_t os::Linux::_jboltMerge_judge; ++#endif // INCLUDE_JBOLT ++ ++void os::Linux::load_plugin_library() { ++ ++#if INCLUDE_JBOLT ++ _jboltLog_precalc = CAST_TO_FN_PTR(jboltLog_precalc_t, dlsym(RTLD_DEFAULT, "JBoltLog_PreCalc")); ++ _jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(RTLD_DEFAULT, "JBoltLog_DO")); ++ _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(RTLD_DEFAULT, "JBoltMerge_Judge")); ++#endif // INCLUDE_JBOLT ++ ++ char path[JVM_MAXPATHLEN]; ++ char ebuf[1024]; ++ void* handle = NULL; ++ if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "jvm21_Acc") || ++ os::dll_locate_lib(path, sizeof(path), "/usr/lib64", "jvm21_Acc")) { ++ handle = dlopen(path, RTLD_LAZY); ++ } ++ if (handle != NULL) { ++#if INCLUDE_JBOLT ++ if (_jboltLog_precalc == NULL) { ++ _jboltLog_precalc = CAST_TO_FN_PTR(jboltLog_precalc_t, dlsym(handle, "JBoltLog_PreCalc")); ++ } ++ if (_jboltLog_do == NULL) { ++ _jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(handle, "JBoltLog_DO")); ++ } ++ if (_jboltMerge_judge == NULL) { ++ _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge")); ++ } ++#endif // INCLUDE_JBOLT ++ } ++ ++ JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr), ++ BOOL_TO_STR(_jboltLog_do != nullptr), ++ BOOL_TO_STR(_jboltMerge_judge != nullptr));) ++} ++ + #if defined(IA32) && !defined(ZERO) + /* + * Work-around (execute code at a high address) for broken NX emulation using CS limit, +diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp +index 029f2aa7a..4192c90bd 100644 +--- a/src/hotspot/os/linux/os_linux.hpp ++++ b/src/hotspot/os/linux/os_linux.hpp +@@ -139,6 +139,7 @@ class os::Linux { + static const char *libc_version() { return _libc_version; } + static const char *libpthread_version() { return _libpthread_version; } + ++ static void load_plugin_library(); + static void libpthread_init(); + static void sched_getcpu_init(); + static bool libnuma_init(); +@@ -214,7 +215,14 @@ class os::Linux { + typedef void (*numa_set_bind_policy_func_t)(int policy); + typedef int (*numa_bitmask_isbitset_func_t)(struct bitmask *bmp, unsigned int n); + typedef int (*numa_distance_func_t)(int node1, int node2); +- ++#if INCLUDE_JBOLT ++ typedef void (*jboltLog_precalc_t)(unsigned int topFrameIndex, unsigned int &max_frames); ++ typedef bool (*jboltLog_do_t)(uintptr_t related_data[], address stacktrace, unsigned int i, int comp_level, address new_func, address *tempfunc); ++ typedef int (*jboltMerge_judge_t)(uintptr_t data_layout[], int candidate, address clusters, address merged, address cluster); ++ static jboltLog_precalc_t _jboltLog_precalc; ++ static jboltLog_do_t _jboltLog_do; ++ static jboltMerge_judge_t _jboltMerge_judge; ++#endif + static sched_getcpu_func_t _sched_getcpu; + static numa_node_to_cpus_func_t _numa_node_to_cpus; + static numa_node_to_cpus_v2_func_t _numa_node_to_cpus_v2; +@@ -431,6 +439,26 @@ class os::Linux { + // otherwise does nothing and returns -2. + static int malloc_info(FILE* stream); + #endif // GLIBC ++ ++#if INCLUDE_JBOLT ++ static void jboltLog_precalc(unsigned int topFrameIndex, unsigned int &max_frames) { ++ if (_jboltLog_precalc != nullptr) { ++ _jboltLog_precalc(topFrameIndex, max_frames); ++ } ++ } ++ static bool jboltLog_do(uintptr_t related_data[], address stacktrace, unsigned int i, int comp_level, address new_func, address *tempfunc) { ++ if (_jboltLog_do != nullptr) { ++ return _jboltLog_do(related_data, stacktrace, i, comp_level, new_func, tempfunc); ++ } ++ return false; ++ } ++ static int jboltMerge_judge(uintptr_t data_layout[], int candidate, address clusters, address merged, address cluster) { ++ if (_jboltMerge_judge != nullptr) { ++ return _jboltMerge_judge(data_layout, candidate, clusters, merged, cluster); ++ } ++ return -1; ++ } ++#endif // INCLUDE_JBOLT + }; + + #endif // OS_LINUX_OS_LINUX_HPP +diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp +index 6112b46ac..0c48b6153 100644 +--- a/src/hotspot/share/ci/ciEnv.cpp ++++ b/src/hotspot/share/ci/ciEnv.cpp +@@ -83,6 +83,9 @@ + #ifdef COMPILER2 + #include "opto/runtime.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif + + // ciEnv + // +@@ -1117,15 +1120,35 @@ void ciEnv::register_method(ciMethod* target, + assert(offsets->value(CodeOffsets::Deopt) != -1, "must have deopt entry"); + assert(offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry"); + +- nm = nmethod::new_nmethod(method, +- compile_id(), +- entry_bci, +- offsets, +- orig_pc_offset, +- debug_info(), dependencies(), code_buffer, +- frame_words, oop_map_set, +- handler_table, inc_table, +- compiler, CompLevel(task()->comp_level())); ++#if INCLUDE_JBOLT ++ if (UseJBolt && JBoltManager::reorder_phase_is_collecting_or_reordering()) { ++ CodeBlobType code_blob_type = JBoltManager::calc_code_blob_type(method(), task(), THREAD); ++ nm = nmethod::new_nmethod(method, ++ compile_id(), ++ entry_bci, ++ offsets, ++ orig_pc_offset, ++ debug_info(), dependencies(), code_buffer, ++ frame_words, oop_map_set, ++ handler_table, inc_table, ++ compiler, CompLevel(task()->comp_level()), ++#if INCLUDE_JVMCI ++ nullptr, 0, nullptr, ++#endif ++ code_blob_type); ++ } else ++#endif // INCLUDE_JBOLT ++ { ++ nm = nmethod::new_nmethod(method, ++ compile_id(), ++ entry_bci, ++ offsets, ++ orig_pc_offset, ++ debug_info(), dependencies(), code_buffer, ++ frame_words, oop_map_set, ++ handler_table, inc_table, ++ compiler, CompLevel(task()->comp_level())); ++ } + + // Free codeBlobs + code_buffer->free_blob(); +diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp +index e842bd88a..8392499d3 100644 +--- a/src/hotspot/share/code/codeBlob.hpp ++++ b/src/hotspot/share/code/codeBlob.hpp +@@ -44,9 +44,12 @@ class OopMapSet; + enum class CodeBlobType { + MethodNonProfiled = 0, // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods) + MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods +- NonNMethod = 2, // Non-nmethods like Buffers, Adapters and Runtime Stubs +- All = 3, // All types (No code cache segmentation) +- NumTypes = 4 // Number of CodeBlobTypes ++ MethodJBoltHot = 2, // Hot methods (determined by JBolt) of level 1 and 4 nmethods ++ MethodJBoltTmp = 3, // Temporary storage of JBolt hot methods ++ NonNMethod = 4, // Non-nmethods like Buffers, Adapters and Runtime Stubs ++ All = 5, // All types (No code cache segmentation) ++ AOT = 6, // AOT methods ++ NumTypes = 7 // Number of CodeBlobTypes + }; + + // CodeBlob - superclass for all entries in the CodeCache. +diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp +index 9b0bdc364..f63e4f266 100644 +--- a/src/hotspot/share/code/codeCache.cpp ++++ b/src/hotspot/share/code/codeCache.cpp +@@ -77,6 +77,9 @@ + #include "opto/compile.hpp" + #include "opto/node.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif // INCLUDE_JBOLT + + // Helper class for printing in CodeCache + class CodeBlob_sizes { +@@ -329,6 +332,16 @@ void CodeCache::initialize_heaps() { + profiled_size = align_down(profiled_size, alignment); + non_profiled_size = align_down(non_profiled_size, alignment); + ++#if INCLUDE_JBOLT ++ if (UseJBolt && !JBoltDumpMode) { ++ // We replace the original add-heap logic with the JBolt one. manual dump mode doesn't need that ++ JBoltManager::init_code_heaps(non_nmethod_size, profiled_size, non_profiled_size, cache_size, ps, alignment); ++ return; ++ } ++ // The following add-heap logic will not be executed if JBolt load mode is on. ++ // If the following logic is modified, remember to modify the JBolt logic accordingly. ++#endif // INCLUDE_JBOLT ++ + // Reserve one continuous chunk of memory for CodeHeaps and split it into + // parts for the individual heaps. The memory layout looks like this: + // ---------- high ----------- +@@ -384,6 +397,12 @@ ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size, size_t rs_ps) { + + // Heaps available for allocation + bool CodeCache::heap_available(CodeBlobType code_blob_type) { ++ if (code_blob_type == CodeBlobType::MethodJBoltHot) { ++ return JBOLT_ONLY(UseJBolt && !JBoltDumpMode) NOT_JBOLT(false); ++ } else if (code_blob_type == CodeBlobType::MethodJBoltTmp) { ++ return JBOLT_ONLY(UseJBolt && !JBoltDumpMode) NOT_JBOLT(false); ++ } ++ + if (!SegmentedCodeCache) { + // No segmentation: use a single code heap + return (code_blob_type == CodeBlobType::All); +@@ -411,6 +430,12 @@ const char* CodeCache::get_code_heap_flag_name(CodeBlobType code_blob_type) { + case CodeBlobType::MethodProfiled: + return "ProfiledCodeHeapSize"; + break; ++ case CodeBlobType::MethodJBoltHot: ++ return "JBoltHotCodeHeapSize"; ++ break; ++ case CodeBlobType::MethodJBoltTmp: ++ return "JBoltTmpCodeHeapSize"; ++ break; + default: + ShouldNotReachHere(); + return nullptr; +@@ -558,6 +583,14 @@ CodeBlob* CodeCache::allocate(int size, CodeBlobType code_blob_type, bool handle + type = CodeBlobType::MethodNonProfiled; + } + break; ++#if INCLUDE_JBOLT ++ case CodeBlobType::MethodJBoltHot: ++ type = CodeBlobType::MethodNonProfiled; ++ break; ++ case CodeBlobType::MethodJBoltTmp: ++ type = CodeBlobType::MethodNonProfiled; ++ break; ++#endif // INCLUDE_JBOLT + default: + break; + } +diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp +index fbcaefd2a..df38664e7 100644 +--- a/src/hotspot/share/code/codeCache.hpp ++++ b/src/hotspot/share/code/codeCache.hpp +@@ -48,6 +48,10 @@ + // executed at level 2 or 3 + // - Non-Profiled nmethods: nmethods that are not profiled, i.e., those + // executed at level 1 or 4 and native methods ++// - JBolt nmethods: sorted non-profiled nmethods that are judged to be hot ++// by JBolt ++// - JBolt tmp nmethods: non-profiled nmethods that are judged to be hot by ++// JBolt but not sorted yet + // - All: Used for code of all types if code cache segmentation is disabled. + // + // In the rare case of the non-nmethod code heap getting full, non-nmethod code +@@ -87,6 +91,10 @@ class CodeCache : AllStatic { + friend class WhiteBox; + friend class CodeCacheLoader; + friend class ShenandoahParallelCodeHeapIterator; ++#if INCLUDE_JBOLT ++ friend class JBoltManager; ++#endif // INCLUDE_JBOLT ++ + private: + // CodeHeaps of the cache + static GrowableArray* _heaps; +@@ -266,12 +274,16 @@ class CodeCache : AllStatic { + } + + static bool code_blob_type_accepts_compiled(CodeBlobType code_blob_type) { +- bool result = code_blob_type == CodeBlobType::All || code_blob_type <= CodeBlobType::MethodProfiled; ++ // Modified `type <= CodeBlobType::MethodProfiled` to `type < CodeBlobType::NonNMethod` ++ // after adding the JBolt heap. The two logics are still equivalent even without JBolt. ++ bool result = code_blob_type == CodeBlobType::All || code_blob_type < CodeBlobType::NonNMethod; + return result; + } + + static bool code_blob_type_accepts_nmethod(CodeBlobType type) { +- return type == CodeBlobType::All || type <= CodeBlobType::MethodProfiled; ++ // Modified `type <= CodeBlobType::MethodProfiled` to `type < CodeBlobType::NonNMethod` ++ // after adding the JBolt heap. The two logics are still equivalent even without JBolt. ++ return type == CodeBlobType::All || type < CodeBlobType::NonNMethod; + } + + static bool code_blob_type_accepts_allocable(CodeBlobType type) { +diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp +index 500ddbc2f..24b5139cf 100644 +--- a/src/hotspot/share/code/nmethod.cpp ++++ b/src/hotspot/share/code/nmethod.cpp +@@ -85,6 +85,9 @@ + #if INCLUDE_JVMCI + #include "jvmci/jvmciRuntime.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif + + #ifdef DTRACE_ENABLED + +@@ -554,6 +557,9 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, + int speculations_len, + JVMCINMethodData* jvmci_data + #endif ++#if INCLUDE_JBOLT ++ , CodeBlobType code_blob_type // for jbolt ++#endif // INCLUDE_JBOLT + ) + { + assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); +@@ -577,7 +583,11 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + ++#if INCLUDE_JBOLT ++ nm = new (nmethod_size, comp_level, code_blob_type) ++#else // INCLUDE_JBOLT + nm = new (nmethod_size, comp_level) ++#endif // INCLUDE_JBOLT + nmethod(method(), compiler->type(), nmethod_size, compile_id, entry_bci, offsets, + orig_pc_offset, debug_info, dependencies, code_buffer, frame_size, + oop_maps, +@@ -761,6 +771,15 @@ void* nmethod::operator new(size_t size, int nmethod_size, bool allow_NonNMethod + return CodeCache::allocate(nmethod_size, CodeBlobType::NonNMethod); + } + ++#if INCLUDE_JBOLT ++void* nmethod::operator new(size_t size, int nmethod_size, int comp_level, CodeBlobType code_blob_type) throw () { ++ if (code_blob_type < CodeBlobType::All) { ++ return CodeCache::allocate(nmethod_size, code_blob_type); ++ } ++ return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); ++} ++#endif // INCLUDE_JBOLT ++ + nmethod::nmethod( + Method* method, + CompilerType type, +diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp +index 03b8210c3..ddb8a1274 100644 +--- a/src/hotspot/share/code/nmethod.hpp ++++ b/src/hotspot/share/code/nmethod.hpp +@@ -307,6 +307,11 @@ class nmethod : public CompiledMethod { + // findable by nmethod iterators! In particular, they must not contain oops! + void* operator new(size_t size, int nmethod_size, bool allow_NonNMethod_space) throw(); + ++#if INCLUDE_JBOLT ++ // For JBolt. So the code can be allocated in code segments defined by JBolt. ++ void* operator new(size_t size, int nmethod_size, int comp_level, CodeBlobType code_blob_type) throw (); ++#endif // INCLUDE_JBOLT ++ + const char* reloc_string_for(u_char* begin, u_char* end); + + bool try_transition(int new_state); +@@ -349,6 +354,9 @@ class nmethod : public CompiledMethod { + int speculations_len = 0, + JVMCINMethodData* jvmci_data = nullptr + #endif ++#if INCLUDE_JBOLT ++ , CodeBlobType code_blob_type = CodeBlobType::All // for jbolt ++#endif // INCLUDE_JBOLT + ); + + // Only used for unit tests. +diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp +index 9c1bf5393..3a59a17eb 100644 +--- a/src/hotspot/share/compiler/compileBroker.cpp ++++ b/src/hotspot/share/compiler/compileBroker.cpp +@@ -83,6 +83,9 @@ + #include "jvmci/jvmciEnv.hpp" + #include "jvmci/jvmciRuntime.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif // INCLUDE_JBOLT + + #ifdef DTRACE_ENABLED + +@@ -1959,6 +1962,12 @@ void CompileBroker::compiler_thread_loop() { + task->set_failure_reason("breakpoints are present"); + } + ++#if INCLUDE_JBOLT ++ if (UseJBolt && JBoltLoadMode) { ++ JBoltManager::check_start_reordering(thread); ++ } ++#endif // INCLUDE_JBOLT ++ + if (UseDynamicNumberOfCompilerThreads) { + possibly_add_compiler_threads(thread); + assert(!thread->has_pending_exception(), "should have been handled"); +diff --git a/src/hotspot/share/compiler/compileBroker.hpp b/src/hotspot/share/compiler/compileBroker.hpp +index b7f09259f..a2143ad93 100644 +--- a/src/hotspot/share/compiler/compileBroker.hpp ++++ b/src/hotspot/share/compiler/compileBroker.hpp +@@ -140,6 +140,9 @@ public: + class CompileBroker: AllStatic { + friend class Threads; + friend class CompileTaskWrapper; ++#if INCLUDE_JBOLT ++ friend class JBoltManager; ++#endif // INCLUDE_JBOLT + + public: + enum { +diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp +index f5b628232..aff2df38a 100644 +--- a/src/hotspot/share/compiler/compileTask.hpp ++++ b/src/hotspot/share/compiler/compileTask.hpp +@@ -56,6 +56,9 @@ class CompileTask : public CHeapObj { + Reason_Whitebox, // Whitebox API + Reason_MustBeCompiled, // Used for -Xcomp or AlwaysCompileLoopMethods (see CompilationPolicy::must_be_compiled()) + Reason_Bootstrap, // JVMCI bootstrap ++#if INCLUDE_JBOLT ++ Reason_Reorder, // JBolt reorder ++#endif + Reason_Count + }; + +@@ -69,6 +72,9 @@ class CompileTask : public CHeapObj { + "whitebox", + "must_be_compiled", + "bootstrap" ++#if INCLUDE_JBOLT ++ , "reorder" ++#endif + }; + return reason_names[compile_reason]; + } +@@ -230,6 +236,12 @@ public: + print_inlining_inner(tty, method, inline_level, bci, msg); + } + static void print_inlining_ul(ciMethod* method, int inline_level, int bci, const char* msg = nullptr); ++ ++#if INCLUDE_JBOLT ++ CompileReason compile_reason() { return _compile_reason; } ++ int hot_count() { return _hot_count; } ++ const char* failure_reason() { return _failure_reason; } ++#endif // INCLUDE_JBOLT + }; + + #endif // SHARE_COMPILER_COMPILETASK_HPP +diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +index 9b6b22a29..67667a08c 100644 +--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp ++++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +@@ -116,6 +116,9 @@ + #include "utilities/bitMap.inline.hpp" + #include "utilities/globalDefinitions.hpp" + #include "utilities/stack.inline.hpp" ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif // INCLUDE_JBOLT + + size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0; + +@@ -1645,6 +1648,11 @@ size_t G1CollectedHeap::recalculate_used() const { + } + + bool G1CollectedHeap::is_user_requested_concurrent_full_gc(GCCause::Cause cause) { ++#if INCLUDE_JBOLT ++ if (UseJBolt && cause == GCCause::_java_lang_system_gc && JBoltManager::gc_should_sweep_code_heaps_now()) { ++ return true; ++ } ++#endif // INCLUDE_JBOLT + return GCCause::is_user_requested_gc(cause) && ExplicitGCInvokesConcurrent; + } + +diff --git a/src/hotspot/share/jbolt/jBoltCallGraph.cpp b/src/hotspot/share/jbolt/jBoltCallGraph.cpp +new file mode 100644 +index 000000000..c171215ad +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltCallGraph.cpp +@@ -0,0 +1,480 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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 "precompiled.hpp" ++#include "jbolt/jBoltCallGraph.hpp" ++#include "jfr/utilities/jfrAllocation.hpp" ++#include "jfr/support/jfrMethodLookup.hpp" ++#include "logging/log.hpp" ++#include "logging/logStream.hpp" ++#include "oops/method.inline.hpp" ++#include "runtime/os.hpp" ++#include "utilities/defaultStream.hpp" ++#ifdef LINUX ++#include "os_linux.hpp" ++#endif ++ ++#define PAGE_SIZE os::vm_page_size() ++ ++static GrowableArray* _clusters = NULL; ++static GrowableArray* _calls = NULL; ++static GrowableArray* _funcs = NULL; ++ ++// (JBolt hfsort optional)sort final clusters by density ++static const bool _jbolt_density_sort = false; ++// (JBolt hfsort optional)freeze merging while exceeding pagesize ++static const bool _jbolt_merge_frozen = false; ++ ++void JBoltCallGraph::initialize() { ++ ::_clusters = JBoltCallGraph::callgraph_instance().callgraph_clusters(); ++ ::_calls = JBoltCallGraph::callgraph_instance().callgraph_calls(); ++ ::_funcs = JBoltCallGraph::callgraph_instance().callgraph_funcs(); ++} ++ ++void JBoltCallGraph::deinitialize() { ++ ::_clusters = NULL; ++ ::_calls = NULL; ++ ::_funcs = NULL; ++} ++ ++int JBoltCallGraph::clear_instance() { ++ delete _clusters; ++ delete _calls; ++ delete _funcs; ++ ++ // Reinit default cluster start id ++ _init_cluster_id = 0; ++ ++ // Re-allocate ++ _clusters = create_growable_array(); ++ _calls = create_growable_array(); ++ _funcs = create_growable_array(); ++ ++ // Re-initialize ++ initialize(); ++ ++ return 0; ++} ++ ++static GrowableArray* clusters_copy() { ++ GrowableArray* copy = create_growable_array(_clusters->length()); ++ copy->appendAll(_clusters); ++ return copy; ++} ++ ++static GrowableArray* funcs_copy() { ++ GrowableArray* copy = create_growable_array(_funcs->length()); ++ copy->appendAll(_funcs); ++ return copy; ++} ++ ++static int find_func_index(const JBoltFunc* func) { ++ for (int i = 0; i < _funcs->length(); ++i) { ++ JBoltFunc& existing = _funcs->at(i); ++ if (existing == (*func)) { ++ return i; ++ } ++ } ++ return -1; ++} ++ ++// Searching for a cluster with corresponding func or creating a new one if doesn't exist ++static JBoltCluster* find_cluster(JBoltFunc* func) { ++ for (int i = 0; i < _clusters->length(); ++i) { ++ JBoltCluster& cluster = _clusters->at(i); ++ int index = cluster.func_indexes()->at(0); ++ if (_funcs->at(index) == (*func)) { ++ return &cluster; ++ } ++ } ++ _funcs->append(*func); ++ _clusters->append(JBoltCluster(*func)); ++ JBoltCluster& cluster = _clusters->at(_clusters->length() - 1); ++ _funcs->at(_funcs->length() - 1).set_cluster_id(cluster.id()); ++ return &cluster; ++} ++ ++// Creating a new call in graph or updating the weight if exists ++static void add_call_to_calls(GrowableArray* calls, const JBoltCall* call) { ++ for (int i = 0; i < calls->length(); ++i) { ++ JBoltCall& existing_call = calls->at(i); ++ if (existing_call == *call) { ++ if (existing_call.stacktrace_id() == call->stacktrace_id()) { ++ assert(call->call_count() >= existing_call.call_count(), "invariant"); ++ existing_call.callee().add_heat(call->call_count() - existing_call.call_count()); ++ existing_call.set_call_count(call->call_count()); ++ } ++ else { ++ existing_call.callee().add_heat(call->call_count()); ++ existing_call.set_call_count(existing_call.call_count() + call->call_count()); ++ } ++ return; ++ } ++ } ++ ++ calls->append(*call); ++ call->callee().add_heat(call->call_count()); ++ call->callee().append_call_index(calls->length() - 1); ++} ++ ++// Getting final funcs order from an array of processed clusters ++static GrowableArray* clusters_to_funcs_order(GrowableArray* clusters) { ++ log_debug(jbolt)( "sorted clusters:\n"); ++ for (int i = 0; i < clusters->length(); ++i) { ++ log_debug(jbolt)( "cluster id: %d heats: %ld size: %dB density: %f\n", clusters->at(i).id(), clusters->at(i).heats(), clusters->at(i).size(), clusters->at(i).density()); ++ for (int j = 0; j < clusters->at(i).get_funcs_count(); ++j) { ++ JBoltFunc& func = _funcs->at(clusters->at(i).func_indexes()->at(j)); ++ const Method* const method = JfrMethodLookup::lookup(func.klass(), func.method_id()); ++ if (method != NULL) { ++ log_debug(jbolt)( "%d: method signature:%s heat: %ld size: %dB\n", ++ j, method->external_name(), func.heat(), func.size()); ++ } ++ } ++ } ++ ++ GrowableArray* order = create_growable_array(_funcs->length()); ++ // used to seperator distinct cluster, klass = NULL ++ JBoltFunc seperator_func; ++ order->append(seperator_func); ++ for (int i = 0; i < clusters->length(); ++i) { ++ JBoltCluster& cluster = clusters->at(i); ++ GrowableArray* func_indexes = cluster.func_indexes(); ++ ++ for (int j = 0; j < func_indexes->length(); ++j) { ++ int index = func_indexes->at(j); ++ order->append(_funcs->at(index)); ++ } ++ ++ order->append(seperator_func); ++ } ++ return order; ++} ++ ++// Comparing function needed to sort an array of funcs by their weights (in decreasing order) ++static int func_comparator(JBoltFunc* func1, JBoltFunc* func2) { ++ return func1->heat() < func2->heat(); ++} ++ ++// Comparing cluster needed to sort an array of clusters by their densities (in decreasing order) ++static int cluster_comparator(JBoltCluster* cluster1, JBoltCluster* cluster2) { ++ return _jbolt_density_sort ? (cluster1->density() < cluster2->density()) : (cluster1->heats() < cluster2 -> heats()); ++} ++ ++// Comparing call indexes needed to sort an array of call indexes by their call counts (in decreasing order) ++static int func_call_indexes_comparator(int* index1, int* index2) { ++ return _calls->at(*index1).call_count() < _calls->at(*index2).call_count(); ++} ++ ++JBoltCallGraph& JBoltCallGraph::callgraph_instance() { ++ static JBoltCallGraph _call_graph; ++ return _call_graph; ++} ++ ++void JBoltCallGraph::add_func(JBoltFunc* func) { ++ if (!(UseJBolt && JBoltManager::reorder_phase_is_profiling_or_waiting())) return; ++ JBoltCluster* cluster = find_cluster(func); ++ assert(cluster != NULL, "invariant"); ++} ++ ++void JBoltCallGraph::add_call(JBoltCall* call) { ++ if (!(UseJBolt && JBoltManager::reorder_phase_is_profiling_or_waiting())) return; ++ add_call_to_calls(_calls, call); ++} ++ ++uintptr_t data_layout_jbolt[] = { ++ (uintptr_t)in_bytes(JBoltCluster::id_offset()), ++ (uintptr_t)in_bytes(JBoltCluster::heats_offset()), ++ (uintptr_t)in_bytes(JBoltCluster::frozen_offset()), ++ (uintptr_t)in_bytes(JBoltCluster::size_offset()), ++ (uintptr_t)in_bytes(JBoltCluster::density_offset()), ++ (uintptr_t)in_bytes(JBoltCluster::func_indexes_offset()), ++ ++ (uintptr_t)in_bytes(GrowableArrayView
    ::data_offset()), ++ ++ (uintptr_t)JBoltCluster::find_cluster_by_id, ++ (uintptr_t)_jbolt_merge_frozen ++}; ++ ++static void deal_with_each_func(GrowableArray* clusters, GrowableArray* funcs, GrowableArray* merged) { ++ for (int i = 0; i < funcs->length(); ++i) { ++ JBoltFunc& func = funcs->at(i); ++ ++ JBoltCluster* cluster = JBoltCluster::find_cluster_by_id(clusters, func.cluster_id()); ++ ++ // for cluster size larger than page size, should be frozen and don't merge with any cluster ++ if (_jbolt_merge_frozen && cluster->frozen()) continue; ++ ++ // find best predecessor ++ func.call_indexes()->sort(&func_call_indexes_comparator); ++ ++ int bestPred = -1; ++ ++ for (int j = 0; j < func.call_indexes()->length(); ++j) { ++ const JBoltCall& call = _calls->at(func.call_indexes()->at(j)); ++ ++ bestPred = os::Linux::jboltMerge_judge(data_layout_jbolt, call.caller().cluster_id(), (address)clusters, (address)merged, (address)cluster); ++ ++ if (bestPred == -1) continue; ++ ++ break; ++ } ++ ++ // not merge -- no suitable caller nodes ++ if (bestPred == -1) { ++ continue; ++ } ++ ++ JBoltCluster* predCluster = JBoltCluster::find_cluster_by_id(clusters, bestPred); ++ ++ // merge callee cluster to caller cluster ++ for (int j = 0; j < cluster->func_indexes()->length(); ++j) { ++ int index = cluster->func_indexes()->at(j); ++ predCluster->append_func_index(index); ++ } ++ predCluster->add_heat(cluster->heats()); ++ predCluster->add_size(cluster->size()); ++ predCluster->update_density(); ++ merged->at(cluster->id()) = bestPred; ++ cluster->clear(); ++ } ++} ++ ++// Every node is a cluster with funcs ++// Initially each cluster has only one func inside ++GrowableArray* JBoltCallGraph::hfsort() { ++ if (!(UseJBolt && (JBoltDumpMode || JBoltManager::auto_mode()))) return NULL; ++ log_debug(jbolt)( "hfsort begin...\n"); ++ // Copies are needed for saving initial graph in memory ++ GrowableArray* clusters = clusters_copy(); ++ GrowableArray* funcs = funcs_copy(); ++ ++ // store a map for finding head of merge chain ++ GrowableArray* merged = create_growable_array(clusters->length()); ++ for (int i = 0; i < clusters->length(); ++i) { ++ merged->append(-1); ++ } ++ ++ // sorted by func(initially a node) weight(now just as 'heat') ++ funcs->sort(&func_comparator); ++ ++ // Process each function, and consider merging its cluster with the ++ // one containing its most likely predecessor. ++ deal_with_each_func(clusters, funcs, merged); ++ ++ // the set of clusters that are left ++ GrowableArray* sortedClusters = create_growable_array(); ++ for (int i = 0; i < clusters->length(); ++i) { ++ if (clusters->at(i).id() != -1) { ++ sortedClusters->append(clusters->at(i)); ++ } ++ } ++ ++ sortedClusters->sort(&cluster_comparator); ++ ++ GrowableArray* order = clusters_to_funcs_order(sortedClusters); ++ ++ delete clusters; ++ delete funcs; ++ delete merged; ++ delete sortedClusters; ++ log_debug(jbolt)( "hfsort over...\n"); ++ ++ return order; ++} ++ ++JBoltFunc::JBoltFunc() : ++ _klass(NULL), ++ _method_id(0), ++ _heat(0), ++ _size(0), ++ _cluster_id(-1), ++ _method_key(), ++ _call_indexes(create_growable_array()) {} ++ ++JBoltFunc::JBoltFunc(const JBoltFunc& func) : ++ _klass(func._klass), ++ _method_id(func._method_id), ++ _heat(func._heat), ++ _size(func._size), ++ _cluster_id(func._cluster_id), ++ _method_key(func._method_key), ++ _call_indexes(create_growable_array(func.get_calls_count())) { ++ GrowableArray* array = func.call_indexes(); ++ _call_indexes->appendAll(array); ++ } ++ ++JBoltFunc::JBoltFunc(const InstanceKlass* klass, traceid method_id, int size, JBoltMethodKey method_key) : ++ _klass(klass), ++ _method_id(method_id), ++ _heat(0), ++ _size(size), ++ _cluster_id(-1), ++ _method_key(method_key), ++ _call_indexes(create_growable_array()) { ++ // not new_symbol, need to inc reference cnt ++ _method_key.klass()->increment_refcount(); ++ _method_key.name()->increment_refcount(); ++ _method_key.sig()->increment_refcount(); ++ } ++ ++void JBoltFunc::add_heat(int64_t heat) { ++ _heat += heat; ++ assert(_cluster_id != -1, "invariant"); ++ _clusters->at(_cluster_id).add_heat(heat); ++ _clusters->at(_cluster_id).update_density(); ++} ++ ++void JBoltFunc::set_heat(int64_t heat) { ++ int64_t diff = heat - _heat; ++ _heat = heat; ++ assert(_cluster_id != -1, "invariant"); ++ _clusters->at(_cluster_id).add_heat(diff); ++ _clusters->at(_cluster_id).update_density(); ++} ++ ++void JBoltFunc::set_cluster_id(int cluster_id) { _cluster_id = cluster_id; } ++ ++void JBoltFunc::append_call_index(int index) { _call_indexes->append(index); } ++ ++JBoltFunc* JBoltFunc::constructor(const InstanceKlass* klass, traceid method_id, int size, JBoltMethodKey method_key) { ++ JBoltFunc *ret = new JBoltFunc(klass, method_id, size, method_key); ++ return ret; ++} ++ ++JBoltFunc* JBoltFunc::copy_constructor(const JBoltFunc* func) { ++ JBoltFunc *ret = new JBoltFunc(*func); ++ return ret; ++} ++ ++JBoltCluster::JBoltCluster() : ++ _id(-1), ++ _heats(0), ++ _frozen(false), ++ _size(0), ++ _density(0.0), ++ _func_indexes(create_growable_array()) {} ++ ++JBoltCluster::JBoltCluster(const JBoltFunc& func) : ++ _id(_init_cluster_id++), ++ _heats(func.heat()), ++ _frozen(false), ++ _size(func.size()), ++ _density(0.0), ++ _func_indexes(create_growable_array()) { ++ if (_size >= (int) PAGE_SIZE) ++ freeze(); ++ ++ update_density(); ++ ++ int func_idx = find_func_index(&func); ++ assert(func_idx != -1, "invariant"); ++ _func_indexes->append(func_idx); ++ } ++ ++JBoltCluster::JBoltCluster(const JBoltCluster& cluster) : ++ _id(cluster.id()), ++ _heats(cluster.heats()), ++ _frozen(cluster.frozen()), ++ _size(cluster.size()), ++ _density(cluster.density()), ++ _func_indexes(create_growable_array(cluster.get_funcs_count())) { ++ GrowableArray* array = cluster.func_indexes(); ++ _func_indexes->appendAll(array); ++ } ++ ++void JBoltCluster::add_heat(int64_t heat) { _heats += heat; } ++ ++void JBoltCluster::freeze() { _frozen = true; } ++ ++void JBoltCluster::add_size(int size) { _size += size; } ++ ++void JBoltCluster::update_density() { _density = (double)_heats / (double)_size; } ++ ++void JBoltCluster::append_func_index(int index) { _func_indexes->append(index); } ++ ++void JBoltCluster::clear() { ++ _id = -1; ++ _heats = 0; ++ _frozen = false; ++ _size = 0; ++ _density = 0.0; ++ _func_indexes->clear(); ++} ++ ++// Searching for a cluster by its id ++JBoltCluster* JBoltCluster::find_cluster_by_id(GrowableArray* clusters, u4 id) { ++ if (id >= (u4)clusters->length()) return NULL; ++ ++ return &(clusters->at(id)); ++} ++ ++JBoltCluster* JBoltCluster::constructor(const JBoltFunc* func) { ++ JBoltCluster *ret = new JBoltCluster(*func); ++ return ret; ++} ++ ++JBoltCluster* JBoltCluster::copy_constructor(const JBoltCluster* cluster) { ++ JBoltCluster *ret = new JBoltCluster(*cluster); ++ return ret; ++} ++ ++JBoltCall::JBoltCall() : ++ _caller_index(-1), ++ _callee_index(-1), ++ _call_count(0), ++ _stacktrace_id(0) {} ++ ++JBoltCall::JBoltCall(const JBoltCall& call) : ++ _caller_index(call._caller_index), ++ _callee_index(call._callee_index), ++ _call_count(call._call_count), ++ _stacktrace_id(call._stacktrace_id) {} ++ ++JBoltCall::JBoltCall(const JBoltFunc& caller_func, const JBoltFunc& callee_func, u4 call_count, traceid stacktrace_id) : ++ _call_count(call_count), ++ _stacktrace_id(stacktrace_id) { ++ _caller_index = find_func_index(&caller_func); ++ _callee_index = find_func_index(&callee_func); ++ assert(_caller_index != -1, "invariant"); ++ assert(_callee_index != -1, "invariant"); ++ } ++ ++JBoltFunc& JBoltCall::caller() const { return _funcs->at(_caller_index); } ++ ++JBoltFunc& JBoltCall::callee() const { return _funcs->at(_callee_index); } ++ ++void JBoltCall::set_caller_index(int index) { _caller_index = index; } ++ ++void JBoltCall::set_callee_index(int index) { _callee_index = index; } ++ ++void JBoltCall::set_call_count(u4 call_count) { _call_count = call_count; } ++ ++JBoltCall* JBoltCall::constructor(const JBoltFunc* caller_func, const JBoltFunc* callee_func, u4 call_count, traceid stacktrace_id) { ++ JBoltCall *ret = new JBoltCall(*caller_func, *callee_func, call_count, stacktrace_id); ++ return ret; ++} ++ ++JBoltCall* JBoltCall::copy_constructor(const JBoltCall* call) { ++ JBoltCall *ret = new JBoltCall(*call); ++ return ret; ++} +\ No newline at end of file +diff --git a/src/hotspot/share/jbolt/jBoltCallGraph.hpp b/src/hotspot/share/jbolt/jBoltCallGraph.hpp +new file mode 100644 +index 000000000..93115f3ce +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltCallGraph.hpp +@@ -0,0 +1,277 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLTCALLGRAPH_HPP ++#define SHARE_JBOLT_JBOLTCALLGRAPH_HPP ++ ++#include "jbolt/jbolt_globals.hpp" ++#include "jbolt/jBoltManager.hpp" ++#include "jfr/utilities/jfrTypes.hpp" ++#include "utilities/growableArray.hpp" ++ ++class JBoltFunc; ++class JBoltCall; ++class JBoltCluster; ++ ++template ++static GrowableArray* create_growable_array(int size = 1) { ++ GrowableArray* array = new (mtTracing) GrowableArray(size, mtTracing); ++ assert(array != NULL, "invariant"); ++ return array; ++} ++ ++// initial cluster id ++static u4 _init_cluster_id = 0; ++ ++class JBoltCallGraph : public CHeapObj { ++ private: ++ GrowableArray* _clusters = NULL; ++ GrowableArray* _calls = NULL; ++ GrowableArray* _funcs = NULL; ++ ++ JBoltCallGraph() { ++ _clusters = create_growable_array(); ++ _calls = create_growable_array(); ++ _funcs = create_growable_array(); ++ } ++ ++ JBoltCallGraph(const JBoltCallGraph &) = delete; ++ JBoltCallGraph(const JBoltCallGraph &&) = delete; ++ ++ // for constructing CG ++ void add_func(JBoltFunc* func); // Node ++ void add_call(JBoltCall* call); // Edge ++ ++ public: ++ static JBoltCallGraph& callgraph_instance(); ++ // these two funcs initialize and deinitialize homonymous static array pointers in global ++ static void initialize(); ++ static void deinitialize(); ++ ++ GrowableArray* callgraph_clusters() { return _clusters; } ++ GrowableArray* callgraph_calls() { return _calls; } ++ GrowableArray* callgraph_funcs() { return _funcs; } ++ ++ static void static_add_func(JBoltFunc* func) { callgraph_instance().add_func(func); } ++ static void static_add_call(JBoltCall* call) { callgraph_instance().add_call(call); } ++ ++ // for dealing with CG ++ GrowableArray* hfsort(); ++ ++ int clear_instance(); ++ ++ virtual ~JBoltCallGraph() { ++ delete _clusters; ++ delete _calls; ++ delete _funcs; ++ ++ _clusters = NULL; ++ _calls = NULL; ++ _funcs = NULL; ++ } ++}; ++ ++class JBoltFunc : public CHeapObj { ++ private: ++ const InstanceKlass* _klass; ++ traceid _method_id; ++ int64_t _heat; ++ int _size; ++ int _cluster_id; ++ JBoltMethodKey _method_key; ++ GrowableArray* _call_indexes; ++ ++ public: ++ JBoltFunc(); ++ JBoltFunc(const JBoltFunc& func); ++ JBoltFunc(const InstanceKlass* klass, traceid method_id, int size, JBoltMethodKey method_key); ++ ++ virtual ~JBoltFunc() { ++ delete _call_indexes; ++ } ++ ++ bool operator==(const JBoltFunc& func) const { return (_klass == func._klass && _method_id == func._method_id) || (_method_key.equals(func._method_key)); } ++ bool operator!=(const JBoltFunc& func) const { return (_klass != func._klass || _method_id != func._method_id) && !(_method_key.equals(func._method_key)); } ++ ++ JBoltFunc& operator=(const JBoltFunc& func) { ++ _klass = func._klass; ++ _method_id = func._method_id; ++ _heat = func._heat; ++ _size = func._size; ++ _cluster_id = func._cluster_id; ++ _method_key = func._method_key; ++ if (_call_indexes != nullptr) { ++ delete _call_indexes; ++ } ++ _call_indexes = create_growable_array(func.get_calls_count()); ++ _call_indexes->appendAll(func.call_indexes()); ++ ++ return *this; ++ } ++ ++ const InstanceKlass* klass() const { return _klass; } ++ const traceid method_id() const { return _method_id; } ++ const int64_t heat() const { return _heat; } ++ const int size() const { return _size; } ++ const int cluster_id() const { return _cluster_id; } ++ JBoltMethodKey method_key() const { return _method_key; } ++ GrowableArray* call_indexes() const { return _call_indexes; } ++ int get_calls_count() const { return _call_indexes->length(); } ++ ++ void add_heat(int64_t heat); ++ void set_heat(int64_t heat); ++ void set_cluster_id(int cluster_id); ++ void append_call_index(int index); ++ ++ static ByteSize klass_offset() { return byte_offset_of(JBoltFunc, _klass); } ++ static ByteSize method_id_offset() { return byte_offset_of(JBoltFunc, _method_id); } ++ static ByteSize heat_offset() { return byte_offset_of(JBoltFunc, _heat); } ++ static ByteSize size_offset() { return byte_offset_of(JBoltFunc, _size); } ++ static ByteSize cluster_id_offset() { return byte_offset_of(JBoltFunc, _cluster_id); } ++ static ByteSize call_indexes_offset() { return byte_offset_of(JBoltFunc, _call_indexes); } ++ ++ static JBoltFunc* constructor(const InstanceKlass* klass, traceid method_id, int size, JBoltMethodKey method_key); ++ static JBoltFunc* copy_constructor(const JBoltFunc* func); ++}; ++ ++class JBoltCluster : public CHeapObj { ++ private: ++ int _id; ++ int64_t _heats; ++ bool _frozen; ++ int _size; ++ double _density; ++ GrowableArray* _func_indexes; ++ ++ public: ++ JBoltCluster(); ++ JBoltCluster(const JBoltFunc& func); ++ JBoltCluster(const JBoltCluster& cluster); ++ ++ bool operator==(const JBoltCluster& cluster) const { ++ if (_id != cluster.id()) return false; ++ ++ int count = get_funcs_count(); ++ if (count != cluster.get_funcs_count()) ++ return false; ++ ++ for (int i = 0; i < count; ++i) { ++ if (_func_indexes->at(i) != cluster._func_indexes->at(i)) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ ++ JBoltCluster& operator=(const JBoltCluster& cluster) { ++ _id = cluster.id(); ++ _heats = cluster.heats(); ++ _frozen = cluster.frozen(); ++ _size = cluster.size(); ++ _density = cluster.density(); ++ if (_func_indexes != nullptr) { ++ delete _func_indexes; ++ } ++ _func_indexes = create_growable_array(cluster.get_funcs_count()); ++ _func_indexes->appendAll(cluster.func_indexes()); ++ return *this; ++ } ++ ++ virtual ~JBoltCluster() { delete _func_indexes; } ++ ++ int id() const { return _id; } ++ int64_t heats() const { return _heats; } ++ bool frozen() const { return _frozen; } ++ int size() const { return _size; } ++ double density() const { return _density; } ++ GrowableArray* func_indexes() const { return _func_indexes; } ++ int get_funcs_count() const { return _func_indexes->length(); } ++ ++ void add_heat(int64_t heat); ++ void freeze(); ++ void add_size(int size); ++ void update_density(); ++ void append_func_index(int index); ++ void clear(); ++ ++ static JBoltCluster* find_cluster_by_id(GrowableArray* clusters, u4 id); ++ ++ static ByteSize id_offset() { return byte_offset_of(JBoltCluster, _id); } ++ static ByteSize heats_offset() { return byte_offset_of(JBoltCluster, _heats); } ++ static ByteSize frozen_offset() { return byte_offset_of(JBoltCluster, _frozen); } ++ static ByteSize size_offset() { return byte_offset_of(JBoltCluster, _size); } ++ static ByteSize density_offset() { return byte_offset_of(JBoltCluster, _density); } ++ static ByteSize func_indexes_offset() { return byte_offset_of(JBoltCluster, _func_indexes); } ++ ++ static JBoltCluster* constructor(const JBoltFunc* func); ++ static JBoltCluster* copy_constructor(const JBoltCluster* cluster); ++}; ++ ++class JBoltCall : public CHeapObj { ++ private: ++ int _caller_index; ++ int _callee_index; ++ u4 _call_count; ++ traceid _stacktrace_id; ++ ++ public: ++ JBoltCall(); ++ JBoltCall(const JBoltCall& call); ++ JBoltCall(const JBoltFunc& caller_func, const JBoltFunc& callee_func, u4 call_count, traceid stacktrace_id); ++ ++ bool operator==(const JBoltCall& call) const { ++ return _caller_index == call._caller_index && _callee_index == call._callee_index; ++ } ++ ++ JBoltCall& operator=(const JBoltCall& call) { ++ _caller_index = call._caller_index; ++ _callee_index = call._callee_index; ++ _call_count = call._call_count; ++ _stacktrace_id = call._stacktrace_id; ++ return *this; ++ } ++ ++ virtual ~JBoltCall() {} ++ ++ int caller_index() const { return _caller_index; } ++ int callee_index() const { return _callee_index; } ++ u4 call_count() const { return _call_count; } ++ traceid stacktrace_id() const { return _stacktrace_id; } ++ ++ JBoltFunc& caller() const; ++ JBoltFunc& callee() const; ++ void set_caller_index(int index); ++ void set_callee_index(int index); ++ void set_call_count(u4 count); ++ ++ static ByteSize caller_offset() { return byte_offset_of(JBoltCall, _caller_index); } ++ static ByteSize callee_offset() { return byte_offset_of(JBoltCall, _caller_index); } ++ static ByteSize call_count_offset() { return byte_offset_of(JBoltCall, _call_count); } ++ static ByteSize stacktrace_id_offset() { return byte_offset_of(JBoltCall, _stacktrace_id); } ++ ++ static JBoltCall* constructor(const JBoltFunc* caller_func, const JBoltFunc* callee_func, u4 call_count, traceid stacktrace_id); ++ static JBoltCall* copy_constructor(const JBoltCall* call); ++}; ++ ++#endif // SHARE_JBOLT_JBOLTCALLGRAPH_HPP +diff --git a/src/hotspot/share/jbolt/jBoltControlThread.cpp b/src/hotspot/share/jbolt/jBoltControlThread.cpp +new file mode 100644 +index 000000000..dc42ca77b +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltControlThread.cpp +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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 "classfile/javaClasses.inline.hpp" ++#include "classfile/vmClasses.hpp" ++#include "classfile/vmSymbols.hpp" ++#include "jbolt/jBoltControlThread.hpp" ++#include "jbolt/jBoltManager.hpp" ++#include "logging/log.hpp" ++#include "logging/logStream.hpp" ++#include "runtime/atomic.hpp" ++#include "runtime/handles.inline.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/handles.inline.hpp" ++#include "runtime/javaCalls.hpp" ++#include "runtime/jniHandles.inline.hpp" ++#include "runtime/thread.inline.hpp" ++ ++JavaThread* volatile JBoltControlThread::_the_java_thread = nullptr; ++Monitor* JBoltControlThread::_control_wait_monitor = nullptr; ++Monitor* JBoltControlThread::_sample_wait_monitor = nullptr; ++jobject JBoltControlThread::_thread_obj = nullptr; ++int volatile JBoltControlThread::_signal = JBoltControlThread::SIG_NULL; ++bool volatile JBoltControlThread::_abort = false; ++intx volatile JBoltControlThread::_interval = 0; ++ ++static bool not_first = false; ++ ++void JBoltControlThread::init(TRAPS) { ++ Handle string = java_lang_String::create_from_str("JBolt Control", CATCH); ++ Handle thread_group(THREAD, Universe::system_thread_group()); ++ Handle thread_oop = JavaCalls::construct_new_instance( ++ vmClasses::Thread_klass(), ++ vmSymbols::threadgroup_string_void_signature(), ++ thread_group, ++ string, ++ CATCH); ++ _thread_obj = JNIHandles::make_global(thread_oop); ++ _control_wait_monitor = new Monitor(Mutex::safepoint - 1, "JBoltControlMonitor"); ++ _sample_wait_monitor = new Monitor(Mutex::safepoint - 1, "JBoltSampleMonitor"); ++ Atomic::release_store(&_interval, JBoltSampleInterval); ++} ++ ++void JBoltControlThread::start_thread(TRAPS) { ++ guarantee(Atomic::load_acquire(&_the_java_thread) == nullptr, "sanity"); ++ JavaThread* new_thread = new JavaThread(&thread_entry); ++ if (new_thread->osthread() == nullptr) { ++ fatal("Failed to create JBoltControlThread as no os thread!"); ++ return; ++ } ++ ++ Handle thread_oop(THREAD, JNIHandles::resolve_non_null(_thread_obj)); ++ JavaThread::start_internal_daemon(THREAD, new_thread, thread_oop, MinPriority); ++ guarantee(Atomic::cmpxchg(&_the_java_thread, (JavaThread*) nullptr, new_thread) == nullptr, "sanity"); ++} ++ ++intx JBoltControlThread::sample_interval() { ++ return Atomic::load_acquire(&_interval); ++} ++ ++// Work to do before restarting a control schedule, twice and after only ++bool JBoltControlThread::prev_control_schdule(TRAPS) { ++ guarantee(JBoltManager::auto_mode(), "sanity"); ++ // Clear obsolete data structures ++ if (JBoltManager::clear_last_sample_datas() != 0) { ++ log_error(jbolt)("Something wrong happened in data clean, not going on..."); ++ return false; ++ } ++ ++ // Restart JFR ++ bufferedStream output; ++ DCmd::parse_and_execute(DCmd_Source_Internal, &output, "JFR.start name=jbolt-jfr", ' ', THREAD); ++ if (HAS_PENDING_EXCEPTION) { ++ ResourceMark rm; ++ log_warning(jbolt)("unable to start jfr jbolt-jfr"); ++ log_warning(jbolt)("exception type: %s", PENDING_EXCEPTION->klass()->external_name()); ++ // don't unwind this exception ++ CLEAR_PENDING_EXCEPTION; ++ } ++ ++ return true; ++} ++ ++void JBoltControlThread::control_schdule(TRAPS) { ++ guarantee(JBoltManager::auto_mode(), "sanity"); ++ { MonitorLocker locker(_sample_wait_monitor); ++ // Perform time wait ++ log_info(jbolt)("JBolt Starting Sample for %lds!!!", sample_interval()); ++ const jlong interval = (jlong) sample_interval(); ++ jlong cur_time = os::javaTimeMillis(); ++ const jlong end_time = cur_time + (interval * 1000); ++ while ((end_time > cur_time) && Atomic::load_acquire(&_signal) != SIG_STOP_PROFILING) { ++ int64_t timeout = (int64_t) (end_time - cur_time); ++ locker.wait(timeout); ++ cur_time = os::javaTimeMillis(); ++ } ++ } ++ // Close JFR ++ guarantee(JBoltManager::reorder_phase_profiling_to_waiting(), "sanity"); ++ bufferedStream output; ++ DCmd::parse_and_execute(DCmd_Source_Internal, &output, "JFR.stop name=jbolt-jfr", ' ', THREAD); ++ if (HAS_PENDING_EXCEPTION) { ++ ResourceMark rm; ++ // JFR.stop maybe failed if a jfr recording is already stopped ++ // but it's nothing worry, jbolt should continue to work normally ++ log_warning(jbolt)("unable to stop jfr jbolt-jfr"); ++ log_warning(jbolt)("exception type: %s", PENDING_EXCEPTION->klass()->external_name()); ++ // don't unwind this exception ++ CLEAR_PENDING_EXCEPTION; ++ } ++ if (Atomic::cmpxchg(&_abort, true, false) == /* should abort */ true) { ++ return; ++ } ++ ++ size_t total_nmethod_size = 0; ++ // Init structures for load phase ++ JBoltManager::init_auto_transition(&total_nmethod_size, CATCH); ++ ++ if (total_nmethod_size > JBoltCodeHeapSize) { ++ log_warning(jbolt)("JBolt reordering not complete because JBolt CodeHeap is too small to place all ordered methods. Please use -XX:JBoltCodeHeapSize to enlarge"); ++ log_warning(jbolt)("JBoltCodeHeapSize=" UINTX_FORMAT " B ( need " UINTX_FORMAT " B).", JBoltCodeHeapSize, total_nmethod_size); ++ } ++ ++ if (not_first) { ++ // Exchange Hot Segment primary and secondary relationships ++ JBoltManager::swap_semi_jbolt_segs(); ++ } ++ ++ guarantee(JBoltManager::reorder_phase_waiting_to_reordering(), "sanity"); ++ Atomic::release_store(&_signal, SIG_NULL); ++ ++ // Start reorder ++ JBoltManager::reorder_all_methods(CATCH); ++} ++ ++// Work to do after reordering, twice and after only ++void JBoltControlThread::post_control_schdule(TRAPS) { ++ JBoltManager::clear_secondary_hot_seg(THREAD); ++} ++ ++void JBoltControlThread::thread_run(TRAPS) { ++ if (JBoltManager::auto_mode()) { ++ do { ++ Atomic::release_store(&_signal, SIG_NULL); ++ if (not_first && !prev_control_schdule(THREAD)) continue; ++ guarantee(JBoltManager::reorder_phase_available_to_profiling(), "sanity"); ++ control_schdule(THREAD); ++ if (!JBoltManager::reorder_phase_reordering_to_available()) { ++ // abort logic ++ guarantee(JBoltManager::reorder_phase_waiting_to_available(), "sanity"); ++ guarantee(Atomic::cmpxchg(&_signal, SIG_STOP_PROFILING, SIG_NULL) == SIG_STOP_PROFILING, "sanity"); ++ } ++ else if (not_first) { ++ post_control_schdule(THREAD); ++ } ++ not_first = true; ++ MonitorLocker locker(_control_wait_monitor); ++ while (Atomic::load_acquire(&_signal) != SIG_START_PROFILING) { ++ locker.wait(60 * 1000); ++ } ++ JBoltManager::clear_structures(); ++ } while(true); ++ } else { ++ guarantee(JBoltManager::can_reorder_now(), "sanity"); ++ guarantee(JBoltManager::reorder_phase_collecting_to_reordering(), "sanity"); ++ JBoltManager::reorder_all_methods(CATCH); ++ JBoltManager::clear_structures(); ++ guarantee(JBoltManager::reorder_phase_reordering_to_end(), "sanity"); ++ assert(JBoltLoadMode, "Only manual JBoltLoadMode can reach here"); ++ } ++} ++ ++bool JBoltControlThread::notify_sample_wait(bool abort) { ++ int old_sig = Atomic::cmpxchg(&_signal, SIG_NULL, SIG_STOP_PROFILING); ++ if (old_sig == SIG_NULL) { ++ MonitorLocker locker(_sample_wait_monitor); ++ // abort implementation maybe not in order in extreme cases ++ // add fence? or delete abort() if not so useful. ++ Atomic::release_store(&_abort, abort); ++ locker.notify(); ++ return true; ++ } ++ return false; ++} ++ ++bool JBoltControlThread::notify_control_wait(intx interval) { ++ int old_sig = Atomic::cmpxchg(&_signal, SIG_NULL, SIG_START_PROFILING); ++ if (old_sig == SIG_NULL) { ++ // this lock will be grabbed by ControlThread until it's waiting ++ MonitorLocker locker(_control_wait_monitor); ++ Atomic::release_store(&_interval, interval); ++ locker.notify(); ++ return true; ++ } ++ return false; ++} ++ ++JavaThread* JBoltControlThread::get_thread() { ++ return Atomic::load_acquire(&_the_java_thread); ++} +diff --git a/src/hotspot/share/jbolt/jBoltControlThread.hpp b/src/hotspot/share/jbolt/jBoltControlThread.hpp +new file mode 100644 +index 000000000..e63dd1ea9 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltControlThread.hpp +@@ -0,0 +1,69 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLTCONTROLTHREAD_HPP ++#define SHARE_JBOLT_JBOLTCONTROLTHREAD_HPP ++ ++#include "runtime/thread.hpp" ++ ++/** ++ * Control JBolt how to run in this thread. ++ */ ++class JBoltControlThread : public AllStatic { ++public: ++ static const int SIG_NULL = 0; ++ static const int SIG_START_PROFILING = 1; ++ static const int SIG_STOP_PROFILING = 2; ++ ++private: ++ static JavaThread* volatile _the_java_thread; ++ // Can be notified by jcmd JBolt.start, restart a control schedule ++ static Monitor* _control_wait_monitor; ++ // Can be notified by jcmd JBolt.stop/abort, stop a running JFR ++ static Monitor* _sample_wait_monitor; ++ static jobject _thread_obj; ++ static int volatile _signal; ++ static bool volatile _abort; ++ static intx volatile _interval; ++ ++ static void thread_entry(JavaThread* thread, TRAPS) { thread_run(thread); } ++ static void thread_run(TRAPS); ++ ++ static intx sample_interval(); ++ static bool prev_control_schdule(TRAPS); ++ static void control_schdule(TRAPS); ++ static void post_control_schdule(TRAPS); ++ ++public: ++ static void init(TRAPS); ++ ++ static void start_thread(TRAPS); ++ ++ static bool notify_sample_wait(bool abort = false); ++ ++ static bool notify_control_wait(intx interval); ++ ++ static JavaThread* get_thread(); ++}; ++ ++#endif // SHARE_JBOLT_JBOLTCONTROLTHREAD_HPP +diff --git a/src/hotspot/share/jbolt/jBoltDcmds.cpp b/src/hotspot/share/jbolt/jBoltDcmds.cpp +new file mode 100644 +index 000000000..0cf1c75b4 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltDcmds.cpp +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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 "jbolt/jBoltDcmds.hpp" ++#include "jbolt/jBoltControlThread.hpp" ++#include "jbolt/jBoltManager.hpp" ++ ++bool register_jbolt_dcmds() { ++ uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ return true; ++} ++ ++JBoltStartDCmd::JBoltStartDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), ++ _duration("duration", "Duration of time(second) in this sample.", "INT", false, "600") { ++ _dcmdparser.add_dcmd_option(&_duration); ++} ++ ++int JBoltStartDCmd::num_arguments() { ++ ResourceMark rm; ++ JBoltStartDCmd* dcmd = new JBoltStartDCmd(NULL, false); ++ if (dcmd != NULL) { ++ DCmdMark mark(dcmd); ++ return dcmd->_dcmdparser.num_arguments(); ++ } else { ++ return 0; ++ } ++} ++ ++void JBoltStartDCmd::execute(DCmdSource source, TRAPS) { ++ if (!UseJBolt) { ++ output()->print_cr("Unable to execute because \"UseJBolt\" is disabled."); ++ return; ++ } ++ ++ if (!JBoltManager::auto_mode()) { ++ output()->print_cr("JBolt JCMD can only be used in auto mode."); ++ return; ++ } ++ ++ if (!JBoltManager::reorder_phase_is_available()) { ++ output()->print_cr("Unable to start because it's working now. Stop it first."); ++ return; ++ } ++ ++ intx interval = _duration.is_set() ? _duration.value() : JBoltSampleInterval; ++ ++ if (interval < 0) { ++ output()->print_cr("duration is set to %ld which is above range, should be in [0, %d]", interval, max_jint); ++ return; ++ } ++ ++ if (JBoltControlThread::notify_control_wait(interval)) { ++ output()->print_cr("OK. Start a new JBolt schedule, duration=%lds.", interval); ++ } ++ else { ++ output()->print_cr("It's busy now. Please try again later..."); ++ } ++} ++ ++void JBoltStartDCmd::print_help(const char* name) const { ++ output()->print_cr( ++ "Syntax : %s [options]\n" ++ "\n" ++ "Options:\n" ++ "\n" ++ " duration (Optional) Duration of time(second) in this sample. (INT, default value=600)\n" ++ "\n" ++ "Options must be specified using the or = syntax.\n" ++ "\n" ++ "Example usage:\n" ++ " $ jcmd JBolt.start\n" ++ " $ jcmd JBolt.start duration=900", name); ++} ++ ++void JBoltStopDCmd::execute(DCmdSource source, TRAPS) { ++ if (!UseJBolt) { ++ output()->print_cr("Unable to execute because \"UseJBolt\" is disabled."); ++ return; ++ } ++ ++ if (!JBoltManager::auto_mode()) { ++ output()->print_cr("JBolt JCMD can only be used in auto mode."); ++ return; ++ } ++ ++ if (!JBoltManager::reorder_phase_is_profiling()) { ++ output()->print_cr("Unable to stop because it's not sampling now."); ++ return; ++ } ++ ++ if (JBoltControlThread::notify_sample_wait()) { ++ output()->print_cr("OK.\"jbolt-jfr\" would be stopped and turn to reorder."); ++ } else { ++ output()->print_cr("It's busy now. Please try again later..."); ++ } ++} ++ ++void JBoltStopDCmd::print_help(const char* name) const { ++ output()->print_cr( ++ "Syntax : %s\n" ++ "\n" ++ "Example usage:\n" ++ " $ jcmd JBolt.stop", name); ++} ++ ++void JBoltAbortDCmd::execute(DCmdSource source, TRAPS) { ++ if (!UseJBolt) { ++ output()->print_cr("Unable to execute because \"UseJBolt\" is disabled."); ++ return; ++ } ++ ++ if (!JBoltManager::auto_mode()) { ++ output()->print_cr("JBolt JCMD can only be used in auto mode."); ++ return; ++ } ++ ++ if (!JBoltManager::reorder_phase_is_profiling()) { ++ output()->print_cr("Unable to abort because it's not sampling now."); ++ return; ++ } ++ ++ if (JBoltControlThread::notify_sample_wait(true)) { ++ output()->print_cr("OK.\"jbolt-jfr\" would be aborted."); ++ } else { ++ output()->print_cr("It's busy now. Please try again later..."); ++ } ++} ++ ++void JBoltAbortDCmd::print_help(const char* name) const { ++ output()->print_cr( ++ "Syntax : %s\n" ++ "\n" ++ "Example usage:\n" ++ " $ jcmd JBolt.abort", name); ++} ++ ++JBoltDumpDCmd::JBoltDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), ++ _filename("filename", "Name of the file to which the flight recording data is dumped", "STRING", true, NULL) { ++ _dcmdparser.add_dcmd_option(&_filename); ++} ++ ++int JBoltDumpDCmd::num_arguments() { ++ ResourceMark rm; ++ JBoltDumpDCmd* dcmd = new JBoltDumpDCmd(NULL, false); ++ if (dcmd != NULL) { ++ DCmdMark mark(dcmd); ++ return dcmd->_dcmdparser.num_arguments(); ++ } else { ++ return 0; ++ } ++} ++ ++void JBoltDumpDCmd::execute(DCmdSource source, TRAPS) { ++ if (!UseJBolt) { ++ output()->print_cr("Unable to execute because \"UseJBolt\" is disabled."); ++ return; ++ } ++ ++ if (!JBoltManager::auto_mode()) { ++ output()->print_cr("JBolt JCMD can only be used in auto mode."); ++ return; ++ } ++ ++ const char* path = _filename.value(); ++ char buffer[PATH_MAX]; ++ char* rp = NULL; ++ ++ JBoltErrorCode ec = JBoltManager::dump_order_in_jcmd(path); ++ switch (ec) { ++ case JBoltOrderNULL: ++ output()->print_cr("Failed: No order applied by JBolt now."); ++ break; ++ case JBoltOpenFileError: ++ output()->print_cr("Failed: File open error or NULL: %s", path); ++ break; ++ case JBoltOK: ++ rp = realpath(path, buffer); ++ output()->print_cr("Successful: Dump to %s", buffer); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++} ++ ++void JBoltDumpDCmd::print_help(const char* name) const { ++ output()->print_cr( ++ "Syntax : %s [options]\n" ++ "\n" ++ "Options:\n" ++ "\n" ++ " filename Name of the file to which the flight recording data is dumped. (STRING, no default value)\n" ++ "\n" ++ "Options must be specified using the or = syntax.\n" ++ "\n" ++ "Example usage:\n" ++ " $ jcmd JBolt.dump filename=order.log", name); ++} +\ No newline at end of file +diff --git a/src/hotspot/share/jbolt/jBoltDcmds.hpp b/src/hotspot/share/jbolt/jBoltDcmds.hpp +new file mode 100644 +index 000000000..f73fc01e6 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltDcmds.hpp +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLTDCMDS_HPP ++#define SHARE_JBOLT_JBOLTDCMDS_HPP ++ ++#include "services/diagnosticCommand.hpp" ++ ++class JBoltStartDCmd : public DCmdWithParser { ++ protected: ++ DCmdArgument _duration; ++ public: ++ JBoltStartDCmd(outputStream* output, bool heap); ++ ++ static const char* name() { ++ return "JBolt.start"; ++ } ++ static const char* description() { ++ return "Starts a new JBolt sample schedule(fail if sampling)"; ++ } ++ static const char* impact() { ++ return "Medium: Depending on JFR that JBolt rely on, the impact can range from low to high."; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", "control", NULL}; ++ return p; ++ } ++ static int num_arguments(); ++ virtual void execute(DCmdSource source, TRAPS); ++ virtual void print_help(const char* name) const; ++}; ++ ++class JBoltStopDCmd : public DCmd { ++ public: ++ JBoltStopDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} ++ ++ static const char* name() { ++ return "JBolt.stop"; ++ } ++ static const char* description() { ++ return "Stop a running JBolt sample schedule and reorder immediately(fail if not sampling)"; ++ } ++ static const char* impact() { ++ return "Low"; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", "control", NULL}; ++ return p; ++ } ++ static int num_arguments() { ++ return 0; ++ } ++ ++ virtual void execute(DCmdSource source, TRAPS); ++ virtual void print_help(const char* name) const; ++}; ++ ++class JBoltAbortDCmd : public DCmd { ++ public: ++ JBoltAbortDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} ++ ++ static const char* name() { ++ return "JBolt.abort"; ++ } ++ static const char* description() { ++ return "Stop a running JBolt sample schedule but don't reorder(fail if not sampling)"; ++ } ++ static const char* impact() { ++ return "Low"; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL}; ++ return p; ++ } ++ static int num_arguments() { ++ return 0; ++ } ++ ++ virtual void execute(DCmdSource source, TRAPS); ++ virtual void print_help(const char* name) const; ++}; ++ ++class JBoltDumpDCmd : public DCmdWithParser { ++ protected: ++ DCmdArgument _filename; ++ public: ++ JBoltDumpDCmd(outputStream* output, bool heap); ++ ++ static const char* name() { ++ return "JBolt.dump"; ++ } ++ static const char* description() { ++ return "dump an effective order to file(fail if no order)"; ++ } ++ static const char* impact() { ++ return "Low"; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL}; ++ return p; ++ } ++ static int num_arguments(); ++ virtual void execute(DCmdSource source, TRAPS); ++ virtual void print_help(const char* name) const; ++}; ++ ++bool register_jbolt_dcmds(); ++ ++#endif // SHARE_JBOLT_JBOLTDCMDS_HPP +\ No newline at end of file +diff --git a/src/hotspot/share/jbolt/jBoltManager.cpp b/src/hotspot/share/jbolt/jBoltManager.cpp +new file mode 100644 +index 000000000..4cb6f4d1a +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltManager.cpp +@@ -0,0 +1,1429 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++ ++#include "classfile/javaClasses.inline.hpp" ++#include "classfile/symbolTable.hpp" ++#include "classfile/vmSymbols.hpp" ++#include "code/codeBlob.hpp" ++#include "code/codeCache.hpp" ++#include "compiler/compileBroker.hpp" ++#include "compiler/compilerDefinitions.inline.hpp" ++#include "jbolt/jBoltCallGraph.hpp" ++#include "jbolt/jBoltControlThread.hpp" ++#include "jbolt/jBoltManager.hpp" ++#include "jbolt/jBoltUtils.inline.hpp" ++#include "jfr/jfr.hpp" ++#include "jfr/support/jfrMethodLookup.hpp" ++#include "logging/log.hpp" ++#include "logging/logStream.hpp" ++#include "memory/resourceArea.hpp" ++#include "memory/universe.hpp" ++#include "oops/klass.inline.hpp" ++#include "oops/method.inline.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/atomic.hpp" ++#include "runtime/globals_extension.hpp" ++#include "runtime/handles.inline.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/jniHandles.hpp" ++#include "runtime/os.hpp" ++#include "runtime/safepointVerifiers.hpp" ++#include "utilities/formatBuffer.hpp" ++#ifdef LINUX ++#include "os_linux.hpp" ++#endif ++ ++static constexpr int LINE_BUF_SIZE = 8192; // used to parse JBolt order file ++static constexpr int MIN_FRAMESCOUNT = 2; // used as default stacktrace depth ++static constexpr int ILL_NM_STATE = -2; // used to present nmethod illegal state ++ ++#define B_TF(b) (b ? "V" : "X") ++ ++GrowableArray* JBoltManager::_hot_methods_sorted = nullptr; ++JBoltManager::MethodKeyMap* JBoltManager::_hot_methods_vis = nullptr; ++int JBoltManager::_reorder_method_threshold_cnt = 0; ++ ++volatile int JBoltManager::_reorder_phase = JBoltReorderPhase::Available; ++volatile int JBoltManager::_reorderable_method_cnt = 0; ++Method* volatile JBoltManager::_cur_reordering_method = nullptr; ++ ++Thread* JBoltManager::_start_reordering_thread = nullptr; ++ ++JBoltManager::StackFrameKeyMap* JBoltManager::_sampled_methods_refs = nullptr; ++ ++bool JBoltManager::_auto_mode = false; ++ ++// swap between MethodJBoltHot and MethodJBoltTmp ++volatile int JBoltManager::_primary_hot_seg = int(CodeBlobType::MethodJBoltHot); ++volatile int JBoltManager::_secondary_hot_seg = int(CodeBlobType::MethodJBoltTmp); ++ ++volatile int JBoltManager::_gc_should_sweep_code_heaps_now = 0; ++ ++GrowableArray* _order_stored = nullptr; ++ ++// This is a tmp obj used only in initialization phases. ++// We cannot alloc Symbol in phase 1 so we have to parses the order file again ++// in phase 2. ++// This obj will be freed after initialization. ++static FILE* _order_fp = nullptr; ++ ++// The threshold to trigger JBolt reorder in load mode. ++static const double _jbolt_reorder_threshold = 0.8; ++ ++static bool read_line(FILE* fp, char* buf, int buf_len, int* res_len) { ++ if (fgets(buf, buf_len, fp) == nullptr) { ++ return false; ++ } ++ int len = (int) strcspn(buf, "\r\n"); ++ buf[len] = '\0'; ++ *res_len = len; ++ return true; ++} ++ ++static bool read_a_size(char* buf, size_t* res) { ++ char* t = strchr(buf, ' '); ++ if (t == nullptr) return false; ++ *t = '\0'; ++ julong v; ++ if (!Arguments::atojulong(buf, &v)) { ++ *t = ' '; ++ return false; ++ } ++ *t = ' '; ++ *res = (size_t) v; ++ return true; ++} ++ ++static void replace_all(char* s, char from, char to) { ++ char* begin = s; ++ while (true) { ++ char* t = strchr(begin, from); ++ if (t == nullptr) { ++ break; ++ } ++ *t = to; ++ begin = t + 1; ++ } ++} ++ ++JBoltMethodValue::~JBoltMethodValue() { ++ if (_comp_info != nullptr) delete get_comp_info(); ++} ++ ++CompileTaskInfo* JBoltMethodValue::get_comp_info() { ++ return Atomic::load_acquire(&_comp_info); ++} ++ ++bool JBoltMethodValue::set_comp_info(CompileTaskInfo* info) { ++ return Atomic::cmpxchg(&_comp_info, (CompileTaskInfo*) nullptr, info) == nullptr; ++} ++ ++void JBoltMethodValue::clear_comp_info_but_not_release() { ++ Atomic::release_store(&_comp_info, (CompileTaskInfo*) nullptr); ++} ++ ++JBoltStackFrameValue::~JBoltStackFrameValue() { ++ if (_method_holder != nullptr) { ++ if (JNIHandles::is_weak_global_handle(_method_holder)) { ++ JNIHandles::destroy_weak_global(_method_holder); ++ } else { ++ JNIHandles::destroy_global(_method_holder); ++ } ++ } ++} ++ ++jobject JBoltStackFrameValue::get_method_holder() { return _method_holder; } ++ ++void JBoltStackFrameValue::clear_method_holder_but_not_release() { _method_holder = nullptr; } ++ ++CompileTaskInfo::CompileTaskInfo(Method* method, int osr_bci, int comp_level, int comp_reason, Method* hot_method, int hot_cnt): ++ _method(method), _osr_bci(osr_bci), _comp_level(comp_level), _comp_reason(comp_reason), _hot_method(hot_method), _hot_count(hot_cnt) { ++ Thread* thread = Thread::current(); ++ ++ assert(_method != nullptr, "sanity"); ++ // _method_holder can be null for boot loader (the null loader) ++ _method_holder = JNIHandles::make_weak_global(Handle(thread, _method->method_holder()->klass_holder())); ++ ++ if (_hot_method != nullptr && _hot_method != _method) { ++ _hot_method_holder = JNIHandles::make_weak_global(Handle(thread, _hot_method->method_holder()->klass_holder())); ++ } else { ++ _hot_method_holder = nullptr; ++ } ++} ++ ++CompileTaskInfo::~CompileTaskInfo() { ++ if (_method_holder != nullptr) { ++ if (JNIHandles::is_weak_global_handle(_method_holder)) { ++ JNIHandles::destroy_weak_global(_method_holder); ++ } else { ++ JNIHandles::destroy_global(_method_holder); ++ } ++ } ++ if (_hot_method_holder != nullptr) { ++ if (JNIHandles::is_weak_global_handle(_hot_method_holder)) { ++ JNIHandles::destroy_weak_global(_hot_method_holder); ++ } else { ++ JNIHandles::destroy_global(_hot_method_holder); ++ } ++ } ++} ++ ++/** ++ * Set the weak reference to strong reference if the method is not unloaded. ++ * It seems that the life cycle of Method is consistent with that of the Klass and CLD. ++ * @see CompileTask::select_for_compilation() ++ */ ++bool CompileTaskInfo::try_select() { ++ NoSafepointVerifier nsv; ++ Thread* thread = Thread::current(); ++ // is unloaded ++ if (_method_holder != nullptr && JNIHandles::is_weak_global_handle(_method_holder) && JNIHandles::is_weak_global_cleared(_method_holder)) { ++ if (log_is_enabled(Debug, jbolt)) { ++ log_debug(jbolt)("Some method has been unloaded so skip reordering for it: p=%p.", _method); ++ } ++ return false; ++ } ++ ++ assert(_method->method_holder()->is_loader_alive(), "should be alive"); ++ Handle method_holder(thread, _method->method_holder()->klass_holder()); ++ JNIHandles::destroy_weak_global(_method_holder); ++ _method_holder = JNIHandles::make_global(method_holder); ++ ++ if (_hot_method_holder != nullptr) { ++ Handle hot_method_holder(thread, _hot_method->method_holder()->klass_holder()); ++ JNIHandles::destroy_weak_global(_hot_method_holder); ++ _hot_method_holder = JNIHandles::make_global(Handle(thread, _hot_method->method_holder()->klass_holder())); ++ } ++ return true; ++} ++ ++static void check_arg_not_set(JVMFlagsEnum flag) { ++ if (JVMFlag::is_cmdline(flag)) { ++ vm_exit_during_initialization(err_msg("Do not set VM option %s without UseJBolt enabled.", ++ JVMFlag::flag_from_enum(flag)->name())); ++ } ++} ++ ++static const char *method_type_to_string(u1 type) { ++ switch (type) { ++ case JfrStackFrame::FRAME_INTERPRETER: ++ return "Interpreted"; ++ case JfrStackFrame::FRAME_JIT: ++ return "JIT compiled"; ++ case JfrStackFrame::FRAME_INLINE: ++ return "Inlined"; ++ case JfrStackFrame::FRAME_NATIVE: ++ return "Native"; ++ default: ++ ShouldNotReachHere(); ++ return "Unknown"; ++ } ++} ++ ++uintptr_t related_data_jbolt[] = { ++ (uintptr_t)in_bytes(JfrStackTrace::hash_offset()), ++ (uintptr_t)in_bytes(JfrStackTrace::id_offset()), ++ (uintptr_t)in_bytes(JfrStackTrace::hotcount_offset()), ++ (uintptr_t)in_bytes(JfrStackTrace::frames_offset()), ++ (uintptr_t)in_bytes(JfrStackTrace::frames_count_offset()), ++ ++ (uintptr_t)in_bytes(JfrStackFrame::klass_offset()), ++ (uintptr_t)in_bytes(JfrStackFrame::methodid_offset()), ++ (uintptr_t)in_bytes(JfrStackFrame::bci_offset()), ++ (uintptr_t)in_bytes(JfrStackFrame::type_offset()), ++ ++ (uintptr_t)JBoltFunc::constructor, ++ (uintptr_t)JBoltFunc::copy_constructor, ++ (uintptr_t)JBoltCall::constructor, ++ (uintptr_t)JBoltCall::copy_constructor, ++ (uintptr_t)JBoltCallGraph::static_add_func, ++ (uintptr_t)JBoltCallGraph::static_add_call ++}; ++ ++/** ++ * Invoked in JfrStackTraceRepository::add_jbolt(). ++ * Each time JFR record a valid stacktrace, ++ * we log a weak ptr of each unique method in _sampled_methods_refs. ++ */ ++void JBoltManager::log_stacktrace(const JfrStackTrace& stacktrace) { ++ Thread* thread = Thread::current(); ++ HandleMark hm(thread); ++ ++ const JfrStackFrame* frames = stacktrace.get_frames(); ++ unsigned int framesCount = stacktrace.get_framesCount(); ++ ++ for (u4 i = 0; i < framesCount; ++i) { ++ const JfrStackFrame& frame = frames[i]; ++ ++ JBoltStackFrameKey stackframe_key(const_cast(frame.get_klass()), frame.get_methodId()); ++ ++ if (!_sampled_methods_refs->contains(stackframe_key)) { ++ jobject method_holder = JNIHandles::make_weak_global(Handle(thread, frame.get_klass()->klass_holder())); ++ JBoltStackFrameValue stackframe_value(method_holder); ++ _sampled_methods_refs->put(stackframe_key, stackframe_value); ++ // put() transmits method_holder ownership to element in map ++ // set the method_holder to nullptr in temp variable stackframe_value, to avoid double free ++ stackframe_value.clear_method_holder_but_not_release(); ++ } ++ } ++} ++ ++methodHandle JBoltManager::lookup_method(InstanceKlass* klass, traceid method_id) { ++ Thread* thread = Thread::current(); ++ JBoltStackFrameKey stackframe_key(klass, method_id); ++ JBoltStackFrameValue* stackframe_value = _sampled_methods_refs->get(stackframe_key); ++ if (stackframe_value == nullptr) { ++ return methodHandle(); ++ } ++ ++ jobject method_holder = stackframe_value->get_method_holder(); ++ if (method_holder != nullptr && JNIHandles::is_weak_global_handle(method_holder) && JNIHandles::is_weak_global_cleared(method_holder)) { ++ log_debug(jbolt)("method klass at %p is unloaded", (void*)klass); ++ return methodHandle(); ++ } ++ ++ const Method* const lookup_method = JfrMethodLookup::lookup(klass, method_id); ++ if (lookup_method == NULL) { ++ // stacktrace obsolete ++ return methodHandle(); ++ } ++ assert(lookup_method != NULL, "invariant"); ++ methodHandle method(thread, const_cast(lookup_method)); ++ ++ return method; ++} ++ ++void JBoltManager::construct_stacktrace(const JfrStackTrace& stacktrace) { ++ NoSafepointVerifier nsv; ++ if (stacktrace.get_framesCount() < MIN_FRAMESCOUNT) ++ return; ++ ++ u4 topFrameIndex = 0; ++ u4 max_frames = 0; ++ ++ const JfrStackFrame* frames = stacktrace.get_frames(); ++ unsigned int framesCount = stacktrace.get_framesCount(); ++ ++ // Native method subsidence ++ while (topFrameIndex < framesCount) { ++ const JfrStackFrame& frame = frames[topFrameIndex]; ++ ++ if (reinterpret_cast(method_type_to_string(frame.get_type())) != reinterpret_cast("Native")) { ++ break; ++ } ++ ++ topFrameIndex++; ++ } ++ ++ if (framesCount - topFrameIndex < MIN_FRAMESCOUNT) { ++ return; ++ } ++ ++ os::Linux::jboltLog_precalc(topFrameIndex, max_frames); ++ ++ JBoltFunc **tempfunc = NULL; ++ ++ for (u4 i = 0; i < max_frames; ++i) { ++ const JfrStackFrame& frame = frames[topFrameIndex + i]; ++ ++ methodHandle method = lookup_method(const_cast(frame.get_klass()), frame.get_methodId()); ++ if (method.is_null()) { ++ break; ++ } ++ const CompiledMethod* const compiled = method->code(); ++ ++ log_trace(jbolt)( ++ "Method id - %lu\n\tBytecode index - %hu\n\tSignature - %s\n\tType - %s\n\tCompiler - %s\n\tCompile Level - %d\n\tSize - %dB\n", ++ frame.get_methodId(), ++ frame.get_byteCodeIndex(), ++ method->external_name(), ++ method_type_to_string(frame.get_type()), ++ compiled != NULL ? compiled->compiler_name() : "None", ++ compiled != NULL ? compiled->comp_level() : -1, ++ compiled != NULL ? compiled->size() : 0); ++ ++ if (compiled == NULL) break; ++ ++ JBoltMethodKey method_key(method->constants()->pool_holder()->name(), method->name(), method->signature()); ++ JBoltFunc* func = JBoltFunc::constructor(frame.get_klass(), frame.get_methodId(), compiled->size(), method_key); ++ ++ if (!os::Linux::jboltLog_do(related_data_jbolt, (address)&stacktrace, i, compiled->comp_level(), (address)func, (address*)&tempfunc)) { ++ delete func; ++ func = NULL; ++ break; ++ } ++ } ++ ++ log_trace(jbolt)( ++ "StackTrace hash - %u hotcount - %d\n==============================\n", stacktrace.hash(), stacktrace.hotcount()); ++} ++ ++/** ++ * Invoked in JfrStackTraceRepository::write(). ++ * Each time JfrChunkWrite do write and clear stacktrace table, ++ * we update the CG by invoke construct_stacktrace(). ++ */ ++void JBoltManager::construct_cg_once() { ++ guarantee((UseJBolt && JBoltManager::reorder_phase_is_profiling_or_waiting()), "sanity"); ++ ++ GrowableArray* traces = create_growable_array(); ++ ++ { ++ MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); ++ const JfrStackTraceRepository& repository = JfrStackTraceRepository::instance(); ++ ++ if (repository.get_entries_count_jbolt() == 0) { ++ return; ++ } ++ ++ const JfrStackTrace* const * table = repository.get_stacktrace_table_jbolt(); ++ for (uint i = 0; i < repository.TABLE_SIZE; ++i) { ++ for (const JfrStackTrace* trace = table[i]; trace != nullptr; trace = trace->next()) { ++ traces->append(const_cast(trace)); ++ } ++ } ++ } ++ ++ Thread* thread = Thread::current(); ++ if (thread->is_Java_thread()) { ++ JavaThread* java_thread = JavaThread::current(); ++ ThreadInVMfromNative tiv(java_thread); ++ for (int i = 0; i < traces->length(); ++i) { ++ construct_stacktrace(*(traces->at(i))); ++ } ++ } else { ++ for (int i = 0; i < traces->length(); ++i) { ++ construct_stacktrace(*(traces->at(i))); ++ } ++ } ++ ++ log_trace(jbolt)( ++ "+++++++ one time log over ++++++\n\n"); ++ delete traces; ++} ++ ++static void write_order(const GrowableArray* order, fileStream& fs) { ++ assert(order != nullptr, "sanity"); ++ const char* methodFlag = "M"; ++ const char* segmentor = "C\n"; ++ ++ log_debug(jbolt)("+============================+\n\t\t\tORDER\n"); ++ ++ for (int i = 0; i < order->length(); ++i) { ++ const JBoltFunc& func = order->at(i); ++ if (func.klass() == NULL) { ++ fs.write(segmentor, strlen(segmentor)); ++ continue; ++ } ++ ++ char* holder_name = func.method_key().klass()->as_C_string(); ++ char* name = func.method_key().name()->as_C_string(); ++ char* signature = func.method_key().sig()->as_C_string(); ++ char size[LINE_BUF_SIZE] = {0}; ++ snprintf(size, sizeof(size), "%d", func.size()); ++ ++ log_debug(jbolt)("order %d --- Method - %s %s %s\n", i, holder_name, name, signature); ++ ++ fs.write(methodFlag, strlen(methodFlag)); ++ fs.write(" ", 1); ++ fs.write(size, strlen(size)); ++ fs.write(" ", 1); ++ fs.write(holder_name, strlen(holder_name)); ++ fs.write(" ", 1); ++ fs.write(name, strlen(name)); ++ fs.write(" ", 1); ++ fs.write(signature, strlen(signature)); ++ fs.write("\n", 1); ++ } ++} ++ ++/** ++ * Invoked in before_exit(). ++ * Only use in manual mode. ++ * Dump the order to JBoltOrderFile before vm exit. ++ */ ++void JBoltManager::dump_order_in_manual() { ++ guarantee((UseJBolt && JBoltDumpMode), "sanity"); ++ guarantee(reorder_phase_profiling_to_waiting(), "sanity"); ++ NoSafepointVerifier nsv; ++ ResourceMark rm; ++ GrowableArray* order = JBoltCallGraph::callgraph_instance().hfsort(); ++ ++ fileStream orderFile(JBoltOrderFile, "w+"); ++ ++ if (JBoltOrderFile == NULL || !orderFile.is_open()) { ++ log_error(jbolt)("JBoltOrderFile open error"); ++ vm_exit_during_initialization("JBoltOrderFile open error"); ++ } ++ ++ write_order(order, orderFile); ++ ++ log_info(jbolt)("order generate successful !!"); ++ log_debug(jbolt)("+============================+\n"); ++ delete order; ++ delete _sampled_methods_refs; ++ _sampled_methods_refs = nullptr; ++ JBoltCallGraph::deinitialize(); ++} ++ ++JBoltErrorCode JBoltManager::dump_order_in_jcmd(const char* filename) { ++ guarantee(UseJBolt, "sanity"); ++ NoSafepointVerifier nsv; ++ ResourceMark rm; ++ ++ if (_order_stored == nullptr) return JBoltOrderNULL; ++ ++ fileStream orderFile(filename, "w+"); ++ ++ if (filename == NULL || !orderFile.is_open()) return JBoltOpenFileError; ++ ++ write_order(_order_stored, orderFile); ++ ++ return JBoltOK; ++} ++ ++/** ++ * Do not set the JBolt-related flags manually if UseJBolt is not enabled. ++ */ ++void JBoltManager::check_arguments_not_set() { ++ if (UseJBolt) return; ++ ++ check_arg_not_set(FLAG_MEMBER_ENUM(JBoltDumpMode)); ++ check_arg_not_set(FLAG_MEMBER_ENUM(JBoltLoadMode)); ++ check_arg_not_set(FLAG_MEMBER_ENUM(JBoltOrderFile)); ++ check_arg_not_set(FLAG_MEMBER_ENUM(JBoltSampleInterval)); ++ check_arg_not_set(FLAG_MEMBER_ENUM(JBoltCodeHeapSize)); ++} ++ ++/** ++ * Check which mode is JBolt in. ++ * If JBoltDumpMode or JBoltLoadMode is set manually then do nothing, else it will be fully auto sched by JBolt itself. ++ */ ++void JBoltManager::check_mode() { ++ if (!(JBoltDumpMode || JBoltLoadMode)) { ++ _auto_mode = true; ++ return; ++ } ++ ++ if (!FLAG_IS_DEFAULT(JBoltSampleInterval)) { ++ log_warning(jbolt)("JBoltSampleInterval is ignored because it is not in auto mode."); ++ } ++ ++ if (JBoltDumpMode && JBoltLoadMode) { ++ vm_exit_during_initialization("Do not set both JBoltDumpMode and JBoltLoadMode!"); ++ } ++ ++ guarantee((JBoltDumpMode ^ JBoltLoadMode), "Must set either JBoltDumpMode or JBoltLoadMode!"); ++} ++ ++/** ++ * If in auto mode, JBoltOrderFile will be ignored ++ * If in any manual mode, then JBoltOrderFile will be necessary. ++ * Check whether the order file exists or is accessable. ++ */ ++void JBoltManager::check_order_file() { ++ if (auto_mode()) { ++ if (JBoltOrderFile != nullptr) log_warning(jbolt)("JBoltOrderFile is ignored because it is in auto mode."); ++ return; ++ } ++ ++ if (JBoltOrderFile == nullptr) { ++ vm_exit_during_initialization("JBoltOrderFile is not set!"); ++ } ++ ++ bool file_exist = (::access(JBoltOrderFile, F_OK) == 0); ++ if (file_exist) { ++ if (JBoltDumpMode) { ++ log_warning(jbolt)("JBoltOrderFile to dump already exists and will be overwritten: file=%s.", JBoltOrderFile); ++ ::remove(JBoltOrderFile); ++ } ++ } else { ++ if (JBoltLoadMode) { ++ vm_exit_during_initialization(err_msg("JBoltOrderFile does not exist or cannot be accessed! file=\"%s\".", JBoltOrderFile)); ++ } ++ } ++} ++ ++void JBoltManager::check_dependency() { ++ if (FLAG_IS_CMDLINE(FlightRecorder) ? !FlightRecorder : false) { ++ vm_exit_during_initialization("JBolt depends on JFR!"); ++ } ++ ++ if (!CompilerConfig::is_c2_enabled()) { ++ vm_exit_during_initialization("JBolt depends on C2!"); ++ } ++ ++ if (!SegmentedCodeCache) { ++ vm_exit_during_initialization("JBolt depends on SegmentedCodeCache!"); ++ } ++} ++ ++size_t JBoltManager::calc_nmethod_size_with_padding(size_t nmethod_size) { ++ return align_up(nmethod_size, (size_t) CodeCacheSegmentSize); ++} ++ ++size_t JBoltManager::calc_segment_size_with_padding(size_t segment_size) { ++ size_t page_size = CodeCache::page_size(); ++ if (segment_size < page_size) return page_size; ++ return align_down(segment_size, page_size); ++} ++ ++/** ++ * We have to parse the file twice because SymbolTable is not inited in phase 1... ++ */ ++void JBoltManager::load_order_file_phase1(int* method_cnt, size_t* segment_size) { ++ assert(JBoltOrderFile != nullptr, "sanity"); ++ ++ _order_fp = os::fopen(JBoltOrderFile, "r"); ++ if (_order_fp == nullptr) { ++ vm_exit_during_initialization(err_msg("Cannot open file JBoltOrderFile! file=\"%s\".", JBoltOrderFile)); ++ } ++ ++ int mth_cnt = 0; ++ size_t seg_size = 0; ++ ++ char line[LINE_BUF_SIZE]; ++ int len = -1; ++ while (read_line(_order_fp, line, sizeof(line), &len)) { ++ if (len <= 2) continue; ++ if (line[0] != 'M' || line[1] != ' ') continue; ++ char* left_start = line + 2; ++ ++ // parse nmethod size ++ size_t nmethod_size; ++ if (!read_a_size(left_start, &nmethod_size)) { ++ vm_exit_during_initialization(err_msg("Wrong format of JBolt order line! line=\"%s\".", line)); ++ } ++ ++mth_cnt; ++ seg_size += calc_nmethod_size_with_padding(nmethod_size); ++ } ++ ++ *method_cnt = mth_cnt; ++ *segment_size = seg_size; ++ log_trace(jbolt)("Read order file method_cnt=%d, estimated_segment_size=" SIZE_FORMAT ".", mth_cnt, seg_size); ++} ++ ++bool JBoltManager::parse_method_line_phase2(char* const line, const int len) { ++ // Skip "M ". ++ char* left_start = line + 2; ++ ++ // Skip nmethod size (has parsed in phase1). ++ { ++ char* t = strchr(left_start, ' '); ++ if (t == nullptr) return false; ++ left_start = t + 1; ++ } ++ ++ // Modify "java.lang.Obj" to "java/lang/Obj". ++ replace_all(left_start, '.', '/'); ++ ++ // Parse the three symbols: class name, method name, signature. ++ Symbol* three_symbols[3]; ++ for (int i = 0; i < 2; ++i) { ++ char* t = strchr(left_start, ' '); ++ if (t == nullptr) return false; ++ Symbol* sym = SymbolTable::new_symbol(left_start, t - left_start); ++ three_symbols[i] = sym; ++ left_start = t + 1; ++ } ++ Symbol* sym = SymbolTable::new_symbol(left_start, line + len - left_start); ++ three_symbols[2] = sym; ++ if (log_is_enabled(Trace, jbolt)) { ++ log_trace(jbolt)("HotMethod init: key={%s %s %s}", ++ three_symbols[0]->as_C_string(), ++ three_symbols[1]->as_C_string(), ++ three_symbols[2]->as_C_string()); ++ } ++ ++ // Add to data structure. ++ JBoltMethodKey method_key(three_symbols[0], three_symbols[1], three_symbols[2]); ++ _hot_methods_sorted->append(method_key); ++ JBoltMethodValue method_value; ++ bool put = _hot_methods_vis->put(method_key, method_value); ++ if (!put) { ++ vm_exit_during_initialization(err_msg("Duplicated method: {%s %s %s}!", ++ three_symbols[0]->as_C_string(), ++ three_symbols[1]->as_C_string(), ++ three_symbols[2]->as_C_string())); ++ } ++ ++ return true; ++} ++ ++bool JBoltManager::parse_connected_component_line_phase2(char* const line, const int len) { return true; } ++ ++void JBoltManager::load_order_file_phase2(TRAPS) { ++ guarantee(_order_fp != nullptr, "sanity"); ++ ++ // re-scan ++ fseek(_order_fp, 0, SEEK_SET); ++ ++ char line[LINE_BUF_SIZE]; ++ int len = -1; ++ while (read_line(_order_fp, line, sizeof(line), &len)) { ++ if (len <= 0) continue; ++ bool success = false; ++ switch (line[0]) { ++ case '#': success = true; break; // ignore comments ++ case 'M': success = parse_method_line_phase2(line, len); break; ++ case 'C': success = parse_connected_component_line_phase2(line, len); break; ++ default: break; ++ } ++ if (!success) { ++ vm_exit_during_initialization(err_msg("Wrong format of JBolt order line! line=\"%s\".", line)); ++ } ++ } ++ fclose(_order_fp); ++ _order_fp = nullptr; ++} ++ ++void JBoltManager::init_load_mode_phase1() { ++ if (!(auto_mode() || JBoltLoadMode)) return; ++ ++ if (auto_mode()) { ++ // auto mode has no order now, initialize as default. ++ _hot_methods_sorted = new (mtCompiler) GrowableArray(1, mtCompiler); ++ _hot_methods_vis = new (mtCompiler) MethodKeyMap(); ++ log_info(jbolt)("Default set JBoltCodeHeapSize=" UINTX_FORMAT " B (" UINTX_FORMAT " MB).", JBoltCodeHeapSize, JBoltCodeHeapSize / 1024 / 1024); ++ return; ++ } ++ guarantee(reorder_phase_available_to_collecting(), "sanity"); ++ size_t total_nmethod_size = 0; ++ int method_cnt = 0; ++ load_order_file_phase1(&method_cnt, &total_nmethod_size); ++ ++ _hot_methods_sorted = new (mtCompiler) GrowableArray(method_cnt, mtCompiler); ++ _hot_methods_vis = new (mtCompiler) MethodKeyMap(); ++ ++ if (FLAG_IS_DEFAULT(JBoltCodeHeapSize)) { ++ FLAG_SET_ERGO(JBoltCodeHeapSize, calc_segment_size_with_padding(total_nmethod_size)); ++ log_info(jbolt)("Auto set JBoltCodeHeapSize=" UINTX_FORMAT " B (" UINTX_FORMAT " MB).", JBoltCodeHeapSize, JBoltCodeHeapSize / 1024 / 1024); ++ } ++} ++ ++void JBoltManager::init_load_mode_phase2(TRAPS) { ++ // Only manual load mode need load phase2 ++ if (!JBoltLoadMode) return; ++ ++ load_order_file_phase2(CHECK); ++ _reorderable_method_cnt = 0; ++ _reorder_method_threshold_cnt = _hot_methods_sorted->length() * _jbolt_reorder_threshold; ++} ++ ++void JBoltManager::init_dump_mode_phase2(TRAPS) { ++ if (!(auto_mode() || JBoltDumpMode)) return; ++ ++ JBoltCallGraph::initialize(); ++ _sampled_methods_refs = new (mtTracing) StackFrameKeyMap(); ++ ++ // JBolt will create a JFR by itself ++ // In auto mode, will stop in JBoltControlThread::start_thread() after JBoltSampleInterval. ++ // In manual dump mode, won't stop until program exit. ++ log_info(jbolt)("JBolt in dump mode now, start a JFR recording named \"jbolt-jfr\"."); ++ bufferedStream output; ++ DCmd::parse_and_execute(DCmd_Source_Internal, &output, "JFR.start name=jbolt-jfr", ' ', THREAD); ++ if (HAS_PENDING_EXCEPTION) { ++ ResourceMark rm; ++ log_warning(jbolt)("unable to start jfr jbolt-jfr"); ++ log_warning(jbolt)("exception type: %s", PENDING_EXCEPTION->klass()->external_name()); ++ // don't unwind this exception ++ CLEAR_PENDING_EXCEPTION; ++ } ++} ++ ++static void update_stored_order(const GrowableArray* order) { ++ if (_order_stored != nullptr) { ++ // use a tmp for releasing space to provent _order_stored from being a wild pointer ++ GrowableArray* tmp = _order_stored; ++ _order_stored = nullptr; ++ delete tmp; ++ } ++ _order_stored = new (mtTracing) GrowableArray(order->length(), mtTracing); ++ _order_stored->appendAll(order); ++} ++ ++static CompileTaskInfo* create_compile_task_info(methodHandle& method) { ++ CompiledMethod* compiled = method->code(); ++ if (compiled == nullptr) { ++ log_warning(jbolt)("Recompilation Task init failed because of null nmethod. func: %s.", method->external_name()); ++ return nullptr; ++ } ++ int osr_bci = compiled->is_osr_method() ? compiled->osr_entry_bci() : InvocationEntryBci; ++ int comp_level = compiled->comp_level(); ++ // comp_level adaptation for deoptmization ++ if (comp_level > CompLevel_simple && comp_level <= CompLevel_full_optimization) comp_level = CompLevel_full_optimization; ++ CompileTask::CompileReason comp_reason = CompileTask::Reason_Reorder; ++ CompileTaskInfo* ret = new CompileTaskInfo(method(), osr_bci, comp_level, (int)comp_reason, ++ nullptr, 0); ++ return ret; ++} ++ ++/** ++ * This function is invoked by JBoltControlThread. ++ * Do initialization for converting dump mode to load mode. ++ */ ++void JBoltManager::init_auto_transition(size_t* segment_size, TRAPS) { ++ guarantee(UseJBolt && auto_mode(), "sanity"); ++ NoSafepointVerifier nsv; ++ ResourceMark rm; ++ ++ GrowableArray* order = JBoltCallGraph::callgraph_instance().hfsort(); ++ update_stored_order(order); ++ ++ size_t seg_size = 0; ++ for (int i = 0; i < order->length(); ++i) { ++ const JBoltFunc& func = order->at(i); ++ if (func.klass() == NULL) { ++ continue; ++ } ++ ++ methodHandle method = lookup_method(const_cast(func.klass()), func.method_id()); ++ if (method.is_null()) { ++ continue; ++ } ++ ++ CompileTaskInfo* cti = create_compile_task_info(method); ++ if (cti == nullptr) { ++ continue; ++ } ++ ++ JBoltMethodKey method_key = func.method_key(); ++ JBoltMethodValue method_value; ++ if (!method_value.set_comp_info(cti)) { ++ delete cti; ++ continue; ++ } ++ ++ seg_size += calc_nmethod_size_with_padding(func.size()); ++ _hot_methods_sorted->append(method_key); ++ bool put = _hot_methods_vis->put(method_key, method_value); ++ if (!put) { ++ vm_exit_during_initialization(err_msg("Duplicated method: {%s %s %s}!", ++ method_key.klass()->as_C_string(), ++ method_key.name()->as_C_string(), ++ method_key.sig()->as_C_string())); ++ } ++ method_value.clear_comp_info_but_not_release(); ++ } ++ log_info(jbolt)("order generate successful !!"); ++ *segment_size = calc_segment_size_with_padding(seg_size); ++ delete order; ++} ++ ++/** ++ * This function must be invoked after CompilerConfig::ergo_initialize() in Arguments::apply_ergo(). ++ * This function must be invoked before CodeCache::initialize_heaps() in codeCache_init() in init_globals(). ++ * Thread and SymbolTable is not inited now! ++ */ ++void JBoltManager::init_phase1() { ++ if (!UseJBolt) return; ++ check_mode(); ++ check_dependency(); ++ check_order_file(); ++ ++ /* dump mode has nothing to do in phase1 */ ++ init_load_mode_phase1(); ++} ++ ++void JBoltManager::init_phase2(TRAPS) { ++ if (!UseJBolt) return; ++ ++ ResourceMark rm(THREAD); ++ init_dump_mode_phase2(CHECK); ++ init_load_mode_phase2(CHECK); ++ ++ // Manual dump mode doesn't need JBoltControlThread, directly go to profiling phase ++ if (JBoltDumpMode) { ++ guarantee(JBoltManager::reorder_phase_available_to_profiling(), "sanity"); ++ return; ++ } ++ ++ JBoltControlThread::init(CHECK); ++ // Auto mode will start control thread earlier. ++ // Manual load mode start later in check_start_reordering() ++ if (auto_mode()) { ++ JBoltControlThread::start_thread(CHECK_AND_CLEAR); ++ } ++} ++ ++/** ++ * Code heaps are initialized between init phase 1 and init phase 2. ++ */ ++void JBoltManager::init_code_heaps(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, size_t ps, size_t alignment) { ++ assert(UseJBolt && !JBoltDumpMode, "sanity"); ++ if(!is_aligned(JBoltCodeHeapSize, alignment)) { ++ vm_exit_during_initialization(err_msg("JBoltCodeHeapSize should be %ld aligned, please adjust", alignment)); ++ } ++ ++ size_t jbolt_hot_size = JBoltCodeHeapSize; ++ size_t jbolt_tmp_size = JBoltCodeHeapSize; ++ size_t jbolt_total_size = jbolt_hot_size + jbolt_tmp_size; ++ if (non_profiled_size <= jbolt_total_size) { ++ vm_exit_during_initialization(err_msg("Not enough space in non-profiled code heap to split out JBolt heap(s): " SIZE_FORMAT "K <= " SIZE_FORMAT "K", non_profiled_size/K, jbolt_total_size/K)); ++ } ++ non_profiled_size -= jbolt_total_size; ++ non_profiled_size = align_down(non_profiled_size, alignment); ++ FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled_size); ++ ++ // Memory layout with JBolt: ++ // ---------- high ----------- ++ // Non-profiled nmethods ++ // JBolt tmp nmethods ++ // JBolt hot nmethods ++ // Non-nmethods ++ // Profiled nmethods ++ // ---------- low ------------ ++ ReservedCodeSpace rs = CodeCache::reserve_heap_memory(cache_size, ps); ++ ReservedSpace profiled_space = rs.first_part(profiled_size); ++ ReservedSpace r1 = rs.last_part(profiled_size); ++ ReservedSpace non_nmethod_space = r1.first_part(non_nmethod_size); ++ ReservedSpace r2 = r1.last_part(non_nmethod_size); ++ ReservedSpace jbolt_hot_space = r2.first_part(jbolt_hot_size); ++ ReservedSpace r3 = r2.last_part(jbolt_hot_size); ++ ReservedSpace jbolt_tmp_space = r3.first_part(jbolt_tmp_size); ++ ReservedSpace non_profiled_space = r3.last_part(jbolt_tmp_size); ++ ++ CodeCache::add_heap(non_nmethod_space, "CodeHeap 'non-nmethods'", CodeBlobType::NonNMethod); ++ CodeCache::add_heap(profiled_space, "CodeHeap 'profiled nmethods'", CodeBlobType::MethodProfiled); ++ CodeCache::add_heap(non_profiled_space, "CodeHeap 'non-profiled nmethods'", CodeBlobType::MethodNonProfiled); ++ const char* no_space = nullptr; ++ CodeCache::add_heap(jbolt_hot_space, "CodeHeap 'jbolt hot nmethods'", CodeBlobType::MethodJBoltHot); ++ if (jbolt_hot_size != jbolt_hot_space.size()) { ++ no_space = "hot"; ++ } ++ CodeCache::add_heap(jbolt_tmp_space, "CodeHeap 'jbolt tmp nmethods'", CodeBlobType::MethodJBoltTmp); ++ if (jbolt_tmp_size != jbolt_tmp_space.size()) { ++ no_space = "tmp"; ++ } ++ if (no_space != nullptr) { ++ vm_exit_during_initialization(FormatBuffer<1024>( ++ "No enough space for JBolt %s heap: \n" ++ "Expect: cache_size=" SIZE_FORMAT "K, profiled_size=" SIZE_FORMAT "K, non_nmethod_size=" SIZE_FORMAT "K, jbolt_hot_size=" SIZE_FORMAT "K, non_profiled_size=" SIZE_FORMAT "K, jbolt_tmp_size=" SIZE_FORMAT "K\n" ++ "Actual: cache_size=" SIZE_FORMAT "K, profiled_size=" SIZE_FORMAT "K, non_nmethod_size=" SIZE_FORMAT "K, jbolt_hot_size=" SIZE_FORMAT "K, non_profiled_size=" SIZE_FORMAT "K, jbolt_tmp_size=" SIZE_FORMAT "K\n" ++ "alignment=" SIZE_FORMAT, ++ no_space, ++ cache_size/K, profiled_size/K, non_nmethod_size/K, jbolt_hot_size/K, non_profiled_size/K, jbolt_tmp_size/K, ++ rs.size()/K, profiled_space.size()/K, non_nmethod_space.size()/K, jbolt_hot_space.size()/K, non_profiled_space.size()/K, jbolt_tmp_space.size()/K, ++ alignment)); ++ } ++} ++ ++int JBoltManager::reorder_phase() { ++ return Atomic::load_acquire(&_reorder_phase); ++} ++ ++bool JBoltManager::reorder_phase_available_to_collecting() { ++ assert(!auto_mode(), "two-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Available, JBoltReorderPhase::Collecting) == JBoltReorderPhase::Available; ++} ++ ++bool JBoltManager::reorder_phase_collecting_to_reordering() { ++ assert(!auto_mode(), "two-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Collecting, JBoltReorderPhase::Reordering) == JBoltReorderPhase::Collecting; ++} ++ ++bool JBoltManager::reorder_phase_available_to_profiling() { ++ assert(auto_mode(), "one-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Available, JBoltReorderPhase::Profiling) == JBoltReorderPhase::Available; ++} ++ ++bool JBoltManager::reorder_phase_profiling_to_reordering() { ++ assert(auto_mode(), "one-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Profiling, JBoltReorderPhase::Reordering) == JBoltReorderPhase::Profiling; ++} ++ ++bool JBoltManager::reorder_phase_reordering_to_available() { ++ assert(auto_mode(), "one-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Reordering, JBoltReorderPhase::Available) == JBoltReorderPhase::Reordering; ++} ++ ++bool JBoltManager::reorder_phase_profiling_to_available() { ++ assert(auto_mode(), "one-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Profiling, JBoltReorderPhase::Available) == JBoltReorderPhase::Profiling; ++} ++ ++bool JBoltManager::reorder_phase_profiling_to_waiting() { ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Profiling, JBoltReorderPhase::Waiting) == JBoltReorderPhase::Profiling; ++} ++ ++bool JBoltManager::reorder_phase_waiting_to_reordering() { ++ assert(auto_mode(), "one-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Waiting, JBoltReorderPhase::Reordering) == JBoltReorderPhase::Waiting; ++} ++ ++bool JBoltManager::reorder_phase_waiting_to_available() { ++ assert(auto_mode(), "one-phase only"); ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Waiting, JBoltReorderPhase::Available) == JBoltReorderPhase::Waiting; ++} ++ ++bool JBoltManager::reorder_phase_reordering_to_end() { ++ return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Reordering, JBoltReorderPhase::End) == JBoltReorderPhase::Reordering; ++} ++ ++bool JBoltManager::reorder_phase_is_waiting() { ++ return Atomic::load_acquire(&_reorder_phase) == JBoltReorderPhase::Waiting; ++} ++ ++bool JBoltManager::reorder_phase_is_available() { ++ bool res = (Atomic::load_acquire(&_reorder_phase) == JBoltReorderPhase::Available); ++ assert(!res || auto_mode(), "one-phase only"); ++ return res; ++} ++ ++bool JBoltManager::reorder_phase_is_collecting() { ++ bool res = (Atomic::load_acquire(&_reorder_phase) == JBoltReorderPhase::Collecting); ++ assert(!res || !auto_mode(), "two-phase only"); ++ return res; ++} ++ ++bool JBoltManager::reorder_phase_is_profiling() { ++ bool res = (Atomic::load_acquire(&_reorder_phase) == JBoltReorderPhase::Profiling); ++ assert(!res || auto_mode(), "for two-phase dump mode & one-phase"); ++ return res; ++} ++ ++bool JBoltManager::reorder_phase_is_reordering() { ++ return Atomic::load_acquire(&_reorder_phase) == JBoltReorderPhase::Reordering; ++} ++ ++bool JBoltManager::reorder_phase_is_collecting_or_reordering() { ++ int p = Atomic::load_acquire(&_reorder_phase); ++ assert(p != JBoltReorderPhase::Collecting || !auto_mode(), "two-phase only"); ++ return p == JBoltReorderPhase::Collecting || p == JBoltReorderPhase::Reordering; ++} ++ ++bool JBoltManager::reorder_phase_is_profiling_or_waiting() { ++ int p = Atomic::load_acquire(&_reorder_phase); ++ return p == JBoltReorderPhase::Profiling || p == JBoltReorderPhase::Waiting; ++} ++ ++Method* JBoltManager::cur_reordering_method() { ++ return Atomic::load_acquire(&_cur_reordering_method); ++} ++ ++void JBoltManager::set_cur_reordering_method(Method* method) { ++ Atomic::release_store(&_cur_reordering_method, method); ++} ++ ++int JBoltManager::inc_reorderable_method_cnt() { ++ return Atomic::add(&_reorderable_method_cnt, +1); ++} ++ ++bool JBoltManager::can_reorder_now() { ++ return Atomic::load_acquire(&_reorderable_method_cnt) >= _reorder_method_threshold_cnt; ++} ++ ++bool JBoltManager::should_reorder_now() { ++ return Atomic::load_acquire(&_reorderable_method_cnt) == _reorder_method_threshold_cnt; ++} ++ ++bool JBoltManager::gc_should_sweep_code_heaps_now() { ++ return Atomic::load_acquire(&_gc_should_sweep_code_heaps_now) != 0; ++} ++ ++CodeBlobType JBoltManager::primary_hot_seg() { ++ return CodeBlobType(Atomic::load_acquire(&_primary_hot_seg)); ++} ++ ++CodeBlobType JBoltManager::secondary_hot_seg() { ++ return CodeBlobType(Atomic::load_acquire(&_secondary_hot_seg)); ++} ++ ++int JBoltManager::clear_manager() { ++ /* _hot_methods_sorted, _hot_methods_vis and _sampled_methods_refs have been cleared in other pos, don't delete again */ ++ guarantee(_hot_methods_sorted == nullptr, "sanity"); ++ guarantee(_hot_methods_vis == nullptr, "sanity"); ++ guarantee(_sampled_methods_refs == nullptr, "sanity"); ++ // Re-allocate them ++ _hot_methods_sorted = new (mtCompiler) GrowableArray(1, mtCompiler); ++ _hot_methods_vis = new (mtCompiler) MethodKeyMap(); ++ _sampled_methods_refs = new (mtTracing) StackFrameKeyMap(); ++ ++ return 0; ++} ++ ++/** ++ * Invoked in JBoltControlThread::prev_control_schedule(). ++ * Expect to only execute in auto mode while JBolt.start triggered. ++ * Clear JBolt related data structures to restore a initial env same as sample never happening. ++*/ ++int JBoltManager::clear_last_sample_datas() { ++ int ret = 0; ++ // Clear _table_jbolt in JfrStackTraceRepository ++ ret = JfrStackTraceRepository::clear_jbolt(); ++ // Clear JBoltCallGraph ++ ret = JBoltCallGraph::callgraph_instance().clear_instance(); ++ // Clear JBoltManager ++ ret = clear_manager(); ++ ++ return ret; ++} ++ ++/** ++ * Invoked in JBoltControlThread::prev_control_schedule(). ++ * Swap primary hot segment with secondary hot segment ++ */ ++void JBoltManager::swap_semi_jbolt_segs() { ++ guarantee(reorder_phase_is_waiting(), "swap must happen in reorder phase Profiling."); ++ int tmp = Atomic::xchg(&_secondary_hot_seg, Atomic::load_acquire(&_primary_hot_seg)); ++ Atomic::xchg(&_primary_hot_seg, tmp); ++} ++ ++/** ++ * Invoked in JBoltControlThread::post_control_schdule(). ++ * Free scondary hot segment space for next reorder. ++ */ ++void JBoltManager::clear_secondary_hot_seg(TRAPS) { ++ guarantee(reorder_phase_is_available(), "secondary clear must happen in reorder phase Available."); ++ // scan secondary hot seg and recompile alive nmethods to non-profiled ++ ResourceMark rm(THREAD); ++ // We cannot alloc weak handle within CodeCache_lock because of the mutex rank check. ++ // So instead we keep the methods alive only within the scope of this method. ++ JBoltUtils::MetaDataKeepAliveMark mdm(THREAD); ++ const GrowableArray& to_recompile = mdm.kept(); ++ ++ { ++ MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); ++ CodeHeap* sec_hot = CodeCache::get_code_heap(secondary_hot_seg()); ++ for (CodeBlob* cb = (CodeBlob*) sec_hot->first(); cb != nullptr; cb = (CodeBlob*) sec_hot->next(cb)) { ++ nmethod* nm = cb->as_nmethod_or_null(); ++ Method* m = nm->method(); ++ if (nm && nm->get_state() == CompiledMethod::in_use && m != nullptr) { ++ mdm.add(m); ++ } ++ } ++ } ++ ++ for (int i = 0; i < to_recompile.length(); ++i) { ++ Method* m = (Method*) to_recompile.at(i); ++ methodHandle method(THREAD, m); ++ CompileTaskInfo* cti = create_compile_task_info(method); ++ if (cti == nullptr) continue; ++ guarantee(cti->try_select(), "method is on stack, should be ok"); ++ assert(cti->hot_method() == nullptr, "sanity"); ++ methodHandle hot_method; ++ ++ bool recompile_result = enqueue_recompile_task(cti, method, hot_method, THREAD); ++ if(recompile_result) { ++ check_compiled_result(method(), CodeBlobType::MethodNonProfiled, THREAD); ++ } ++ delete cti; ++ } ++ ++ Atomic::release_store(&_gc_should_sweep_code_heaps_now, 1); ++ Universe::heap()->collect(GCCause::_java_lang_system_gc); ++ Universe::heap()->collect(GCCause::_java_lang_system_gc); ++ Atomic::release_store(&_gc_should_sweep_code_heaps_now, 0); ++ log_info(jbolt)("Sweep secondary segment"); ++ print_code_heaps(); ++} ++ ++/** ++ * Invoked in ciEnv::register_method() in CompilerThread. ++ * Controls where the new nmethod should be allocated. ++ * ++ * Returns CodeBlobType::All if it is not determined by JBolt logic. ++ */ ++CodeBlobType JBoltManager::calc_code_blob_type(Method* method, CompileTask* task, TRAPS) { ++ assert(UseJBolt && reorder_phase_is_collecting_or_reordering(), "sanity"); ++ const CodeBlobType not_care = CodeBlobType::All; ++ ++ // Only cares about non-profiled segment. ++ int lvl = task->comp_level(); ++ if (lvl != CompLevel_full_optimization && lvl != CompLevel_simple) { ++ return not_care; ++ } ++ ++ // Ignore on-stack-replacement. ++ if (task->osr_bci() != InvocationEntryBci) { ++ return not_care; ++ } ++ ++ int cur_reorder_phase = reorder_phase(); ++ // Do nothing after reordering. ++ if (cur_reorder_phase != JBoltReorderPhase::Collecting && cur_reorder_phase != JBoltReorderPhase::Reordering) { ++ return not_care; ++ } ++ // Only cares about the current reordering method. ++ if (cur_reorder_phase == JBoltReorderPhase::Reordering) { ++ if (cur_reordering_method() == method) { ++ log_trace(jbolt)("Compiling to JBolt heap: method=%s.", method->name_and_sig_as_C_string()); ++ return primary_hot_seg(); ++ } ++ return not_care; ++ } ++ guarantee(cur_reorder_phase == JBoltReorderPhase::Collecting, "sanity"); ++ assert(!auto_mode(), "sanity"); ++ ++ JBoltMethodKey method_key(method); ++ JBoltMethodValue* method_value = _hot_methods_vis->get(method_key); ++ if (method_value == nullptr) { ++ return not_care; ++ } ++ ++ // Register the method and the compile task. ++ if (method_value->get_comp_info() == nullptr) { ++ CompileTaskInfo* cti = new CompileTaskInfo(method, task->osr_bci(), task->comp_level(), (int) task->compile_reason(), ++ task->hot_method(), task->hot_count()); ++ if (method_value->set_comp_info(cti)) { ++ int cnt = inc_reorderable_method_cnt(); ++ log_trace(jbolt)("Reorderable method found: cnt=%d, lvl=%d, p=%p, method=%s.", ++ cnt, task->comp_level(), method, method->name_and_sig_as_C_string()); ++ if (is_power_of_2(_reorder_method_threshold_cnt - cnt)) { ++ log_debug(jbolt)("Reorderable cnt: %d/%d/%d", cnt, _reorder_method_threshold_cnt, _hot_methods_sorted->length()); ++ } ++ if (cnt == _reorder_method_threshold_cnt) { ++ log_info(jbolt)("Time to reorder: %d/%d/%d", cnt, _reorder_method_threshold_cnt, _hot_methods_sorted->length()); ++ _start_reordering_thread = THREAD; ++ } ++ } else { ++ delete cti; ++ } ++ } ++ ++ return secondary_hot_seg(); ++} ++ ++/** ++ * Check if reordering should start. ++ * The reordering should only start once (for now). ++ * We don't do this check in "if (cnt == _reorder_method_threshold_cnt)" in calc_code_blob_type() ++ * because it will cause an assert error: "Possible safepoint reached by thread that does not allow it". ++ */ ++void JBoltManager::check_start_reordering(TRAPS) { ++ // _start_reordering_thread is set and tested in the same thread. No need to be atomic. ++ if (_start_reordering_thread == THREAD) { ++ _start_reordering_thread = nullptr; ++ if (JBoltControlThread::get_thread() == nullptr) { ++ assert(can_reorder_now(), "sanity"); ++ log_info(jbolt)("Starting JBoltControlThread to reorder."); ++ JBoltControlThread::start_thread(CHECK_AND_CLEAR); ++ } ++ } ++} ++ ++/** ++ * The task will be added to the compile queue and be compiled just like other tasks. ++ */ ++CompileTask* JBoltManager::create_a_task_instance(CompileTaskInfo* cti, methodHandle& method, methodHandle& hot_method, TRAPS) { ++ int osr_bci = cti->osr_bci(); ++ int comp_level = cti->comp_level(); ++ CompileTask::CompileReason comp_reason = (CompileTask::CompileReason) cti->comp_reason(); ++ int hot_count = cti->hot_count(); ++ bool is_blocking = true; ++ ++ // init a task (@see CompileBroker::create_compile_task()) ++ CompileTask* task = CompileTask::allocate(); ++ int compile_id = CompileBroker::assign_compile_id(method, osr_bci); ++ task->initialize(compile_id, method, osr_bci, comp_level, ++ hot_method, hot_count, comp_reason, ++ is_blocking); ++ return task; ++} ++ ++/** ++ * Print the failure reason if something is wrong in recompilation. ++ */ ++void JBoltManager::check_compiled_result(Method* method, CodeBlobType check_blob_type, TRAPS) { ++ CompiledMethod* cm = method->code(); ++ if (cm == nullptr) { ++ log_warning(jbolt)("Recompilation failed because of null nmethod."); ++ return; ++ } ++ nmethod* nm = cm->as_nmethod_or_null(); ++ if (nm == nullptr) { ++ log_warning(jbolt)("Recompilation failed because the code is not a nmethod."); ++ return; ++ } ++ CodeBlobType code_blob_type = CodeCache::get_code_blob_type(nm); ++ if (code_blob_type != check_blob_type) { ++ log_warning(jbolt)("Recompilation failed because the nmethod is not in heap [%s]: it's in [%s].", ++ CodeCache::get_code_heap_name(check_blob_type), CodeCache::get_code_heap_name(code_blob_type)); ++ return; ++ } ++ log_trace(jbolt)("Recompilation good: code=%p, size=%d, method=%s, heap=%s.", ++ nm, nm->size(), method->name_and_sig_as_C_string(), CodeCache::get_code_heap_name(check_blob_type)); ++} ++ ++/** ++ * Create the compile task instance and enqueue into compile queue ++ */ ++bool JBoltManager::enqueue_recompile_task(CompileTaskInfo* cti, methodHandle& method, methodHandle& hot_method, TRAPS) { ++ CompileTask* task = nullptr; ++ CompileQueue* queue = CompileBroker::compile_queue(cti->comp_level()); ++ { MutexLocker locker(THREAD, MethodCompileQueue_lock); ++ if (CompileBroker::compilation_is_in_queue(method)) { ++ log_warning(jbolt)("JBOLT won't compile as \"compilation is in queue\": method=%s.", method->name_and_sig_as_C_string()); ++ return false; ++ } ++ ++ task = create_a_task_instance(cti, method, hot_method, CHECK_AND_CLEAR_false); ++ if (task == nullptr) { ++ log_warning(jbolt)("JBOLT won't compile as \"task instance is NULL\": method=%s.", method->name_and_sig_as_C_string()); ++ return false; ++ } ++ queue->add(task); ++ } ++ ++ // Same waiting logic as CompileBroker::wait_for_completion(). ++ { MonitorLocker ml(THREAD, task->lock()); ++ while (!task->is_complete() && !CompileBroker::is_compilation_disabled_forever()) { ++ ml.wait(); ++ } ++ } ++ ++ CompileBroker::wait_for_completion(task); ++ task = nullptr; // freed ++ return true; ++} ++ ++/** ++ * Recompilation is to move the nmethod to _primary_hot_seg. ++ */ ++bool JBoltManager::recompile_one(CompileTaskInfo* cti, methodHandle& method, methodHandle& hot_method, TRAPS) { ++ ResourceMark rm(THREAD); ++ ++ if (cti->osr_bci() != InvocationEntryBci) { ++ log_trace(jbolt)("We don't handle on-stack-replacement nmethods: method=%s.", method->name_and_sig_as_C_string()); ++ return false; ++ } ++ ++ if (log_is_enabled(Trace, jbolt)) { ++ const char* heap_name = nullptr; ++ CompiledMethod* cm = method->code(); ++ if (cm == nullptr) heap_name = ""; ++ else if (!cm->is_nmethod()) heap_name = ""; ++ else heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(cm)); ++ log_trace(jbolt)("Start to recompile & reorder: heap=%s, method=%s.", heap_name, method->name_and_sig_as_C_string()); ++ } ++ ++ // Add a compilation task. ++ set_cur_reordering_method(method()); ++ enqueue_recompile_task(cti, method, hot_method, CHECK_AND_CLEAR_false); ++ check_compiled_result(method(), primary_hot_seg(), CHECK_AND_CLEAR_false); ++ ++ return true; ++} ++ ++/** ++ * This method is invoked in a new thread JBoltControlThread. ++ * Recompiles the methods in the order list one by one (serially) based on the hot order. ++ * The methods to recompile were almost all in MethodJBoltTmp, and will in install in ++ * MethodJBoltHot after recompilation. ++ */ ++void JBoltManager::reorder_all_methods(TRAPS) { ++ guarantee(UseJBolt && reorder_phase_is_reordering(), "sanity"); ++ log_info(jbolt)("Start to reorder!"); ++ print_code_heaps(); ++ ++ ResourceMark rm(THREAD); ++ for (int i = 0; i < _hot_methods_sorted->length(); ++i) { ++ JBoltMethodKey k = _hot_methods_sorted->at(i); ++ JBoltMethodValue* v = _hot_methods_vis->get(k); ++ if (v == nullptr) continue; ++ CompileTaskInfo* cti = v->get_comp_info(); ++ if (cti == nullptr) continue; ++ if (!cti->try_select()) continue; ++ ++ methodHandle method(THREAD, cti->method()); ++ methodHandle hot_method(THREAD, cti->hot_method()); ++ ++ recompile_one(cti, method, hot_method, THREAD); ++ if (HAS_PENDING_EXCEPTION) { ++ Handle ex(THREAD, PENDING_EXCEPTION); ++ CLEAR_PENDING_EXCEPTION; ++ LogTarget(Warning, jbolt) lt; ++ if (lt.is_enabled()) { ++ LogStream ls(lt); ++ ls.print("Failed to recompile the method: %s.", method->name_and_sig_as_C_string()); ++ java_lang_Throwable::print(ex(), &ls); ++ } ++ } ++ } ++ ++ log_info(jbolt)("JBolt reordering succeeds."); ++ print_code_heaps(); ++ ++} ++ ++void JBoltManager::clear_structures() { ++ delete _sampled_methods_refs; ++ _sampled_methods_refs = nullptr; ++ JBoltCallGraph::deinitialize(); ++ set_cur_reordering_method(nullptr); ++ delete _hot_methods_sorted; ++ _hot_methods_sorted = nullptr; ++ delete _hot_methods_vis; ++ _hot_methods_vis = nullptr; ++} ++ ++void JBoltManager::print_code_heap(outputStream& ls, CodeHeap* heap, const char* name) { ++ for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { ++ nmethod* nm = cb->as_nmethod_or_null(); ++ Method* m = nm != nullptr ? nm->method() : nullptr; ++ ls.print_cr("%s %p %d nmethod=%s, entrant=%s, name=[%s %s %s]", ++ name, ++ cb, cb->size(), ++ B_TF(cb->is_nmethod()), ++ nm ? B_TF(!nm->is_not_entrant()) : "?", ++ m ? m->method_holder()->name()->as_C_string() : cb->name(), ++ m ? m->name()->as_C_string() : nullptr, ++ m ? m->signature()->as_C_string() : nullptr); ++ } ++} ++ ++void JBoltManager::print_code_heaps() { ++ { ++ LogTarget(Debug, jbolt) lt; ++ if (!lt.is_enabled()) return; ++ LogStream ls(lt); ++ MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); ++ CodeCache::print_summary(&ls, true); ++ } ++ ++ { ++ LogTarget(Trace, jbolt) lt; ++ if (!lt.is_enabled()) return; ++ LogStream ls(lt); ++ CodeHeap* hot_heap = CodeCache::get_code_heap(CodeBlobType::MethodJBoltHot); ++ CodeHeap* tmp_heap = CodeCache::get_code_heap(CodeBlobType::MethodJBoltTmp); ++ ++ ResourceMark rm; ++ if (hot_heap == nullptr) { ++ ls.print_cr("The jbolt hot heap is null."); ++ } else { ++ print_code_heap(ls, hot_heap, "hot"); ++ } ++ if (tmp_heap == nullptr) { ++ ls.print_cr("The jbolt tmp heap is null."); ++ } else { ++ print_code_heap(ls, tmp_heap, "tmp"); ++ } ++ } ++} ++ ++#undef B_TF +\ No newline at end of file +diff --git a/src/hotspot/share/jbolt/jBoltManager.hpp b/src/hotspot/share/jbolt/jBoltManager.hpp +new file mode 100644 +index 000000000..c0e752073 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltManager.hpp +@@ -0,0 +1,335 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLTMANAGER_HPP ++#define SHARE_JBOLT_JBOLTMANAGER_HPP ++ ++#include "compiler/compileTask.hpp" ++#include "jbolt/jbolt_globals.hpp" ++#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" ++#include "jfr/dcmd/jfrDcmds.hpp" ++#include "memory/allocation.hpp" ++#include "memory/heap.hpp" ++#include "oops/symbol.hpp" ++#include "runtime/handles.hpp" ++#include "utilities/growableArray.hpp" ++#include "utilities/resourceHash.hpp" ++ ++class CompileTask; ++class CompileTaskInfo; ++class Method; ++class Thread; ++ ++enum JBoltErrorCode { ++ JBoltOK = 0, ++ JBoltOrderNULL = 1, ++ JBoltOpenFileError = 2 ++}; ++ ++struct JBoltReorderPhase { ++ static const int Waiting = -1; // JBolt logic is waiting for something to be done. ++ static const int Available = 0; // JBolt logic is not working or is done (can be reordered again now). ++ static const int Collecting = 1; // Collecting methods in the order file (this phase is for two-phase only). ++ static const int Profiling = 2; // JFR is working (this phase is for one-phase only). ++ static const int Reordering = 3; // Recompiling and re-laying. ++ static const int End = 4; // JBolt is not available anymore (for two-phase, or error happened on one-phase). ++}; ++ ++class JBoltMethodKey : public StackObj { ++ Symbol* _klass; ++ Symbol* _name; ++ Symbol* _sig; ++ ++ void inc_ref_cnt() { ++ Symbol* arr[] = { _klass, _name, _sig }; ++ for (int i = 0; i < (int) (sizeof(arr) / sizeof(arr[0])); ++i) { ++ if (arr[i] != nullptr) arr[i]->increment_refcount(); ++ } ++ } ++ ++ void dec_ref_cnt() { ++ Symbol* arr[] = { _klass, _name, _sig }; ++ for (int i = 0; i < (int) (sizeof(arr) / sizeof(arr[0])); ++i) { ++ if (arr[i] != nullptr) arr[i]->decrement_refcount(); ++ } ++ } ++public: ++ ++ JBoltMethodKey(Symbol* klass, Symbol* name, Symbol* sig): _klass(klass), _name(name), _sig(sig) { /* no inc_ref_cnt() here for SymbolTable::new_symbol() */ } ++ JBoltMethodKey(Method* method): _klass(method->method_holder()->name()), _name(method->name()), _sig(method->signature()) { inc_ref_cnt(); } ++ JBoltMethodKey(const JBoltMethodKey& other): _klass(other._klass), _name(other._name), _sig(other._sig) { inc_ref_cnt(); } ++ JBoltMethodKey(): _klass(nullptr), _name(nullptr), _sig(nullptr) {} ++ ~JBoltMethodKey() { dec_ref_cnt(); } ++ ++ JBoltMethodKey& operator = (const JBoltMethodKey& other) { ++ dec_ref_cnt(); ++ _klass = other._klass; ++ _name = other._name; ++ _sig = other._sig; ++ inc_ref_cnt(); ++ return *this; ++ } ++ ++ unsigned hash() const { ++ int v = primitive_hash(_klass); ++ v = v * 31 + primitive_hash(_name); ++ v = v * 31 + primitive_hash(_sig); ++ return v; ++ } ++ bool equals(const JBoltMethodKey& other) const { ++ return _klass == other._klass && _name == other._name && _sig == other._sig; ++ } ++ ++ static unsigned calc_hash(const JBoltMethodKey& k) { ++ return k.hash(); ++ } ++ static bool calc_equals(const JBoltMethodKey& k1, const JBoltMethodKey& k2) { ++ return k1.equals(k2); ++ } ++ ++ Symbol* klass() const { return _klass; } ++ Symbol* name() const { return _name; } ++ Symbol* sig() const { return _sig; } ++}; ++ ++class JBoltMethodValue : public StackObj { ++private: ++ CompileTaskInfo* volatile _comp_info; ++ ++public: ++ JBoltMethodValue(): _comp_info(nullptr) {} ++ ~JBoltMethodValue(); ++ ++ CompileTaskInfo* get_comp_info(); ++ bool set_comp_info(CompileTaskInfo* info); ++ void clear_comp_info_but_not_release(); ++}; ++ ++class CompileTaskInfo : public CHeapObj { ++ Method* const _method; ++ jobject _method_holder; ++ const int _osr_bci; ++ const int _comp_level; ++ const int _comp_reason; ++ Method* const _hot_method; ++ jobject _hot_method_holder; ++ const int _hot_count; ++ ++public: ++ CompileTaskInfo(Method* method, int osr_bci, int comp_level, int comp_reason, Method* hot_method, int hot_cnt); ++ ~CompileTaskInfo(); ++ ++ bool try_select(); ++ ++ Method* method() const { return _method; } ++ int osr_bci() const { return _osr_bci; } ++ int comp_level() const { return _comp_level; } ++ int comp_reason() const { return _comp_reason; } ++ Method* hot_method() const { return _hot_method; } ++ int hot_count() const { return _hot_count; } ++}; ++ ++class JBoltStackFrameKey : public StackObj { ++ InstanceKlass* _klass; ++ traceid _methodid; ++ ++public: ++ JBoltStackFrameKey(InstanceKlass* klass, traceid methodid): _klass(klass), _methodid(methodid) {} ++ JBoltStackFrameKey(const JBoltStackFrameKey& other): _klass(other._klass), _methodid(other._methodid) {} ++ JBoltStackFrameKey(): _klass(NULL), _methodid(0) {} ++ ~JBoltStackFrameKey() { /* nothing to do as _klass is a softcopy of JfrStackFrame::_klass */ } ++ ++ ++ JBoltStackFrameKey& operator = (const JBoltStackFrameKey& other) { ++ _klass = other._klass; ++ _methodid = other._methodid; ++ return *this; ++ } ++ ++ unsigned hash() const { ++ int v = primitive_hash(_klass); ++ v = v * 31 + primitive_hash(_methodid); ++ return v; ++ } ++ ++ bool equals(const JBoltStackFrameKey& other) const { ++ return _klass == other._klass && _methodid == other._methodid; ++ } ++ ++ static unsigned calc_hash(const JBoltStackFrameKey& k) { ++ return k.hash(); ++ } ++ ++ static bool calc_equals(const JBoltStackFrameKey& k1, const JBoltStackFrameKey& k2) { ++ return k1.equals(k2); ++ } ++}; ++ ++class JBoltStackFrameValue : public StackObj { ++private: ++ jobject _method_holder; ++ ++public: ++ JBoltStackFrameValue(jobject method_holder): _method_holder(method_holder) {} ++ ~JBoltStackFrameValue(); ++ ++ jobject get_method_holder(); ++ void clear_method_holder_but_not_release(); ++}; ++ ++class JBoltManager : public AllStatic { ++ friend class JBoltControlThread; ++ ++ typedef ResourceHashtable MethodKeyMap; ++ ++ typedef ResourceHashtable StackFrameKeyMap; ++ ++ static GrowableArray* _hot_methods_sorted; ++ static MethodKeyMap* _hot_methods_vis; ++ static int _reorder_method_threshold_cnt; ++ ++ static volatile int _reorder_phase; ++ static volatile int _reorderable_method_cnt; ++ static Method* volatile _cur_reordering_method; ++ ++ // the CompilerThread to start the new JBoltControlThread ++ static Thread* _start_reordering_thread; ++ ++ static StackFrameKeyMap* _sampled_methods_refs; ++ ++ // when not set JBoltDumpMode or JBoltLoadMode, JBolt will be in one-step auto mode. ++ static bool _auto_mode; ++ ++ // use MethodJBoltHot and MethodJBoltTmp as two semi hot space. ++ // each time restart a schedule, we exchange primary and secondary ++ static volatile int _primary_hot_seg; ++ static volatile int _secondary_hot_seg; ++ ++ static volatile int _gc_should_sweep_code_heaps_now; ++ ++private: ++ // Used in dump mode. ++ static methodHandle lookup_method(InstanceKlass* klass, traceid method_id); ++ static void construct_stacktrace(const JfrStackTrace &stacktrace); ++ ++ // Used in init phase 1. ++ static void check_mode(); ++ static void check_order_file(); ++ static void check_dependency(); ++ static size_t calc_nmethod_size_with_padding(size_t nmethod_size); ++ static size_t calc_segment_size_with_padding(size_t segment_size); ++ static void load_order_file_phase1(int* method_cnt , size_t* total_nmethod_size); ++ static void init_load_mode_phase1(); ++ ++ // Used in init phase 2. ++ static bool parse_method_line_phase2(char* const line, const int len); ++ static bool parse_connected_component_line_phase2(char* const line, const int len); ++ static void load_order_file_phase2(TRAPS); ++ static void init_load_mode_phase2(TRAPS); ++ static void init_dump_mode_phase2(TRAPS); ++ ++ // Used in auto mode. ++ static CodeBlobType primary_hot_seg(); ++ static CodeBlobType secondary_hot_seg(); ++ ++ // Used in auto mode prev_control_schedule ++ static int clear_last_sample_datas(); ++ static void swap_semi_jbolt_segs(); ++ static int clear_manager(); ++ ++ // Used in auto mode control_schedule ++ static void init_auto_transition(size_t* segment_size, TRAPS); ++ ++ // Used in auto mode post_control_schedule ++ static void clear_secondary_hot_seg(TRAPS); ++ ++ // JBolt phases ++ ++ static int reorder_phase(); ++ ++ static bool reorder_phase_available_to_collecting(); ++ static bool reorder_phase_collecting_to_reordering(); ++ ++ static bool reorder_phase_available_to_profiling(); ++ static bool reorder_phase_profiling_to_reordering(); ++ static bool reorder_phase_reordering_to_available(); ++ static bool reorder_phase_profiling_to_available(); ++ static bool reorder_phase_profiling_to_waiting(); ++ static bool reorder_phase_waiting_to_reordering(); ++ static bool reorder_phase_waiting_to_available(); ++ ++ static bool reorder_phase_reordering_to_end(); ++ ++ static Method* cur_reordering_method(); ++ static void set_cur_reordering_method(Method* method); ++ static int inc_reorderable_method_cnt(); ++ ++ // Used in reordering phase. ++ static CompileTask* create_a_task_instance(CompileTaskInfo* cti, methodHandle& method, methodHandle& hot_method, TRAPS); ++ static void check_compiled_result(Method* method, CodeBlobType check_blob_type, TRAPS); ++ static bool enqueue_recompile_task(CompileTaskInfo* cti, methodHandle& method, methodHandle& hot_method, TRAPS); ++ static bool recompile_one(CompileTaskInfo* cti, methodHandle& method, methodHandle& hot_method, TRAPS); ++ ++ static void print_code_heap(outputStream& ls, CodeHeap* heap, const char* name); ++public: ++ static void log_stacktrace(const JfrStackTrace &stacktrace); ++ static void construct_cg_once(); ++ static void dump_order_in_manual(); ++ static JBoltErrorCode dump_order_in_jcmd(const char* filename); ++ ++ static void check_arguments_not_set(); ++ static void init_phase1(); ++ static void init_phase2(TRAPS); ++ static void init_code_heaps(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, size_t ps, size_t alignment); ++ ++ static bool auto_mode() { return _auto_mode; } ++ ++ static bool reorder_phase_is_waiting(); ++ static bool reorder_phase_is_available(); ++ static bool reorder_phase_is_collecting(); ++ static bool reorder_phase_is_profiling(); ++ static bool reorder_phase_is_reordering(); ++ static bool reorder_phase_is_profiling_or_waiting(); ++ static bool reorder_phase_is_collecting_or_reordering(); ++ ++ static bool can_reorder_now(); ++ static bool should_reorder_now(); ++ ++ static bool gc_should_sweep_code_heaps_now(); ++ ++ static CodeBlobType calc_code_blob_type(Method* method, CompileTask* task, TRAPS); ++ ++ static void check_start_reordering(TRAPS); ++ static void reorder_all_methods(TRAPS); ++ static void clear_structures(); ++ ++ static void print_code_heaps(); ++}; ++ ++#endif // SHARE_JBOLT_JBOLTMANAGER_HPP +diff --git a/src/hotspot/share/jbolt/jBoltUtils.cpp b/src/hotspot/share/jbolt/jBoltUtils.cpp +new file mode 100644 +index 000000000..e48d3b046 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltUtils.cpp +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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 "jbolt/jBoltUtils.hpp" ++ ++JBoltUtils::MetaDataKeepAliveMark::MetaDataKeepAliveMark(Thread* thread) : _thread(thread), _kept() { ++ assert(thread == Thread::current(), "Must be current thread"); ++ assert(_thread->is_in_live_stack((address)this), "not on stack?"); ++} ++ ++JBoltUtils::MetaDataKeepAliveMark::~MetaDataKeepAliveMark() { ++ for (int i = _kept.length() - 1; i >= 0; --i) { ++ Metadata* md = _kept.at(i); ++ int idx = _thread->metadata_handles()->find_from_end(md); ++ assert(idx != -1, "not in metadata_handles list"); ++ _thread->metadata_handles()->remove_at(idx); ++ } ++} +diff --git a/src/hotspot/share/jbolt/jBoltUtils.hpp b/src/hotspot/share/jbolt/jBoltUtils.hpp +new file mode 100644 +index 000000000..c2da35519 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltUtils.hpp +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLTUTILS_HPP ++#define SHARE_JBOLT_JBOLTUTILS_HPP ++ ++#include "memory/allocation.hpp" ++#include "oops/metadata.hpp" ++#include "runtime/thread.hpp" ++#include "utilities/growableArray.hpp" ++ ++class JBoltUtils : public AllStatic { ++public: ++ /** ++ * Keep the metadata alive. ++ * ++ * @see KeepAliveRegistrar ++ * @see methodHandle ++ */ ++ class MetaDataKeepAliveMark : public StackObj { ++ private: ++ Thread* _thread; ++ GrowableArray _kept; ++ ++ public: ++ MetaDataKeepAliveMark(Thread* thread); ++ ~MetaDataKeepAliveMark(); ++ ++ void add(Metadata* md); ++ ++ const GrowableArray& kept() { return _kept; } ++ }; ++}; ++ ++#endif // SHARE_JBOLT_JBOLTUTILS_HPP +diff --git a/src/hotspot/share/jbolt/jBoltUtils.inline.hpp b/src/hotspot/share/jbolt/jBoltUtils.inline.hpp +new file mode 100644 +index 000000000..abd7501ca +--- /dev/null ++++ b/src/hotspot/share/jbolt/jBoltUtils.inline.hpp +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLTUTILS_INLINE_HPP ++#define SHARE_JBOLT_JBOLTUTILS_INLINE_HPP ++ ++#include "jbolt/jBoltUtils.hpp" ++ ++// Register a metadata as 'in-use' by the thread. It's fine to register a ++// metadata multiple times (though perhaps inefficient). ++inline void JBoltUtils::MetaDataKeepAliveMark::add(Metadata* md) { ++ assert(md->is_valid(), "obj is valid"); ++ assert(_thread == Thread::current(), "thread must be current"); ++ _kept.push(md); ++ _thread->metadata_handles()->push(md); ++} ++ ++#endif // SHARE_JBOLT_JBOLTUTILS_INLINE_HPP +diff --git a/src/hotspot/share/jbolt/jbolt_globals.hpp b/src/hotspot/share/jbolt/jbolt_globals.hpp +new file mode 100644 +index 000000000..355e79672 +--- /dev/null ++++ b/src/hotspot/share/jbolt/jbolt_globals.hpp +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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_JBOLT_JBOLT_GLOBALS_HPP ++#define SHARE_JBOLT_JBOLT_GLOBALS_HPP ++ ++#include "runtime/globals_shared.hpp" ++ ++#define JBOLT_FLAGS(develop, \ ++ develop_pd, \ ++ product, \ ++ product_pd, \ ++ notproduct, \ ++ range, \ ++ constraint) \ ++ \ ++ product(bool, UseJBolt, false, EXPERIMENTAL, \ ++ "Enable JBolt feature.") \ ++ \ ++ product(bool, JBoltDumpMode, false, EXPERIMENTAL, \ ++ "Trial run of JBolt. Collect profiling and dump it.") \ ++ \ ++ product(bool, JBoltLoadMode, false, EXPERIMENTAL, \ ++ "Second run of JBolt. Load the profiling and reorder nmethods.") \ ++ \ ++ product(ccstr, JBoltOrderFile, NULL, EXPERIMENTAL, \ ++ "The JBolt method order file to dump or load.") \ ++ \ ++ product(intx, JBoltSampleInterval, 600, EXPERIMENTAL, \ ++ "Sample interval(second) of JBolt dump mode" \ ++ "only useful in auto mode.") \ ++ range(0, max_jint) \ ++ \ ++ product(uintx, JBoltCodeHeapSize, 8*M , EXPERIMENTAL, \ ++ "Code heap size of MethodJBoltHot and MethodJBoltTmp heaps.") \ ++ \ ++ ++// end of JBOLT_FLAGS ++ ++DECLARE_FLAGS(JBOLT_FLAGS) ++ ++#endif // SHARE_JBOLT_JBOLT_GLOBALS_HPP +diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml +index 80ea101a7..3045a46e1 100644 +--- a/src/hotspot/share/jfr/metadata/metadata.xml ++++ b/src/hotspot/share/jfr/metadata/metadata.xml +@@ -988,6 +988,8 @@ + + + ++ ++ + + + +diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +index ff52b4104..0582f91eb 100644 +--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp ++++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +@@ -75,6 +75,9 @@ + #if INCLUDE_SHENANDOAHGC + #include "gc/shenandoah/shenandoahJfrSupport.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jbolt_globals.hpp" ++#endif // INCLUDE_JBOLT + + /** + * JfrPeriodic class +@@ -692,6 +695,10 @@ TRACE_REQUEST_FUNC(CodeCacheConfiguration) { + event.set_nonNMethodSize(NonNMethodCodeHeapSize); + event.set_profiledSize(ProfiledCodeHeapSize); + event.set_nonProfiledSize(NonProfiledCodeHeapSize); ++#if INCLUDE_JBOLT ++ event.set_jboltHotSize(JBoltCodeHeapSize); ++ event.set_jboltTmpSize(JBoltCodeHeapSize); ++#endif + event.set_expansionSize(CodeCacheExpansionSize); + event.set_minBlockLength(CodeCacheMinBlockLength); + event.set_startAddress((u8)CodeCache::low_bound()); +diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +index bda6acbc8..1270a5c63 100644 +--- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp ++++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +@@ -46,6 +46,9 @@ + #include "runtime/threadCrashProtection.hpp" + #include "runtime/threadSMR.hpp" + #include "utilities/systemMemoryBarrier.hpp" ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif + + enum JfrSampleType { + NO_SAMPLE = 0, +@@ -273,7 +276,15 @@ bool JfrThreadSampleClosure::sample_thread_in_java(JavaThread* thread, JfrStackF + return false; + } + EventExecutionSample *event = &_events[_added_java - 1]; +- traceid id = JfrStackTraceRepository::add(sampler.stacktrace()); ++ traceid id = 0; ++#if INCLUDE_JBOLT ++ if (UseJBolt && JBoltManager::reorder_phase_is_profiling()) { ++ id = JfrStackTraceRepository::add_jbolt(sampler.stacktrace()); ++ } else ++#endif ++ { ++ id = JfrStackTraceRepository::add(sampler.stacktrace()); ++ } + assert(id != 0, "Stacktrace id should not be 0"); + event->set_stackTrace(id); + return true; +diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp +index 48db2fd87..a68d6ea22 100644 +--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp ++++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp +@@ -62,7 +62,11 @@ JfrStackTrace::JfrStackTrace(JfrStackFrame* frames, u4 max_frames) : + _frames_ownership(false), + _reached_root(false), + _lineno(false), +- _written(false) {} ++ _written(false) ++#if INCLUDE_JBOLT ++ , _hotcount(1) ++#endif ++ {} + + JfrStackTrace::JfrStackTrace(traceid id, const JfrStackTrace& trace, const JfrStackTrace* next) : + _next(next), +@@ -74,7 +78,11 @@ JfrStackTrace::JfrStackTrace(traceid id, const JfrStackTrace& trace, const JfrSt + _frames_ownership(true), + _reached_root(trace._reached_root), + _lineno(trace._lineno), +- _written(false) { ++ _written(false) ++#if INCLUDE_JBOLT ++ , _hotcount(trace._hotcount) ++#endif ++{ + copy_frames(&_frames, trace._nr_of_frames, trace._frames); + } + +diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp +index 49e7d7a19..a89b09359 100644 +--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp ++++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp +@@ -52,6 +52,17 @@ class JfrStackFrame { + void write(JfrCheckpointWriter& cpw) const; + void resolve_lineno() const; + ++#if INCLUDE_JBOLT ++ const InstanceKlass* get_klass() const { return _klass; } ++ traceid get_methodId() const { return _methodid; } ++ int get_byteCodeIndex() const { return _bci; } ++ u1 get_type() const { return _type; } ++ ++ static ByteSize klass_offset() { return byte_offset_of(JfrStackFrame, _klass ); } ++ static ByteSize methodid_offset() { return byte_offset_of(JfrStackFrame, _methodid ); } ++ static ByteSize bci_offset() { return byte_offset_of(JfrStackFrame, _bci ); } ++ static ByteSize type_offset() { return byte_offset_of(JfrStackFrame, _type ); } ++#endif + enum { + FRAME_INTERPRETER = 0, + FRAME_JIT, +@@ -68,6 +79,10 @@ class JfrStackTrace : public JfrCHeapObj { + friend class ObjectSampler; + friend class OSThreadSampler; + friend class StackTraceResolver; ++#if INCLUDE_JBOLT ++ friend class JBoltManager; ++#endif ++ + private: + const JfrStackTrace* _next; + JfrStackFrame* _frames; +@@ -79,6 +94,9 @@ class JfrStackTrace : public JfrCHeapObj { + bool _reached_root; + mutable bool _lineno; + mutable bool _written; ++#if INCLUDE_JBOLT ++ u4 _hotcount; ++#endif + + const JfrStackTrace* next() const { return _next; } + +@@ -107,6 +125,17 @@ class JfrStackTrace : public JfrCHeapObj { + public: + unsigned int hash() const { return _hash; } + traceid id() const { return _id; } ++#if INCLUDE_JBOLT ++ u4 hotcount() const { return _hotcount; } ++ const JfrStackFrame* get_frames() const { return _frames; } ++ u4 get_framesCount() const { return _nr_of_frames; } ++ ++ static ByteSize hash_offset() { return byte_offset_of(JfrStackTrace, _hash ); } ++ static ByteSize id_offset() { return byte_offset_of(JfrStackTrace, _id ); } ++ static ByteSize hotcount_offset() { return byte_offset_of(JfrStackTrace, _hotcount ); } ++ static ByteSize frames_offset() { return byte_offset_of(JfrStackTrace, _frames ); } ++ static ByteSize frames_count_offset() { return byte_offset_of(JfrStackTrace, _nr_of_frames ); } ++#endif + }; + + #endif // SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACE_HPP +diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp +index 7caada5ab..250535803 100644 +--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp ++++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp +@@ -29,6 +29,9 @@ + #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" + #include "jfr/support/jfrThreadLocal.hpp" + #include "runtime/mutexLocker.hpp" ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif + + /* + * There are two separate repository instances. +@@ -51,9 +54,16 @@ static JfrStackTraceRepository& leak_profiler_instance() { + return *_leak_profiler_instance; + } + ++#if INCLUDE_JBOLT ++JfrStackTraceRepository::JfrStackTraceRepository() : _last_entries(0), _entries(0), _last_entries_jbolt(0), _entries_jbolt(0) { ++ memset(_table, 0, sizeof(_table)); ++ memset(_table_jbolt, 0, sizeof(_table_jbolt)); ++} ++#else + JfrStackTraceRepository::JfrStackTraceRepository() : _last_entries(0), _entries(0) { + memset(_table, 0, sizeof(_table)); + } ++#endif + + JfrStackTraceRepository* JfrStackTraceRepository::create() { + assert(_instance == nullptr, "invariant"); +@@ -98,6 +108,11 @@ bool JfrStackTraceRepository::is_modified() const { + } + + size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) { ++#if INCLUDE_JBOLT ++ if (clear && (UseJBolt && JBoltManager::reorder_phase_is_profiling_or_waiting())) { ++ JBoltManager::construct_cg_once(); ++ } ++#endif + MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); + if (_entries == 0) { + return 0; +@@ -120,6 +135,21 @@ size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) { + if (clear) { + memset(_table, 0, sizeof(_table)); + _entries = 0; ++#if INCLUDE_JBOLT ++ for (u4 i = 0; i < TABLE_SIZE; ++i) { ++ JfrStackTrace* stacktrace = _table_jbolt[i]; ++ while (stacktrace != NULL) { ++ JfrStackTrace* next = const_cast(stacktrace->next()); ++ delete stacktrace; ++ stacktrace = next; ++ } ++ } ++ memset(_table_jbolt, 0, sizeof(_table_jbolt)); ++ _entries_jbolt = 0; ++ } ++ _last_entries_jbolt = _entries_jbolt; ++ { ++#endif + } + _last_entries = _entries; + return count; +@@ -142,6 +172,21 @@ size_t JfrStackTraceRepository::clear(JfrStackTraceRepository& repo) { + const size_t processed = repo._entries; + repo._entries = 0; + repo._last_entries = 0; ++#if INCLUDE_JBOLT ++ if (repo._entries_jbolt != 0) { ++ for (u4 i = 0; i < TABLE_SIZE; ++i) { ++ JfrStackTrace* stacktrace = repo._table_jbolt[i]; ++ while (stacktrace != NULL) { ++ JfrStackTrace* next = const_cast(stacktrace->next()); ++ delete stacktrace; ++ stacktrace = next; ++ } ++ } ++ memset(repo._table_jbolt, 0, sizeof(repo._table_jbolt)); ++ repo._entries_jbolt = 0; ++ repo._last_entries_jbolt = 0; ++ } ++#endif + return processed; + } + +@@ -233,6 +278,75 @@ const JfrStackTrace* JfrStackTraceRepository::lookup_for_leak_profiler(unsigned + return trace; + } + ++#if INCLUDE_JBOLT ++size_t JfrStackTraceRepository::clear_jbolt(JfrStackTraceRepository& repo) { ++ MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); ++ if (repo._entries_jbolt == 0) { ++ return 0; ++ } ++ ++ for (u4 i = 0; i < TABLE_SIZE; ++i) { ++ JfrStackTrace* stacktrace = repo._table_jbolt[i]; ++ while (stacktrace != NULL) { ++ JfrStackTrace* next = const_cast(stacktrace->next()); ++ delete stacktrace; ++ stacktrace = next; ++ } ++ } ++ memset(repo._table_jbolt, 0, sizeof(repo._table_jbolt)); ++ const size_t processed = repo._entries; ++ repo._entries_jbolt = 0; ++ repo._last_entries_jbolt = 0; ++ ++ return processed; ++} ++ ++size_t JfrStackTraceRepository::clear_jbolt() { ++ clear_jbolt(leak_profiler_instance()); ++ return clear_jbolt(instance()); ++} ++ ++traceid JfrStackTraceRepository::add_jbolt(JfrStackTraceRepository& repo, const JfrStackTrace& stacktrace) { ++ traceid tid = repo.add_trace_jbolt(stacktrace); ++ if (tid == 0) { ++ stacktrace.resolve_linenos(); ++ tid = repo.add_trace_jbolt(stacktrace); ++ } ++ assert(tid != 0, "invariant"); ++ return tid; ++} ++ ++traceid JfrStackTraceRepository::add_jbolt(const JfrStackTrace& stacktrace) { ++ JBoltManager::log_stacktrace(stacktrace); ++ return add_jbolt(instance(), stacktrace); ++} ++ ++traceid JfrStackTraceRepository::add_trace_jbolt(const JfrStackTrace& stacktrace) { ++ traceid id = add_trace(stacktrace); ++ MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); ++ const size_t index = stacktrace._hash % TABLE_SIZE; ++ ++ if (UseJBolt && JBoltManager::reorder_phase_is_profiling()) { ++ const JfrStackTrace* table_jbolt_entry = _table_jbolt[index]; ++ while (table_jbolt_entry != NULL) { ++ if (table_jbolt_entry->equals(stacktrace)) { ++ // [jbolt]: each time add an old trace, inc its hotcount ++ const_cast(table_jbolt_entry)->_hotcount++; ++ return table_jbolt_entry->id(); ++ } ++ table_jbolt_entry = table_jbolt_entry->next(); ++ } ++ } ++ ++ if (id != 0 && UseJBolt && JBoltManager::reorder_phase_is_profiling()) { ++ _table_jbolt[index] = new JfrStackTrace(id, stacktrace, _table_jbolt[index]); ++ ++_entries_jbolt; ++ } ++ ++ return id; ++} ++#endif ++ + void JfrStackTraceRepository::clear_leak_profiler() { + clear(leak_profiler_instance()); + } +diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp +index ba0f966ed..dbedb947f 100644 +--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp ++++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp +@@ -42,6 +42,9 @@ class JfrStackTraceRepository : public JfrCHeapObj { + friend class RecordStackTrace; + friend class StackTraceBlobInstaller; + friend class StackTraceRepository; ++#if INCLUDE_JBOLT ++ friend class JBoltManager; ++#endif + + private: + static const u4 TABLE_SIZE = 2053; +@@ -49,6 +52,19 @@ class JfrStackTraceRepository : public JfrCHeapObj { + u4 _last_entries; + u4 _entries; + ++#if INCLUDE_JBOLT ++ // [jbolt]: an exclusive table for jbolt. It should be a subset of _table ++ JfrStackTrace* _table_jbolt[TABLE_SIZE]; ++ u4 _last_entries_jbolt; ++ u4 _entries_jbolt; ++ ++ static size_t clear_jbolt(); ++ static size_t clear_jbolt(JfrStackTraceRepository& repo); ++ traceid add_trace_jbolt(const JfrStackTrace& stacktrace); ++ static traceid add_jbolt(JfrStackTraceRepository& repo, const JfrStackTrace& stacktrace); ++ static traceid add_jbolt(const JfrStackTrace& stacktrace); ++#endif ++ + JfrStackTraceRepository(); + static JfrStackTraceRepository& instance(); + static JfrStackTraceRepository* create(); +@@ -71,6 +87,13 @@ class JfrStackTraceRepository : public JfrCHeapObj { + + public: + static traceid record(Thread* current_thread, int skip = 0); ++#if INCLUDE_JBOLT ++ const JfrStackTrace* const * get_stacktrace_table() const { return _table; } ++ u4 get_entries_count() const { return _entries; } ++ ++ const JfrStackTrace* const * get_stacktrace_table_jbolt() const { return _table_jbolt; } ++ u4 get_entries_count_jbolt() const { return _entries_jbolt; } ++#endif + }; + + #endif // SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP +diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp +index 99adff484..4ea67e3ff 100644 +--- a/src/hotspot/share/logging/logTag.hpp ++++ b/src/hotspot/share/logging/logTag.hpp +@@ -98,6 +98,7 @@ class outputStream; + LOG_TAG(install) \ + LOG_TAG(interpreter) \ + LOG_TAG(itables) \ ++ JBOLT_ONLY(LOG_TAG(jbolt)) \ + LOG_TAG(jfr) \ + LOG_TAG(jit) \ + LOG_TAG(jni) \ +diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp +index c852316f8..9a0d64a33 100644 +--- a/src/hotspot/share/opto/doCall.cpp ++++ b/src/hotspot/share/opto/doCall.cpp +@@ -1053,8 +1053,8 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { + + #ifndef PRODUCT + void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) { +- if( CountCompiledCalls ) { +- if( at_method_entry ) { ++ if(CountCompiledCalls) { ++ if(at_method_entry) { + // bump invocation counter if top method (for statistics) + if (CountCompiledCalls && depth() == 1) { + const TypePtr* addr_type = TypeMetadataPtr::make(method()); +diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp +index 4d71e552e..6e8fb2e67 100644 +--- a/src/hotspot/share/opto/parse1.cpp ++++ b/src/hotspot/share/opto/parse1.cpp +@@ -1216,7 +1216,7 @@ void Parse::do_method_entry() { + set_parse_bci(InvocationEntryBci); // Pseudo-BCP + set_sp(0); // Java Stack Pointer + +- NOT_PRODUCT( count_compiled_calls(true/*at_method_entry*/, false/*is_inline*/); ) ++ NOT_PRODUCT(count_compiled_calls(true/* at_method_entry */, false/* is_inline */);) + + if (C->env()->dtrace_method_probes()) { + make_dtrace_method_entry(method()); +diff --git a/src/hotspot/share/runtime/flags/allFlags.hpp b/src/hotspot/share/runtime/flags/allFlags.hpp +index 03a51891e..19292dcb2 100644 +--- a/src/hotspot/share/runtime/flags/allFlags.hpp ++++ b/src/hotspot/share/runtime/flags/allFlags.hpp +@@ -31,6 +31,9 @@ + #include "gc/shared/tlab_globals.hpp" + #include "runtime/flags/debug_globals.hpp" + #include "runtime/globals.hpp" ++#if INCLUDE_JBOLT ++#include "jbolt/jbolt_globals.hpp" ++#endif // INCLUDE_JBOLT + + // Put LP64/ARCH/JVMCI/COMPILER1/COMPILER2 at the top, + // as they are processed by jvmFlag.cpp in that order. +@@ -148,7 +151,17 @@ + product_pd, \ + notproduct, \ + range, \ +- constraint) ++ constraint) \ ++ \ ++ JBOLT_ONLY( \ ++ JBOLT_FLAGS( \ ++ develop, \ ++ develop_pd, \ ++ product, \ ++ product_pd, \ ++ notproduct, \ ++ range, \ ++ constraint)) + + #define ALL_CONSTRAINTS(f) \ + COMPILER_CONSTRAINTS(f) \ +diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp +index a92a1c5d2..52551446c 100644 +--- a/src/hotspot/share/runtime/java.cpp ++++ b/src/hotspot/share/runtime/java.cpp +@@ -97,6 +97,9 @@ + #if INCLUDE_JVMCI + #include "jvmci/jvmci.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltManager.hpp" ++#endif + + GrowableArray* collected_profiled_methods; + +@@ -522,6 +525,12 @@ void before_exit(JavaThread* thread, bool halt) { + // Note: we don't wait until it actually dies. + os::terminate_signal_thread(); + ++#if INCLUDE_JBOLT ++ if (UseJBolt && JBoltDumpMode) { ++ JBoltManager::dump_order_in_manual(); ++ } ++#endif ++ + print_statistics(); + Universe::heap()->print_tracing_info(); + +diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp +index ac435317d..8b7058405 100644 +--- a/src/hotspot/share/runtime/threads.cpp ++++ b/src/hotspot/share/runtime/threads.cpp +@@ -113,6 +113,10 @@ + #if INCLUDE_JFR + #include "jfr/jfr.hpp" + #endif ++#if INCLUDE_JBOLT ++#include "jbolt/jBoltDcmds.hpp" ++#include "jbolt/jBoltManager.hpp" ++#endif // INCLUDE_JBOLT + + // Initialization after module runtime initialization + void universe_post_module_init(); // must happen after call_initPhase2 +@@ -547,6 +551,14 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { + ObjectMonitor::Initialize(); + ObjectSynchronizer::initialize(); + ++#if INCLUDE_JBOLT ++ if (UseJBolt) { ++ JBoltManager::init_phase1(); ++ } else { ++ JBoltManager::check_arguments_not_set(); ++ } ++#endif // INCLUDE_JBOLT ++ + // Initialize global modules + jint status = init_globals(); + if (status != JNI_OK) { +@@ -818,6 +830,13 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { + ShouldNotReachHere(); + } + ++#if INCLUDE_JBOLT ++ register_jbolt_dcmds(); ++ if (UseJBolt) { ++ JBoltManager::init_phase2(CATCH); ++ } ++#endif // INCLUDE_JBOLT ++ + return JNI_OK; + } + +diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp +index 63dbf668e..4731624cf 100644 +--- a/src/hotspot/share/utilities/growableArray.hpp ++++ b/src/hotspot/share/utilities/growableArray.hpp +@@ -31,6 +31,9 @@ + #include "utilities/globalDefinitions.hpp" + #include "utilities/ostream.hpp" + #include "utilities/powerOfTwo.hpp" ++#if INCLUDE_JBOLT ++#include "utilities/sizes.hpp" ++#endif // INCLUDE_JBOLT + + // A growable array. + +@@ -126,6 +129,10 @@ protected: + public: + const static GrowableArrayView EMPTY; + ++#if INCLUDE_JBOLT ++ static ByteSize data_offset() { return byte_offset_of(GrowableArrayView, _data); } ++#endif // INCLUDE_JBOLT ++ + bool operator==(const GrowableArrayView& rhs) const { + if (_len != rhs._len) + return false; +diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp +index 244b18ecd..8526d95fb 100644 +--- a/src/hotspot/share/utilities/macros.hpp ++++ b/src/hotspot/share/utilities/macros.hpp +@@ -129,6 +129,18 @@ + #define NOT_CDS_RETURN_(code) { return code; } + #endif // INCLUDE_CDS + ++#ifndef INCLUDE_JBOLT ++#define INCLUDE_JBOLT 1 ++#endif ++ ++#if INCLUDE_JBOLT ++#define JBOLT_ONLY(x) x ++#define NOT_JBOLT(x) ++#else ++#define JBOLT_ONLY(x) ++#define NOT_JBOLT(x) x ++#endif // INCLUDE_JBOLT ++ + #ifndef INCLUDE_MANAGEMENT + #define INCLUDE_MANAGEMENT 1 + #endif // INCLUDE_MANAGEMENT +@@ -263,6 +275,9 @@ + #define JFR_ONLY(code) + #define NOT_JFR_RETURN() {} + #define NOT_JFR_RETURN_(code) { return code; } ++#if INCLUDE_JBOLT ++#define INCLUDE_JBOLT 0 // INCLUDE_JBOLT depends on INCLUDE_JFR ++#endif + #endif + + #ifndef INCLUDE_JVMCI +diff --git a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java +index eca5c70e0..39f633361 100644 +--- a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java ++++ b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java +@@ -68,12 +68,12 @@ public class CodeCacheCLITestCase { + * Verifies that in interpreted mode PrintCodeCache output contains + * the whole code cache. Int mode disables SegmentedCodeCache with a warning. + */ +- INT_MODE(ONLY_SEGMENTED, EnumSet.of(BlobType.All), USE_INT_MODE), ++ INT_MODE(ONLY_SEGMENTED, EnumSet.copyOf(CodeCacheOptions.NON_SEGMENTED_HEAPS), USE_INT_MODE), + /** + * Verifies that with disabled SegmentedCodeCache PrintCodeCache output + * contains only CodeCache's entry. + */ +- NON_SEGMENTED(options -> !options.segmented, EnumSet.of(BlobType.All), ++ NON_SEGMENTED(options -> !options.segmented, EnumSet.copyOf(CodeCacheOptions.NON_SEGMENTED_HEAPS), + CommandLineOptionTest.prepareBooleanFlag(SEGMENTED_CODE_CACHE, + false)), + /** +@@ -82,7 +82,7 @@ public class CodeCacheCLITestCase { + * profiled-nmethods heap and non-segmented CodeCache. + */ + NON_TIERED(ONLY_SEGMENTED, +- EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled), ++ EnumSet.copyOf(CodeCacheOptions.SEGMENTED_HEAPS_WO_PROFILED), + CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, + false)), + /** +@@ -91,7 +91,7 @@ public class CodeCacheCLITestCase { + * heaps only. + */ + TIERED_LEVEL_0(SEGMENTED_SERVER, +- EnumSet.of(BlobType.All), ++ EnumSet.copyOf(CodeCacheOptions.NON_SEGMENTED_HEAPS), + CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, + true), + CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 0)), +@@ -101,7 +101,7 @@ public class CodeCacheCLITestCase { + * heaps only. + */ + TIERED_LEVEL_1(SEGMENTED_SERVER, +- EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled), ++ EnumSet.copyOf(CodeCacheOptions.SEGMENTED_HEAPS_WO_PROFILED), + CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, + true), + CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 1)), +@@ -110,7 +110,7 @@ public class CodeCacheCLITestCase { + * contain information about all three code heaps. + */ + TIERED_LEVEL_4(SEGMENTED_SERVER, +- EnumSet.complementOf(EnumSet.of(BlobType.All)), ++ EnumSet.copyOf(CodeCacheOptions.ALL_SEGMENTED_HEAPS), + CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, + true), + CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 4)); +diff --git a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java +index f5243aaa4..1830911a9 100644 +--- a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java ++++ b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java +@@ -33,20 +33,27 @@ import java.util.List; + public class CodeCacheOptions { + public static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache"; + +- private static final EnumSet NON_SEGMENTED_HEAPS ++ public static final EnumSet NON_SEGMENTED_HEAPS + = EnumSet.of(BlobType.All); +- private static final EnumSet ALL_SEGMENTED_HEAPS +- = EnumSet.complementOf(NON_SEGMENTED_HEAPS); +- private static final EnumSet SEGMENTED_HEAPS_WO_PROFILED ++ public static final EnumSet JBOLT_HEAPS ++ = EnumSet.of(BlobType.MethodJBoltHot, BlobType.MethodJBoltTmp); ++ public static final EnumSet ALL_SEGMENTED_HEAPS ++ = EnumSet.complementOf(union(NON_SEGMENTED_HEAPS, JBOLT_HEAPS)); ++ public static final EnumSet ALL_SEGMENTED_HEAPS_WITH_JBOLT ++ = union(ALL_SEGMENTED_HEAPS, JBOLT_HEAPS); ++ public static final EnumSet SEGMENTED_HEAPS_WO_PROFILED + = EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled); +- private static final EnumSet ONLY_NON_METHODS_HEAP ++ public static final EnumSet ONLY_NON_METHODS_HEAP + = EnumSet.of(BlobType.NonNMethod); + + public final long reserved; + public final long nonNmethods; + public final long nonProfiled; + public final long profiled; ++ public final long jboltHot; ++ public final long jboltTmp; + public final boolean segmented; ++ public final boolean useJBolt; + + public static long mB(long val) { + return CodeCacheOptions.kB(val) * 1024L; +@@ -56,12 +63,21 @@ public class CodeCacheOptions { + return val * 1024L; + } + ++ public static > EnumSet union(EnumSet e1, EnumSet e2) { ++ EnumSet res = EnumSet.copyOf(e1); ++ res.addAll(e2); ++ return res; ++ } ++ + public CodeCacheOptions(long reserved) { + this.reserved = reserved; + this.nonNmethods = 0; + this.nonProfiled = 0; + this.profiled = 0; ++ this.jboltHot = 0; ++ this.jboltTmp = 0; + this.segmented = false; ++ this.useJBolt = false; + } + + public CodeCacheOptions(long reserved, long nonNmethods, long nonProfiled, +@@ -70,7 +86,25 @@ public class CodeCacheOptions { + this.nonNmethods = nonNmethods; + this.nonProfiled = nonProfiled; + this.profiled = profiled; ++ this.jboltHot = 0; ++ this.jboltTmp = 0; + this.segmented = true; ++ this.useJBolt = false; ++ } ++ ++ /** ++ * No tests for JBolt yet as the related VM options are experimental now. ++ */ ++ public CodeCacheOptions(long reserved, long nonNmethods, long nonProfiled, ++ long profiled, long jboltHot, long jboltTmp) { ++ this.reserved = reserved; ++ this.nonNmethods = nonNmethods; ++ this.nonProfiled = nonProfiled; ++ this.profiled = profiled; ++ this.jboltHot = jboltHot; ++ this.jboltTmp = jboltTmp; ++ this.segmented = true; ++ this.useJBolt = true; + } + + public long sizeForHeap(BlobType heap) { +@@ -83,6 +117,10 @@ public class CodeCacheOptions { + return this.nonProfiled; + case MethodProfiled: + return this.profiled; ++ case MethodJBoltHot: ++ return this.jboltHot; ++ case MethodJBoltTmp: ++ return this.jboltTmp; + default: + throw new Error("Unknown heap: " + heap.name()); + } +@@ -107,14 +145,26 @@ public class CodeCacheOptions { + CommandLineOptionTest.prepareNumericFlag( + BlobType.MethodProfiled.sizeOptionName, profiled)); + } ++ ++ if (useJBolt) { ++ Collections.addAll(options, ++ CommandLineOptionTest.prepareNumericFlag( ++ BlobType.MethodJBoltHot.sizeOptionName, jboltHot), ++ CommandLineOptionTest.prepareNumericFlag( ++ BlobType.MethodJBoltTmp.sizeOptionName, jboltTmp)); ++ } ++ + return options.toArray(new String[options.size()]); + } + + public CodeCacheOptions mapOptions(EnumSet involvedCodeHeaps) { + if (involvedCodeHeaps.isEmpty() + || involvedCodeHeaps.equals(NON_SEGMENTED_HEAPS) +- || involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS)) { ++ || involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS_WITH_JBOLT)) { + return this; ++ } else if (involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS)) { ++ return new CodeCacheOptions(reserved, nonNmethods, ++ nonProfiled + jboltHot + jboltTmp, profiled); + } else if (involvedCodeHeaps.equals(SEGMENTED_HEAPS_WO_PROFILED)) { + return new CodeCacheOptions(reserved, nonNmethods, + profiled + nonProfiled, 0L); +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java +new file mode 100644 +index 000000000..b5bdb19bc +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java +@@ -0,0 +1,187 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++/* ++ * @test ++ * @summary Test JBolt dump mode functions. ++ * @library /test/lib ++ * @requires vm.flagless ++ * ++ * @run driver compiler.codecache.jbolt.JBoltDumpModeTest ++ */ ++ ++package compiler.codecache.jbolt; ++ ++import java.io.File; ++import java.io.IOException; ++import jdk.test.lib.process.OutputAnalyzer; ++import jdk.test.lib.process.ProcessTools; ++import jdk.test.lib.Utils; ++ ++public class JBoltDumpModeTest { ++ public static final String SRC_DIR = Utils.TEST_SRC; ++ public static final String ORDER_FILE = SRC_DIR + "/order.log"; ++ ++ private static void createOrderFile() { ++ try { ++ File order = new File(ORDER_FILE); ++ if (!order.exists()) { ++ order.createNewFile(); ++ } ++ } ++ catch (IOException e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ private static void clearOrderFile() { ++ File order = new File(ORDER_FILE); ++ if (order.exists()) { ++ order.delete(); ++ } ++ } ++ ++ private static void OrderFileShouldExist() throws Exception { ++ File order = new File(ORDER_FILE); ++ if (order.exists()) { ++ order.delete(); ++ } ++ else { ++ throw new RuntimeException(ORDER_FILE + " doesn't exist as expect."); ++ } ++ } ++ ++ private static void OrderFileShouldNotExist() throws Exception { ++ File order = new File(ORDER_FILE); ++ if (order.exists()) { ++ throw new RuntimeException(ORDER_FILE + " exists while expect not."); ++ } ++ } ++ ++ private static void testNormalUse() throws Exception { ++ ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:JBoltOrderFile=" + ORDER_FILE, ++ "-XX:+JBoltDumpMode", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:JBoltOrderFile=" + ORDER_FILE, ++ "-XX:+JBoltDumpMode", ++ "-XX:StartFlightRecording", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:JBoltOrderFile=" + ORDER_FILE, ++ "-XX:+JBoltDumpMode", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ clearOrderFile(); ++ ++ String stdout; ++ ++ OutputAnalyzer out1 = new OutputAnalyzer(pb1.start()); ++ stdout = out1.getStdout(); ++ if (!stdout.contains("JBolt in dump mode now, start a JFR recording named \"jbolt-jfr\".")) { ++ throw new RuntimeException(stdout); ++ } ++ out1.shouldHaveExitValue(0); ++ OrderFileShouldExist(); ++ ++ OutputAnalyzer out2 = new OutputAnalyzer(pb2.start()); ++ stdout = out2.getStdout(); ++ if (!stdout.contains("JBolt in dump mode now, start a JFR recording named \"jbolt-jfr\".")) { ++ throw new RuntimeException(stdout); ++ } ++ out2.shouldHaveExitValue(0); ++ OrderFileShouldExist(); ++ ++ createOrderFile(); ++ OutputAnalyzer out3 = new OutputAnalyzer(pb3.start()); ++ stdout = out3.getStdout(); ++ if (!stdout.contains("JBoltOrderFile to dump already exists and will be overwritten:")) { ++ throw new RuntimeException(stdout); ++ } ++ out3.shouldHaveExitValue(0); ++ OrderFileShouldExist(); ++ } ++ ++ private static void testUnabletoRun() throws Exception { ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:JBoltOrderFile=" + ORDER_FILE, ++ "-XX:+JBoltDumpMode", ++ "-XX:-FlightRecorder", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ clearOrderFile(); ++ ++ String stdout; ++ OutputAnalyzer out = new OutputAnalyzer(pb.start()); ++ ++ stdout = out.getStdout(); ++ if (!stdout.contains("JBolt depends on JFR!")) { ++ throw new RuntimeException(stdout); ++ } ++ OrderFileShouldNotExist(); ++ } ++ ++ private static void testFatalError() throws Exception { ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:JBoltOrderFile=" + ORDER_FILE, ++ "-XX:+JBoltDumpMode", ++ "-XX:foo", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ clearOrderFile(); ++ ++ OutputAnalyzer out = new OutputAnalyzer(pb.start()); ++ ++ out.stderrShouldContain("Could not create the Java Virtual Machine"); ++ OrderFileShouldNotExist(); ++ } ++ ++ public static void main(String[] args) throws Exception { ++ testNormalUse(); ++ testUnabletoRun(); ++ testFatalError(); ++ } ++} +\ No newline at end of file +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java +new file mode 100644 +index 000000000..4b45a585b +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java +@@ -0,0 +1,291 @@ ++/* ++ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++/* ++ * @test ++ * @summary Test JBolt VM options. ++ * @library /test/lib ++ * @requires vm.flagless ++ * ++ * @run driver compiler.codecache.jbolt.JBoltVMOptionsTest ++ */ ++ ++package compiler.codecache.jbolt; ++ ++import java.io.File; ++import jdk.test.lib.process.OutputAnalyzer; ++import jdk.test.lib.process.ProcessTools; ++import jdk.test.lib.Utils; ++ ++public class JBoltVMOptionsTest { ++ public static final String SRC_DIR = Utils.TEST_SRC; ++ public static final String TEMP_FILE = SRC_DIR + "/tmp.log"; ++ ++ public static void main(String[] args) throws Exception { ++ test1(); ++ test2(); ++ test3(); ++ test4(); ++ } ++ ++ private static void clearTmpFile() { ++ File tmp = new File(TEMP_FILE); ++ if (tmp.exists()) { ++ tmp.delete(); ++ } ++ } ++ ++ private static void test1() throws Exception { ++ ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltDumpMode", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:+JBoltDumpMode", ++ "-XX:JBoltOrderFile=" + SRC_DIR + "/o1.log", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb4 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:JBoltOrderFile=" + TEMP_FILE, ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ OutputAnalyzer out1 = new OutputAnalyzer(pb1.start()); ++ OutputAnalyzer out2 = new OutputAnalyzer(pb2.start()); ++ OutputAnalyzer out3 = new OutputAnalyzer(pb3.start()); ++ OutputAnalyzer out4 = new OutputAnalyzer(pb4.start()); ++ ++ String stdout; ++ ++ stdout = out1.getStdout(); ++ if (!stdout.contains("JBoltOrderFile is not set!")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = out2.getStdout(); ++ if (!stdout.contains("JBoltOrderFile is not set!")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = out3.getStdout(); ++ if (!stdout.contains("Do not set both JBoltDumpMode and JBoltLoadMode!")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = out4.getStdout(); ++ if (!stdout.contains("JBoltOrderFile is ignored because it is in auto mode.")) { ++ throw new RuntimeException(stdout); ++ } ++ } ++ ++ private static void test2() throws Exception { ++ ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+PrintFlagsFinal", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltDumpMode", ++ "-XX:JBoltOrderFile=" + TEMP_FILE, ++ "-XX:+PrintFlagsFinal", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:JBoltOrderFile=" + SRC_DIR + "/o1.log", ++ "-XX:+PrintFlagsFinal", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ OutputAnalyzer out1 = new OutputAnalyzer(pb1.start()); ++ OutputAnalyzer out2 = new OutputAnalyzer(pb2.start()); ++ OutputAnalyzer out3 = new OutputAnalyzer(pb3.start()); ++ ++ String stdout; ++ ++ stdout = out1.getStdout().replaceAll(" +", ""); ++ if (!stdout.contains("JBoltDumpMode=false") || !stdout.contains("JBoltLoadMode=false")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = out2.getStdout().replaceAll(" +", ""); ++ if (!stdout.contains("JBoltDumpMode=true") || !stdout.contains("JBoltLoadMode=false")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ clearTmpFile(); ++ ++ stdout = out3.getStdout().replaceAll(" +", ""); ++ if (!stdout.contains("JBoltDumpMode=false") || !stdout.contains("JBoltLoadMode=true")) { ++ throw new RuntimeException(stdout); ++ } ++ } ++ ++ private static void test3() throws Exception { ++ ProcessBuilder pbF0 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:JBoltOrderFile=" + TEMP_FILE, ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pbF1 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:JBoltOrderFile=" + SRC_DIR + "/o1.log", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pbF2 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:JBoltOrderFile=" + SRC_DIR + "/o2.log", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pbF3 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:JBoltOrderFile=" + SRC_DIR + "/o3.log", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pbF4 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+UseJBolt", ++ "-XX:+JBoltLoadMode", ++ "-XX:JBoltOrderFile=" + SRC_DIR + "/o4.log", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ OutputAnalyzer outF0 = new OutputAnalyzer(pbF0.start()); ++ OutputAnalyzer outF1 = new OutputAnalyzer(pbF1.start()); ++ OutputAnalyzer outF2 = new OutputAnalyzer(pbF2.start()); ++ OutputAnalyzer outF3 = new OutputAnalyzer(pbF3.start()); ++ OutputAnalyzer outF4 = new OutputAnalyzer(pbF4.start()); ++ ++ String stdout; ++ ++ stdout = outF0.getStdout(); ++ if (!stdout.contains("JBoltOrderFile does not exist or cannot be accessed!")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = outF1.getStdout(); ++ if (!stdout.contains("Wrong format of JBolt order line! line=\"X 123 aa bb cc\".")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = outF2.getStdout(); ++ if (!stdout.contains("Wrong format of JBolt order line! line=\"M aa/bb/C dd ()V\".")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = outF3.getStdout(); ++ if (!stdout.contains("Duplicated method: {aa/bb/CC dd ()V}!")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = outF4.getStdout(); ++ if (stdout.contains("Error occurred during initialization of VM")) { ++ throw new RuntimeException(stdout); ++ } ++ outF4.shouldHaveExitValue(0); ++ ++ clearTmpFile(); ++ } ++ ++ private static void test4() throws Exception { ++ ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+JBoltDumpMode", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:+JBoltLoadMode", ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockExperimentalVMOptions", ++ "-XX:JBoltOrderFile=" + TEMP_FILE, ++ "-Xlog:jbolt*=trace", ++ "--version" ++ ); ++ ++ OutputAnalyzer out1 = new OutputAnalyzer(pb1.start()); ++ OutputAnalyzer out2 = new OutputAnalyzer(pb2.start()); ++ OutputAnalyzer out3 = new OutputAnalyzer(pb3.start()); ++ ++ String stdout; ++ ++ stdout = out1.getStdout(); ++ if (!stdout.contains("Do not set VM option JBoltDumpMode without UseJBolt enabled.")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = out2.getStdout(); ++ if (!stdout.contains("Do not set VM option JBoltLoadMode without UseJBolt enabled.")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ stdout = out3.getStdout(); ++ if (!stdout.contains("Do not set VM option JBoltOrderFile without UseJBolt enabled.")) { ++ throw new RuntimeException(stdout); ++ } ++ ++ clearTmpFile(); ++ } ++} +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/o1.log b/test/hotspot/jtreg/compiler/codecache/jbolt/o1.log +new file mode 100644 +index 000000000..f0ef01586 +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/o1.log +@@ -0,0 +1,2 @@ ++M 123 aa/bb/C dd ()V ++X 123 aa bb cc +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/o2.log b/test/hotspot/jtreg/compiler/codecache/jbolt/o2.log +new file mode 100644 +index 000000000..ef348a6ab +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/o2.log +@@ -0,0 +1,2 @@ ++M aa/bb/C dd ()V ++M 123 aa/bb/CC dd ()V +\ No newline at end of file +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/o3.log b/test/hotspot/jtreg/compiler/codecache/jbolt/o3.log +new file mode 100644 +index 000000000..fe6906b47 +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/o3.log +@@ -0,0 +1,4 @@ ++# this is a comment ++C ++M 123 aa/bb/CC dd ()V ++M 123 aa/bb/CC dd ()V +\ No newline at end of file +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/o4.log b/test/hotspot/jtreg/compiler/codecache/jbolt/o4.log +new file mode 100644 +index 000000000..13e96dbab +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/o4.log +@@ -0,0 +1,12 @@ ++M 123 aa/bb/CC dd ()V ++# asdfadsfadfs ++C ++M 456 aa/bb/CC ddd ()V ++M 456 aa/bb/CCC dd ()V ++ ++C ++ ++ ++ ++ ++M 456 aa/bb/CCCCCC ddddddd ()V +diff --git a/test/hotspot/jtreg/runtime/cds/appcds/ClassLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/ClassLoaderTest.java +index 4fba6584f..6f4cc5a83 100644 +--- a/test/hotspot/jtreg/runtime/cds/appcds/ClassLoaderTest.java ++++ b/test/hotspot/jtreg/runtime/cds/appcds/ClassLoaderTest.java +@@ -57,7 +57,7 @@ public class ClassLoaderTest { + String bootClassPath = "-Xbootclasspath/a:" + appJar + + File.pathSeparator + whiteBoxJar; + +- TestCommon.dump(appJar, appClasses, bootClassPath); ++ TestCommon.dump(appJar, appClasses, bootClassPath).shouldHaveExitValue(0); + + TestCommon.run( + "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", +diff --git a/test/lib/jdk/test/whitebox/code/BlobType.java b/test/lib/jdk/test/whitebox/code/BlobType.java +index 24ce9d96a..59039bbbe 100644 +--- a/test/lib/jdk/test/whitebox/code/BlobType.java ++++ b/test/lib/jdk/test/whitebox/code/BlobType.java +@@ -46,8 +46,24 @@ public enum BlobType { + || type == BlobType.MethodNonProfiled; + } + }, ++ // Execution hot non-profiled nmethods ++ MethodJBoltHot(2, "CodeHeap 'jbolt hot nmethods'", "JBoltCodeHeapSize") { ++ @Override ++ public boolean allowTypeWhenOverflow(BlobType type) { ++ return super.allowTypeWhenOverflow(type) ++ || type == BlobType.MethodNonProfiled; ++ } ++ }, ++ // Execution tmp non-profiled nmethods ++ MethodJBoltTmp(3, "CodeHeap 'jbolt tmp nmethods'", "JBoltCodeHeapSize") { ++ @Override ++ public boolean allowTypeWhenOverflow(BlobType type) { ++ return super.allowTypeWhenOverflow(type) ++ || type == BlobType.MethodNonProfiled; ++ } ++ }, + // Non-nmethods like Buffers, Adapters and Runtime Stubs +- NonNMethod(2, "CodeHeap 'non-nmethods'", "NonNMethodCodeHeapSize") { ++ NonNMethod(4, "CodeHeap 'non-nmethods'", "NonNMethodCodeHeapSize") { + @Override + public boolean allowTypeWhenOverflow(BlobType type) { + return super.allowTypeWhenOverflow(type) +@@ -56,7 +72,7 @@ public enum BlobType { + } + }, + // All types (No code cache segmentation) +- All(3, "CodeCache", "ReservedCodeCacheSize"); ++ All(5, "CodeCache", "ReservedCodeCacheSize"); + + public final int id; + public final String sizeOptionName; +@@ -99,6 +115,10 @@ public enum BlobType { + // there is no MethodProfiled in non tiered world or pure C1 + result.remove(MethodProfiled); + } ++ if (!whiteBox.getBooleanVMFlag("UseJBolt") || whiteBox.getBooleanVMFlag("JBoltDumpMode")) { ++ result.remove(MethodJBoltHot); ++ result.remove(MethodJBoltTmp); ++ } + return result; + } + +-- +2.47.0.windows.2 + diff --git a/huawei-Adapt-to-clang-build-toolchain.patch b/huawei-Adapt-to-clang-build-toolchain.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e8bbd0f13e464cec24dd1c833d03d21c0b86e23 --- /dev/null +++ b/huawei-Adapt-to-clang-build-toolchain.patch @@ -0,0 +1,616 @@ +Date: Fri, 21 Mar 2025 15:22:01 +0800 +Subject: Adapt to clang build toolchain + +--- + make/autoconf/flags-cflags.m4 | 9 ++++++ + make/autoconf/flags-ldflags.m4 | 8 +++-- + make/autoconf/flags-other.m4 | 2 +- + make/autoconf/lib-std.m4 | 6 +++- + make/autoconf/toolchain.m4 | 6 +++- + make/common/NativeCompilation.gmk | 13 ++++++-- + src/hotspot/cpu/arm/icache_arm.cpp | 2 +- + src/hotspot/cpu/riscv/vm_version_riscv.cpp | 2 -- + src/hotspot/cpu/s390/vm_version_s390.cpp | 8 +++++ + src/hotspot/cpu/x86/vm_version_x86.cpp | 9 +++--- + src/hotspot/os/linux/os_linux.cpp | 1 - + src/hotspot/os/linux/os_linux.hpp | 2 +- + src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp | 13 ++++++-- + src/hotspot/share/code/codeBlob.hpp | 3 +- + src/hotspot/share/jbolt/jBoltManager.cpp | 4 +-- + src/hotspot/share/prims/unsafe.cpp | 3 +- + src/hotspot/share/services/heapDumper.cpp | 6 ++-- + .../hotspot/utilities/HeapHprofBinWriter.java | 6 ++-- + .../share/classes/sun/tools/jmap/JMap.java | 2 +- + .../unix/native/libsctp/SctpChannelImpl.c | 2 +- + .../codecache/jbolt/JBoltDumpModeTest.java | 10 +++---- + .../codecache/jbolt/JBoltVMOptionsTest.java | 30 +++++++++---------- + 22 files changed, 93 insertions(+), 54 deletions(-) + +diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 +index ffbf61ea5..891455dee 100644 +--- a/make/autoconf/flags-cflags.m4 ++++ b/make/autoconf/flags-cflags.m4 +@@ -599,6 +599,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], + # Restrict the debug information created by Clang to avoid + # too big object files and speed the build up a little bit + # (see http://llvm.org/bugs/show_bug.cgi?id=7554) ++ TOOLCHAIN_CFLAGS_JVM_ARM="$TOOLCHAIN_CFLAGS_JVM" + TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -flimit-debug-info" + + # In principle the stack alignment below is cpu- and ABI-dependent and +@@ -618,6 +619,10 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], + TOOLCHAIN_CFLAGS_JDK_CONLY="-fno-strict-aliasing" # technically NOT for CXX + fi + ++ if test "x$OPENJDK_TARGET_CPU" = xarm; then ++ TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM_ARM -mno-omit-leaf-frame-pointer" ++ fi ++ + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + # Suggested additions: -qsrcmsg to get improved error reporting + # set -qtbtable=full for a better traceback table/better stacks in hs_err when xlc16 is used +@@ -834,6 +839,10 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], + if test "x$FLAGS_CPU_ARCH" != xarm && test "x$FLAGS_CPU_ARCH" != xppc; then + # for all archs except arm and ppc, prevent gcc to omit frame pointer + $1_CFLAGS_CPU_JDK="${$1_CFLAGS_CPU_JDK} -fno-omit-frame-pointer" ++ elif test "x$FLAGS_CPU_ARCH" = xarm; then ++ # -Wno-psabi to get rid of annoying "note: the mangling of 'va_list' has changed in GCC 4.4" ++ $1_CFLAGS_CPU="-fsigned-char -Wno-psabi $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS -DJDK_ARCH_ABI_PROP_NAME='\"\$(JDK_ARCH_ABI_PROP_NAME)\"'" ++ $1_CFLAGS_CPU_JVM="-DARM" + fi + if test "x$FLAGS_CPU" = xppc64le; then + # Little endian machine uses ELFv2 ABI. +diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 +index e5c345fde..397aee925 100644 +--- a/make/autoconf/flags-ldflags.m4 ++++ b/make/autoconf/flags-ldflags.m4 +@@ -73,8 +73,12 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], + BASIC_LDFLAGS_JVM_ONLY="" + + elif test "x$TOOLCHAIN_TYPE" = xclang; then +- BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \ ++ if test "x$OPENJDK_TARGET_CPU" = xarm; then ++ BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -fPIC" ++ else ++ BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \ + -fPIC" ++ fi + if test "x$OPENJDK_TARGET_OS" = xaix; then + BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-bnolibpath -Wl,-bnoexpall \ + -Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k" +@@ -171,7 +175,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], + [ + # Setup CPU-dependent basic LDFLAGS. These can differ between the target and + # build toolchain. +- if test "x$TOOLCHAIN_TYPE" = xgcc; then ++ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then + if test "x${OPENJDK_$1_CPU}" = xx86; then + $1_CPU_LDFLAGS_JVM_ONLY="-march=i586" + elif test "x$OPENJDK_$1_CPU" = xarm; then +diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4 +index 0af7c02cf..044dfb4a0 100644 +--- a/make/autoconf/flags-other.m4 ++++ b/make/autoconf/flags-other.m4 +@@ -136,7 +136,7 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS_CPU_DEP], + $2JVM_ASFLAGS="$JVM_BASIC_ASFLAGS ${$2EXTRA_CFLAGS}" + + if test "x$1" = "xTARGET" && \ +- test "x$TOOLCHAIN_TYPE" = xgcc && \ ++ (test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang) && \ + test "x$OPENJDK_TARGET_CPU" = xarm; then + $2JVM_ASFLAGS="${$2JVM_ASFLAGS} $ARM_ARCH_TYPE_ASFLAGS $ARM_FLOAT_TYPE_ASFLAGS" + fi +diff --git a/make/autoconf/lib-std.m4 b/make/autoconf/lib-std.m4 +index e470cdbe6..c7fb81386 100644 +--- a/make/autoconf/lib-std.m4 ++++ b/make/autoconf/lib-std.m4 +@@ -47,7 +47,11 @@ AC_DEFUN_ONCE([LIB_SETUP_STD_LIBS], + if test "x$OPENJDK_TARGET_OS" = xlinux; then + # Test if stdc++ can be linked statically. + AC_MSG_CHECKING([if static link of stdc++ is possible]) +- STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc" ++ if test "x$TOOLCHAIN_TYPE" = xclang && test "x$FLAGS_CPU_ARCH" = xarm; then ++ STATIC_STDCXX_FLAGS="" ++ else ++ STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc" ++ fi + AC_LANG_PUSH(C++) + OLD_LIBS="$LIBS" + LIBS="$STATIC_STDCXX_FLAGS" +diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 +index 069ced05f..b7ae22c00 100644 +--- a/make/autoconf/toolchain.m4 ++++ b/make/autoconf/toolchain.m4 +@@ -483,7 +483,11 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION], + if test $? -ne 0; then + AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler.]) + AC_MSG_NOTICE([The result from running with --version was: "$COMPILER_VERSION_OUTPUT"]) +- AC_MSG_ERROR([A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir.]) ++ if test "x$OPENJDK_TARGET_CPU" = xarm; then ++ AC_MSG_NOTICE([A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir.]) ++ else ++ AC_MSG_ERROR([A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir.]) ++ fi + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` +diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk +index 3b96222e4..fbf2f62e0 100644 +--- a/make/common/NativeCompilation.gmk ++++ b/make/common/NativeCompilation.gmk +@@ -795,6 +795,10 @@ define SetupNativeCompilationBody + ifeq ($$($1_COMPILE_WITH_DEBUG_SYMBOLS), true) + $1_EXTRA_CFLAGS += $$(CFLAGS_DEBUG_SYMBOLS) + $1_EXTRA_CXXFLAGS += $$(CFLAGS_DEBUG_SYMBOLS) ++ ifeq ($(findstring $(OPENJDK_TARGET_CPU), arm), ) ++ $1_EXTRA_CFLAGS := $(filter-out -gdwarf-aranges,$(1_EXTRA_CFLAGS)) ++ $1_EXTRA_CXXFLAGS := $(filter-out -gdwarf-aranges,$(1_EXTRA_CXXFLAGS)) ++ endif + $1_EXTRA_ASFLAGS += $$(ASFLAGS_DEBUG_SYMBOLS) + endif + +@@ -900,8 +904,13 @@ define SetupNativeCompilationBody + $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).gch + $1_USE_PCH_FLAGS := -I$$($1_OBJECT_DIR)/precompiled + else ifeq ($(TOOLCHAIN_TYPE), clang) +- $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).pch +- $1_USE_PCH_FLAGS := -include-pch $$($1_PCH_FILE) ++ ifeq ($(findstring $(OPENJDK_TARGET_CPU), arm), ) ++ $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).gch ++ $1_USE_PCH_FLAGS := -I$$($1_OBJECT_DIR)/precompiled ++ else ++ $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).pch ++ $1_USE_PCH_FLAGS := -include-pch $$($1_PCH_FILE) ++ endif + endif + $1_PCH_DEPS_FILE := $$($1_PCH_FILE).d + $1_PCH_DEPS_TARGETS_FILE := $$($1_PCH_FILE).d.targets +diff --git a/src/hotspot/cpu/arm/icache_arm.cpp b/src/hotspot/cpu/arm/icache_arm.cpp +index 61fcb8a35..9054b536c 100644 +--- a/src/hotspot/cpu/arm/icache_arm.cpp ++++ b/src/hotspot/cpu/arm/icache_arm.cpp +@@ -31,7 +31,7 @@ + + + static int icache_flush(address addr, int lines, int magic) { +- __builtin___clear_cache(addr, addr + (lines << ICache::log2_line_size)); ++ __builtin___clear_cache((char *)addr, (char *)addr + (lines << ICache::log2_line_size)); + return magic; + } + +diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +index a740b0301..10fde8688 100644 +--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp ++++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +@@ -232,12 +232,10 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); + warning("HashMap optimization is not supported in this VM."); + } +- + if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { + FLAG_SET_DEFAULT(UseFastSerializer, false); + warning("Serializer optimization is not supported in this VM."); + } +- + #ifdef COMPILER2 + c2_initialize(); + #endif // COMPILER2 +diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp +index 44a0275e4..12fcb3773 100644 +--- a/src/hotspot/cpu/s390/vm_version_s390.cpp ++++ b/src/hotspot/cpu/s390/vm_version_s390.cpp +@@ -272,6 +272,14 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UseSHA, false); + } + ++ if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { ++ FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); ++ warning("HashMap optimization is not supported in this VM."); ++ } ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } + #ifdef COMPILER2 + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); +diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp +index 6f35090cc..b312635b4 100644 +--- a/src/hotspot/cpu/x86/vm_version_x86.cpp ++++ b/src/hotspot/cpu/x86/vm_version_x86.cpp +@@ -1200,15 +1200,14 @@ void VM_Version::get_processor_features() { + } + + #ifdef _LP64 +- if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { +- FLAG_SET_DEFAULT(UseFastSerializer, false); +- warning("Serializer optimization is not supported in this VM."); +- } + if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { + FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); + warning("HashMap optimization is not supported in this VM."); + } +- ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } + #endif + + #ifdef _LP64 +diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp +index 43ee4b7db..990e38b07 100644 +--- a/src/hotspot/os/linux/os_linux.cpp ++++ b/src/hotspot/os/linux/os_linux.cpp +@@ -135,7 +135,6 @@ + __asm__(".symver fcntl64,fcntl@GLIBC_2.2.5"); + #endif + +- + // if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling + // getrusage() is prepared to handle the associated failure. + #ifndef RUSAGE_THREAD +diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp +index 871581f58..d25c2dda0 100644 +--- a/src/hotspot/os/linux/os_linux.hpp ++++ b/src/hotspot/os/linux/os_linux.hpp +@@ -486,7 +486,7 @@ class os::Linux { + return NULL; + } + return _heap_dict_lookup(key, heap_dict, deletable); +- }; ++ } + + static void heap_dict_free(void* heap_dict, bool is_nested) { + if(_heap_dict_free != NULL) { +diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +index 86e8ed256..375925105 100644 +--- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp ++++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +@@ -90,8 +90,14 @@ enum { + #endif + + address os::current_stack_pointer() { +- register address sp __asm__ (SPELL_REG_SP); +- return sp; ++ #if defined(__clang__) || defined(__llvm__) ++ void *sp; ++ __asm__("mov %0, " SPELL_REG_SP : "=r"(sp)); ++ return (address) sp; ++ #else ++ register address sp __asm__ (SPELL_REG_SP); ++ return sp; ++ #endif + } + + char* os::non_memory_address_word() { +@@ -99,7 +105,7 @@ char* os::non_memory_address_word() { + return (char*) -1; + } + +- ++#ifndef __arm__ + #if NGREG == 16 + // These definitions are based on the observation that until + // the certain version of GCC mcontext_t was defined as +@@ -111,6 +117,7 @@ char* os::non_memory_address_word() { + #define arm_fp gregs[11] + #define arm_r0 gregs[0] + #endif ++#endif + + #define ARM_REGS_IN_CONTEXT 16 + +diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp +index 8392499d3..03e7df9c8 100644 +--- a/src/hotspot/share/code/codeBlob.hpp ++++ b/src/hotspot/share/code/codeBlob.hpp +@@ -48,8 +48,7 @@ enum class CodeBlobType { + MethodJBoltTmp = 3, // Temporary storage of JBolt hot methods + NonNMethod = 4, // Non-nmethods like Buffers, Adapters and Runtime Stubs + All = 5, // All types (No code cache segmentation) +- AOT = 6, // AOT methods +- NumTypes = 7 // Number of CodeBlobTypes ++ NumTypes = 6 // Number of CodeBlobTypes + }; + + // CodeBlob - superclass for all entries in the CodeCache. +diff --git a/src/hotspot/share/jbolt/jBoltManager.cpp b/src/hotspot/share/jbolt/jBoltManager.cpp +index 4cb6f4d1a..76be3f6ed 100644 +--- a/src/hotspot/share/jbolt/jBoltManager.cpp ++++ b/src/hotspot/share/jbolt/jBoltManager.cpp +@@ -947,7 +947,7 @@ bool JBoltManager::reorder_phase_collecting_to_reordering() { + } + + bool JBoltManager::reorder_phase_available_to_profiling() { +- assert(auto_mode(), "one-phase only"); ++ assert(JBoltDumpMode || auto_mode(), "for two-phase dump mode & one-phase"); + return Atomic::cmpxchg(&_reorder_phase, JBoltReorderPhase::Available, JBoltReorderPhase::Profiling) == JBoltReorderPhase::Available; + } + +@@ -1002,7 +1002,7 @@ bool JBoltManager::reorder_phase_is_collecting() { + + bool JBoltManager::reorder_phase_is_profiling() { + bool res = (Atomic::load_acquire(&_reorder_phase) == JBoltReorderPhase::Profiling); +- assert(!res || auto_mode(), "for two-phase dump mode & one-phase"); ++ assert(!res || (JBoltDumpMode || auto_mode()), "for two-phase dump mode & one-phase"); + return res; + } + +diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp +index 2fd9ed1d0..4eb1c96a6 100644 +--- a/src/hotspot/share/prims/unsafe.cpp ++++ b/src/hotspot/share/prims/unsafe.cpp +@@ -910,11 +910,10 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { + {CC "writebackPostSync0", CC "()V", FN_PTR(Unsafe_WriteBackPostSync0)}, + {CC "setMemory0", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory0)}, + +- {CC "getUseHashMapIntegerCache", CC "()Z", FN_PTR(Unsafe_GetUseHashMapIntegerCache)} +- , + {CC "shouldBeInitialized0", CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized0)}, + + {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, ++ {CC "getUseHashMapIntegerCache", CC "()Z", FN_PTR(Unsafe_GetUseHashMapIntegerCache)}, + {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)}, + }; + +diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp +index 82e721c17..e44ba085b 100644 +--- a/src/hotspot/share/services/heapDumper.cpp ++++ b/src/hotspot/share/services/heapDumper.cpp +@@ -1053,7 +1053,7 @@ public: + int field_count() { return _entries; } + char sig_start(int field_idx) { return _sigs_start.at(field_idx); } + int offset(int field_idx) { return _offsets.at(field_idx); } +- address name_symbol_addrs(int field_idx) { return _name_symbol_addrs.at(field_idx); } ++ address name_symbol_addr(int field_idx) { return _name_symbol_addrs.at(field_idx); } + u4 instance_size() { return _instance_size; } + }; + +@@ -1391,7 +1391,7 @@ void DumperSupport::dump_instance_redact_fields(AbstractDumpWriter* writer, oop + int offset = class_cache_entry->offset(idx); + + ResourceMark rm; +- address field_adr = class_cache_entry->name_symbol_addrs(idx); ++ address field_adr = class_cache_entry->name_symbol_addr(idx); + void* replace_value = writer->heapRedactor()->lookup_value(field_adr, replace_value_table, false); + + if (replace_value != nullptr) { +@@ -1560,7 +1560,7 @@ void DumperSupport::dump_redact_instance(AbstractDumpWriter* writer, oop o, Dump + + DumperClassCacheTableEntry* cache_entry = class_cache->lookup_or_create(ik); + +- u4 is = instance_size(ik); ++ u4 is = instance_size(ik, cache_entry); + u4 size = 1 + sizeof(address) + 4 + sizeof(address) + 4 + is; + + writer->start_sub_record(HPROF_GC_INSTANCE_DUMP, size); +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +index 8501f4d93..b8f3e182b 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +@@ -1591,11 +1591,11 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL); + byte[] buf = null; + if(shouldRedact) { +- Optional redactField = lookupRedactName(symbolStr); +- buf = redactField.isPresent() ? redactField.get().getBytes("UTF-8") : null; ++ Optional redactFiled = lookupRedactName(symbolStr); ++ buf = redactFiled.isPresent() ? redactFiled.get().getBytes("UTF-8") : null; + } + if(buf == null) { +- buf = symbolStr.getBytes(UTF_8); ++ buf = symbolStr.getBytes("UTF-8"); + } + writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE); + writeSymbolID(sym); +diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +index 50757d2d7..a48d27bab 100644 +--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java ++++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +@@ -343,7 +343,7 @@ public class JMap { + String flag = "RedactPassword"; + try (InputStream in = hvm.printFlag(flag); BufferedInputStream bis = new BufferedInputStream(in); + InputStreamReader isr = new InputStreamReader(bis, "UTF-8")) { +- char c[] = new char[256]; ++ char[] c = new char[256]; + int n; + do { + n = isr.read(c); +diff --git a/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c b/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c +index 83f3519fb..3720caccd 100644 +--- a/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c ++++ b/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c +@@ -389,7 +389,7 @@ void handleMessage + (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read, + jboolean isEOR, struct sockaddr* sap) { + jobject isa, resultObj; +- struct controlData cdata[1]; ++ struct controlData cdata[1] = {0}; + + if (read == 0) { + /* we reached EOF */ +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java +index b5bdb19bc..76a426838 100644 +--- a/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltDumpModeTest.java +@@ -79,7 +79,7 @@ public class JBoltDumpModeTest { + } + + private static void testNormalUse() throws Exception { +- ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb1 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:JBoltOrderFile=" + ORDER_FILE, +@@ -88,7 +88,7 @@ public class JBoltDumpModeTest { + "--version" + ); + +- ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb2 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:JBoltOrderFile=" + ORDER_FILE, +@@ -98,7 +98,7 @@ public class JBoltDumpModeTest { + "--version" + ); + +- ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb3 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:JBoltOrderFile=" + ORDER_FILE, +@@ -138,7 +138,7 @@ public class JBoltDumpModeTest { + } + + private static void testUnabletoRun() throws Exception { +- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:JBoltOrderFile=" + ORDER_FILE, +@@ -161,7 +161,7 @@ public class JBoltDumpModeTest { + } + + private static void testFatalError() throws Exception { +- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:JBoltOrderFile=" + ORDER_FILE, +diff --git a/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java +index 4b45a585b..c17e2c13e 100644 +--- a/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java ++++ b/test/hotspot/jtreg/compiler/codecache/jbolt/JBoltVMOptionsTest.java +@@ -56,21 +56,21 @@ public class JBoltVMOptionsTest { + } + + private static void test1() throws Exception { +- ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb1 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltDumpMode", + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb2 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb3 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -79,7 +79,7 @@ public class JBoltVMOptionsTest { + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb4 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb4 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:JBoltOrderFile=" + TEMP_FILE, +@@ -116,14 +116,14 @@ public class JBoltVMOptionsTest { + } + + private static void test2() throws Exception { +- ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb1 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+PrintFlagsFinal", + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb2 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltDumpMode", +@@ -132,7 +132,7 @@ public class JBoltVMOptionsTest { + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb3 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -167,7 +167,7 @@ public class JBoltVMOptionsTest { + } + + private static void test3() throws Exception { +- ProcessBuilder pbF0 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pbF0 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -175,7 +175,7 @@ public class JBoltVMOptionsTest { + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pbF1 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pbF1 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -183,7 +183,7 @@ public class JBoltVMOptionsTest { + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pbF2 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pbF2 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -191,7 +191,7 @@ public class JBoltVMOptionsTest { + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pbF3 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pbF3 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -199,7 +199,7 @@ public class JBoltVMOptionsTest { + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pbF4 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pbF4 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseJBolt", + "-XX:+JBoltLoadMode", +@@ -246,19 +246,19 @@ public class JBoltVMOptionsTest { + } + + private static void test4() throws Exception { +- ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb1 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+JBoltDumpMode", + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb2 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+JBoltLoadMode", + "-Xlog:jbolt*=trace", + "--version" + ); +- ProcessBuilder pb3 = ProcessTools.createJavaProcessBuilder( ++ ProcessBuilder pb3 = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:JBoltOrderFile=" + TEMP_FILE, + "-Xlog:jbolt*=trace", +-- +2.47.0.windows.2 + diff --git a/huawei-Add-Fast-Serialzer.patch b/huawei-Add-Fast-Serialzer.patch new file mode 100644 index 0000000000000000000000000000000000000000..663849432fe5b50e9d838fceabb6e9f77e7f43ae --- /dev/null +++ b/huawei-Add-Fast-Serialzer.patch @@ -0,0 +1,680 @@ +Date: Thu, 13 Mar 2025 14:14:43 +0800 +Subject: Add Fast Serialzer + +--- + src/hotspot/cpu/x86/vm_version_x86.cpp | 7 + + src/hotspot/share/prims/unsafe.cpp | 5 + + src/hotspot/share/runtime/globals.hpp | 4 + + .../classes/java/io/ObjectInputStream.java | 222 +++++++++++++++--- + .../classes/java/io/ObjectOutputStream.java | 83 ++++++- + .../classes/java/io/ObjectStreamClass.java | 81 +++++++ + .../classes/jdk/internal/misc/Unsafe.java | 2 +- + 7 files changed, 362 insertions(+), 42 deletions(-) + +diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp +index b7f5a2bc9..d71d3a93f 100644 +--- a/src/hotspot/cpu/x86/vm_version_x86.cpp ++++ b/src/hotspot/cpu/x86/vm_version_x86.cpp +@@ -1199,6 +1199,13 @@ void VM_Version::get_processor_features() { + FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); + } + ++#ifdef _LP64 ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } ++#endif ++ + #ifdef _LP64 + // These are only supported on 64-bit + if (UseSHA && supports_avx2() && supports_bmi2()) { +diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp +index 3de8962c0..921693473 100644 +--- a/src/hotspot/share/prims/unsafe.cpp ++++ b/src/hotspot/share/prims/unsafe.cpp +@@ -825,6 +825,10 @@ UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleAr + return ret; + } UNSAFE_END + ++UNSAFE_ENTRY(jboolean, Unsafe_GetUseFastSerializer(JNIEnv *env, jobject unsafe)) { ++ return UseFastSerializer; ++} ++UNSAFE_END + + /// JVM_RegisterUnsafeMethods + +@@ -904,6 +908,7 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { + {CC "shouldBeInitialized0", CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized0)}, + + {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, ++ {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)}, + }; + + #undef CC +diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp +index b422d730a..ac33876d8 100644 +--- a/src/hotspot/share/runtime/globals.hpp ++++ b/src/hotspot/share/runtime/globals.hpp +@@ -1959,6 +1959,10 @@ const int ObjectAlignmentInBytes = 8; + JFR_ONLY(product(ccstr, StartFlightRecording, nullptr, \ + "Start flight recording with options")) \ + \ ++ product(bool, UseFastSerializer, false, EXPERIMENTAL, \ ++ "Cache-based serialization.It is extremely fast, but it" \ ++ "can only be effective in certain scenarios.") \ ++ \ + product(bool, UseFastUnorderedTimeStamps, false, EXPERIMENTAL, \ + "Use platform unstable time where supported for timestamps only") \ + \ +diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java +index 10b7f7715..80b316004 100644 +--- a/src/java.base/share/classes/java/io/ObjectInputStream.java ++++ b/src/java.base/share/classes/java/io/ObjectInputStream.java +@@ -41,6 +41,7 @@ import java.security.PrivilegedExceptionAction; + import java.util.Arrays; + import java.util.Map; + import java.util.Objects; ++import java.util.concurrent.ConcurrentHashMap; + + import jdk.internal.access.SharedSecrets; + import jdk.internal.event.DeserializationEvent; +@@ -329,6 +330,23 @@ public class ObjectInputStream + filterLogger = (filterLog.isLoggable(Logger.Level.DEBUG) + || filterLog.isLoggable(Logger.Level.TRACE)) ? filterLog : null; + } ++ ++ /* ++ * Logger for FastSerializer. ++ * Setup the FastSerializer logger if it is set to DEBUG. ++ * (Assuming it will not change). ++ */ ++ static final System.Logger fastSerLogger; ++ ++ static { ++ if (printFastSerializer) { ++ Logger fastSerLog = System.getLogger("fastSerializer"); ++ fastSerLogger = (fastSerLog.isLoggable(Logger.Level.DEBUG)) ++ ? fastSerLog : null; ++ } else { ++ fastSerLogger = null; ++ } ++ } + } + + /** filter stream for handling block data conversion */ +@@ -354,6 +372,9 @@ public class ObjectInputStream + /** if true, invoke resolveObject() */ + private boolean enableResolve; + ++ /** Used to get the commandline option: useFastSerializer */ ++ private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ + /** + * Context during upcalls to class-defined readObject methods; holds + * object currently being deserialized and descriptor for current class. +@@ -367,6 +388,40 @@ public class ObjectInputStream + */ + private ObjectInputFilter serialFilter; + ++ /** ++ * value of "useFastSerializer" property ++ */ ++ private static final boolean defaultFastSerializer = UNSAFE.getUseFastSerializer(); ++ ++ /** ++ * true or false for open FastSerilizer ++ * May be changed in readStreamHeader ++ */ ++ private boolean useFastSerializer = defaultFastSerializer; ++ ++ /** ++ * Value of "fastSerializerEscapeMode" property. It can be turned on ++ * when useFastSerializer is true. ++ */ ++ @SuppressWarnings("removal") ++ private static final boolean fastSerializerEscapeMode = java.security.AccessController.doPrivileged( ++ new sun.security.action.GetBooleanAction( ++ "fastSerializerEscapeMode")).booleanValue(); ++ ++ /** ++ * Magic number that is written to the stream header when using fastserilizer. ++ */ ++ private static final short STREAM_MAGIC_FAST = (short)0xdeca; ++ ++ /** ++ * value of "printFastSerializer" property, ++ * as true or false for printing FastSerializer logs. ++ */ ++ @SuppressWarnings("removal") ++ private static final boolean printFastSerializer = java.security.AccessController.doPrivileged( ++ new sun.security.action.GetBooleanAction( ++ "printFastSerializer")).booleanValue(); ++ + /** + * True if the stream-specific filter has been set; initially false. + */ +@@ -468,6 +523,9 @@ public class ObjectInputStream + * transitively so that a complete equivalent graph of objects is + * reconstructed by readObject. + * ++ * The difference between fastSerialzation and default serialization is the ++ * descriptor serialization. The data serialization is same with each other. ++ * + *

    The root object is completely restored when all of its fields and the + * objects it references are completely restored. At this point the object + * validation callbacks are executed in order based on their registered +@@ -757,11 +815,20 @@ public class ObjectInputStream + vlist.register(obj, prio); + } + ++ /** ++ * Cache the class meta during serialization. ++ * Only used in FastSerilizer. ++ */ ++ private static ConcurrentHashMap> nameToClass = new ConcurrentHashMap<>(); ++ + /** + * Load the local class equivalent of the specified stream class + * description. Subclasses may implement this method to allow classes to + * be fetched from an alternate source. + * ++ * When fastSerializer is turned on, fields of desc will be null except ++ * name. When resolveClass is override, this may cause null pointer exception. ++ * + *

    The corresponding method in {@code ObjectOutputStream} is + * {@code annotateClass}. This method will be invoked only once for + * each unique class in the stream. This method can be implemented by +@@ -800,16 +867,29 @@ public class ObjectInputStream + throws IOException, ClassNotFoundException + { + String name = desc.getName(); +- try { +- return Class.forName(name, false, latestUserDefinedLoader()); +- } catch (ClassNotFoundException ex) { +- Class cl = primClasses.get(name); ++ Class cl = null; ++ ++ if (useFastSerializer) { ++ cl = nameToClass.get(name); + if (cl != null) { + return cl; +- } else { ++ } ++ } ++ ++ try { ++ cl = Class.forName(name, false, latestUserDefinedLoader()); ++ } catch (ClassNotFoundException ex) { ++ cl = primClasses.get(name); ++ if (cl == null) { + throw ex; + } + } ++ ++ if (useFastSerializer) { ++ nameToClass.put(name, cl); ++ } ++ ++ return cl; + } + + /** +@@ -984,9 +1064,33 @@ public class ObjectInputStream + { + short s0 = bin.readShort(); + short s1 = bin.readShort(); +- if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) { +- throw new StreamCorruptedException( +- String.format("invalid stream header: %04X%04X", s0, s1)); ++ if (useFastSerializer) { ++ if (s0 != STREAM_MAGIC_FAST || s1 != STREAM_VERSION) { ++ if (s0 != STREAM_MAGIC) { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X, and FastSerializer is activated", s0, s1)); ++ } ++ ++ if (!fastSerializerEscapeMode) { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X.Fast serialization does not support " + ++ "original serialized files", s0, s1)); ++ } ++ ++ // Escape to default serialization ++ useFastSerializer = false; ++ if (Logging.fastSerLogger != null) { ++ Logging.fastSerLogger.log(Logger.Level.DEBUG, "[Deserialize]: Escape and disable FastSerializer"); ++ } ++ } ++ } else if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) { ++ if (s0 == STREAM_MAGIC_FAST && s1 == STREAM_VERSION) { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X, and it is a FastSerializer stream", s0, s1)); ++ } else { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X", s0, s1)); ++ } + } + } + +@@ -1000,6 +1104,11 @@ public class ObjectInputStream + * this method reads class descriptors according to the format defined in + * the Object Serialization specification. + * ++ * In fastSerialize mode, the descriptor is obtained by lookup method. And ++ * the resolveClass method is called here to get the classmeta. Since the ++ * descriptor is obtained by lookup, the descriptor is same as localdesc. ++ * So we cann't distinguish the receiver desc and local desc. ++ * + * @return the class descriptor read + * @throws IOException If an I/O error has occurred. + * @throws ClassNotFoundException If the Class of a serialized object used +@@ -1010,6 +1119,29 @@ public class ObjectInputStream + protected ObjectStreamClass readClassDescriptor() + throws IOException, ClassNotFoundException + { ++ // fastSerializer ++ if (useFastSerializer) { ++ String name = readUTF(); ++ Class cl = null; ++ ObjectStreamClass desc = new ObjectStreamClass(name); ++ try { ++ // In order to match this method, we add an annotateClass method in ++ // writeClassDescriptor. ++ cl = resolveClass(desc); ++ } catch (ClassNotFoundException ex) { ++ // resolveClass is just used to obtain Class which required by lookup method ++ // and it will be called again later, so we don't throw ClassNotFoundException here. ++ return desc; ++ } ++ if (cl != null) { ++ // This desc is localDesc. It may be different from the descriptor ++ // obtained from the stream. ++ desc = ObjectStreamClass.lookup(cl, true); ++ } ++ return desc; ++ } ++ ++ // Default deserialization. If the Class cannot be found, throw ClassNotFoundException. + ObjectStreamClass desc = new ObjectStreamClass(); + desc.readNonProxy(this); + return desc; +@@ -2072,41 +2204,63 @@ public class ObjectInputStream + + skipCustomData(); + +- try { +- totalObjectRefs++; +- depth++; +- desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); ++ totalObjectRefs++; ++ depth++; + +- if (cl != null) { +- // Check that serial filtering has been done on the local class descriptor's superclass, +- // in case it does not appear in the stream. +- +- // Find the next super descriptor that has a local class descriptor. +- // Descriptors for which there is no local class are ignored. +- ObjectStreamClass superLocal = null; +- for (ObjectStreamClass sDesc = desc.getSuperDesc(); sDesc != null; sDesc = sDesc.getSuperDesc()) { +- if ((superLocal = sDesc.getLocalDesc()) != null) { +- break; ++ if (useFastSerializer) { ++ desc.initNonProxyFast(readDesc, resolveEx); ++ ObjectStreamClass superDesc = desc.getSuperDesc(); ++ long originDepth = depth - 1; ++ // Since desc is obtained from the lookup method, we will lose the depth and ++ // totalObjectRefs of superDesc. So we add a loop here to compute the depth ++ // and objectRef of superDesc. ++ while (superDesc != null && superDesc.forClass() != null) { ++ filterCheck(superDesc.forClass(), -1); ++ superDesc = superDesc.getSuperDesc(); ++ totalObjectRefs++; ++ depth++; ++ } ++ depth = originDepth; ++ } else { ++ try { ++ desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); ++ ++ if (cl != null) { ++ // Check that serial filtering has been done on the local class descriptor's superclass, ++ // in case it does not appear in the stream. ++ // Find the next super descriptor that has a local class descriptor. ++ // Descriptors for which there is no local class are ignored. ++ ObjectStreamClass superLocal = null; ++ for (ObjectStreamClass sDesc = desc.getSuperDesc(); sDesc != null; sDesc = sDesc.getSuperDesc()) { ++ if ((superLocal = sDesc.getLocalDesc()) != null) { ++ break; ++ } + } +- } + +- // Scan local descriptor superclasses for a match with the local descriptor of the super found above. +- // For each super descriptor before the match, invoke the serial filter on the class. +- // The filter is invoked for each class that has not already been filtered +- // but would be filtered if the instance had been serialized by this Java runtime. +- for (ObjectStreamClass lDesc = desc.getLocalDesc().getSuperDesc(); +- lDesc != null && lDesc != superLocal; +- lDesc = lDesc.getSuperDesc()) { +- filterCheck(lDesc.forClass(), -1); ++ // Scan local descriptor superclasses for a match with the local descriptor of the super found above. ++ // For each super descriptor before the match, invoke the serial filter on the class. ++ // The filter is invoked for each class that has not already been filtered ++ // but would be filtered if the instance had been serialized by this Java runtime. ++ for (ObjectStreamClass lDesc = desc.getLocalDesc().getSuperDesc(); ++ lDesc != null && lDesc != superLocal; ++ lDesc = lDesc.getSuperDesc()) { ++ filterCheck(lDesc.forClass(), -1); ++ } + } ++ } finally { ++ depth--; + } +- } finally { +- depth--; + } + + handles.finish(descHandle); + passHandle = descHandle; + ++ if (Logging.fastSerLogger != null) { ++ Logging.fastSerLogger.log(Logger.Level.DEBUG, ++ "[Deserialize] useFastSerializer:{0}, Class name:{1}, SerialVersionUID:{2}, flags:{3}", ++ useFastSerializer, desc.getName(), desc.getSerialVersionUID(), desc.getFlags(this)); ++ } ++ + return desc; + } + +@@ -2964,8 +3118,6 @@ public class ObjectInputStream + } + } + +- private static final Unsafe UNSAFE = Unsafe.getUnsafe(); +- + /** + * Performs a "freeze" action, required to adhere to final field semantics. + * +diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java +index eb5407a94..adb24a8dc 100644 +--- a/src/java.base/share/classes/java/io/ObjectOutputStream.java ++++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java +@@ -33,6 +33,7 @@ import java.util.List; + import java.util.Objects; + import java.util.StringJoiner; + ++import jdk.internal.misc.Unsafe; + import jdk.internal.util.ByteArray; + import sun.reflect.misc.ReflectUtil; + +@@ -181,6 +182,25 @@ public class ObjectOutputStream + }; + } + ++ private static class Logging { ++ /* ++ * Logger for FastSerializer. ++ * Setup the FastSerializer logger if it is set to DEBUG. ++ * (Assuming it will not change). ++ */ ++ static final System.Logger fastSerLogger; ++ ++ static { ++ if (printFastSerializer) { ++ System.Logger fastSerLog = System.getLogger("fastSerializer"); ++ fastSerLogger = (fastSerLog.isLoggable(System.Logger.Level.DEBUG)) ++ ? fastSerLog : null; ++ } else { ++ fastSerLogger = null; ++ } ++ } ++ } ++ + /** filter stream for handling block data conversion */ + private final BlockDataOutputStream bout; + /** obj -> wire handle map */ +@@ -199,7 +219,6 @@ public class ObjectOutputStream + private final boolean enableOverride; + /** if true, invoke replaceObject() */ + private boolean enableReplace; +- + // values below valid only during upcalls to writeObject()/writeExternal() + /** + * Context during upcalls to class-defined writeObject methods; holds +@@ -223,6 +242,28 @@ public class ObjectOutputStream + new sun.security.action.GetBooleanAction( + "sun.io.serialization.extendedDebugInfo")).booleanValue(); + ++ private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ ++ /** ++ * Value of "UseFastSerializer" property, The fastSerializer is turned ++ * on when it is true. ++ */ ++ private static final boolean useFastSerializer = UNSAFE.getUseFastSerializer(); ++ ++ /** ++ * value of "printFastSerializer" property, ++ * as true or false for printing FastSerializer logs. ++ */ ++ @SuppressWarnings("removal") ++ private static final boolean printFastSerializer = java.security.AccessController.doPrivileged( ++ new sun.security.action.GetBooleanAction( ++ "printFastSerializer")).booleanValue(); ++ ++ /** ++ * Magic number that is written to the stream header when using fastserilizer. ++ */ ++ private static final short STREAM_MAGIC_FAST = (short)0xdeca; ++ + /** + * Creates an ObjectOutputStream that writes to the specified OutputStream. + * This constructor writes the serialization stream header to the +@@ -337,6 +378,9 @@ public class ObjectOutputStream + * object are written transitively so that a complete equivalent graph of + * objects can be reconstructed by an ObjectInputStream. + * ++ * The difference between fastSerialzation and default serialization is the ++ * descriptor serialization. The data serialization is same with each other. ++ * + *

    Exceptions are thrown for problems with the OutputStream and for + * classes that should not be serialized. All exceptions are fatal to the + * OutputStream, which is left in an indeterminate state, and it is up to +@@ -646,7 +690,11 @@ public class ObjectOutputStream + * stream + */ + protected void writeStreamHeader() throws IOException { +- bout.writeShort(STREAM_MAGIC); ++ if (useFastSerializer) { ++ bout.writeShort(STREAM_MAGIC_FAST); ++ } else { ++ bout.writeShort(STREAM_MAGIC); ++ } + bout.writeShort(STREAM_VERSION); + } + +@@ -662,6 +710,9 @@ public class ObjectOutputStream + * defined in the + * Java Object Serialization Specification. + * ++ * In fastSerializer mode, we will only write the classname to the stream. ++ * The annotateClass is used to match the resolveClass in readClassDescriptor. ++ * + *

    Note that this method will only be called if the ObjectOutputStream + * is not using the old serialization stream format (set by calling + * ObjectOutputStream's {@code useProtocolVersion} method). If this +@@ -680,7 +731,14 @@ public class ObjectOutputStream + protected void writeClassDescriptor(ObjectStreamClass desc) + throws IOException + { +- desc.writeNonProxy(this); ++ if (useFastSerializer) { ++ writeUTF(desc.getName()); ++ // The annotateClass is used to match the resolveClass called in ++ // readClassDescriptor. ++ annotateClass(desc.forClass()); ++ } else { ++ desc.writeNonProxy(this); ++ } + } + + /** +@@ -1291,9 +1349,21 @@ public class ObjectOutputStream + bout.writeByte(TC_CLASSDESC); + handles.assign(unshared ? null : desc); + ++ if (Logging.fastSerLogger != null) { ++ Logging.fastSerLogger.log(System.Logger.Level.DEBUG, ++ "[Serialize] useFastSerializer:{0}, Class name:{1}, SerialVersionUID:{2}, flags:{3}, protocol:{4}", ++ useFastSerializer, desc.getName(), desc.getSerialVersionUID(), desc.getFlags(this), protocol); ++ } ++ + if (protocol == PROTOCOL_VERSION_1) { + // do not invoke class descriptor write hook with old protocol +- desc.writeNonProxy(this); ++ if (useFastSerializer) { ++ // only write name and annotate class when using FastSerializer ++ writeUTF(desc.getName()); ++ annotateClass(desc.forClass()); ++ } else { ++ desc.writeNonProxy(this); ++ } + } else { + writeClassDescriptor(desc); + } +@@ -1306,8 +1376,9 @@ public class ObjectOutputStream + annotateClass(cl); + bout.setBlockDataMode(false); + bout.writeByte(TC_ENDBLOCKDATA); +- +- writeClassDesc(desc.getSuperDesc(), false); ++ if (!useFastSerializer) { ++ writeClassDesc(desc.getSuperDesc(), false); ++ } + } + + /** +diff --git a/src/java.base/share/classes/java/io/ObjectStreamClass.java b/src/java.base/share/classes/java/io/ObjectStreamClass.java +index 58841e55a..63aa16a52 100644 +--- a/src/java.base/share/classes/java/io/ObjectStreamClass.java ++++ b/src/java.base/share/classes/java/io/ObjectStreamClass.java +@@ -296,6 +296,40 @@ public final class ObjectStreamClass implements Serializable { + return suid.longValue(); + } + ++ /** ++ * Return the flags for this class described by this descriptor. The flags ++ * means a set of bit masks for ObjectStreamClass, which indicate the status ++ * of SC_WRITE_METHOD, SC_SERIALIZABLE, SC_EXTERNALIZABLE, SC_BLOCK_DATA and ++ * SC_ENUM. ++ * ++ * @param serialStream ObjectOutputStream or ObjectInputStream ++ * ++ * @return the flags for this class described by this descriptor ++ */ ++ byte getFlags(Object serialStream) { ++ byte flags = 0; ++ if (externalizable) { ++ flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; ++ if (serialStream instanceof ObjectOutputStream) { ++ int protocol = ((ObjectOutputStream)serialStream).getProtocolVersion(); ++ if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { ++ flags |= ObjectStreamConstants.SC_BLOCK_DATA; ++ } ++ } else if (serialStream instanceof ObjectInputStream) { ++ flags |= ObjectStreamConstants.SC_BLOCK_DATA; ++ } ++ } else if (serializable) { ++ flags |= ObjectStreamConstants.SC_SERIALIZABLE; ++ } ++ if (hasWriteObjectData) { ++ flags |= ObjectStreamConstants.SC_WRITE_METHOD; ++ } ++ if (isEnum) { ++ flags |= ObjectStreamConstants.SC_ENUM; ++ } ++ return flags; ++ } ++ + /** + * Return the class in the local VM that this version is mapped to. Null + * is returned if there is no corresponding local class. +@@ -468,6 +502,15 @@ public final class ObjectStreamClass implements Serializable { + ObjectStreamClass() { + } + ++ /** ++ * Create a blank class descriptor with name. It is only used ++ * in fastSerialize path. ++ * @param name class name ++ */ ++ ObjectStreamClass(String name) { ++ this.name = name; ++ } ++ + /** + * Creates a PermissionDomain that grants no permission. + */ +@@ -662,6 +705,44 @@ public final class ObjectStreamClass implements Serializable { + initialized = true; + } + ++ /** ++ * Initializes class descriptor representing a non-proxy class. ++ * Used in fast serialization mode. ++ */ ++ void initNonProxyFast(ObjectStreamClass model, ++ ClassNotFoundException resolveEx) ++ { ++ this.cl = model.cl; ++ this.resolveEx = resolveEx; ++ this.superDesc = model.superDesc; ++ name = model.name; ++ this.suid = model.suid; ++ isProxy = false; ++ isEnum = model.isEnum; ++ serializable = model.serializable; ++ externalizable = model.externalizable; ++ hasBlockExternalData = model.hasBlockExternalData; ++ hasWriteObjectData = model.hasWriteObjectData; ++ fields = model.fields; ++ primDataSize = model.primDataSize; ++ numObjFields = model.numObjFields; ++ ++ writeObjectMethod = model.writeObjectMethod; ++ readObjectMethod = model.readObjectMethod; ++ readObjectNoDataMethod = model.readObjectNoDataMethod; ++ writeReplaceMethod = model.writeReplaceMethod; ++ readResolveMethod = model.readResolveMethod; ++ if (deserializeEx == null) { ++ deserializeEx = model.deserializeEx; ++ } ++ domains = model.domains; ++ cons = model.cons; ++ fieldRefl = model.fieldRefl; ++ localDesc = model; ++ ++ initialized = true; ++ } ++ + /** + * Reads non-proxy class descriptor information from given input stream. + * The resulting class descriptor is not fully functional; it can only be +diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +index 47e8bf80c..926d30691 100644 +--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java ++++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +@@ -3819,7 +3819,7 @@ public final class Unsafe { + private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; } + + +- ++ public native boolean getUseFastSerializer(); + private native long allocateMemory0(long bytes); + private native long reallocateMemory0(long address, long bytes); + private native void freeMemory0(long address); +-- +2.47.0.windows.2 + diff --git a/huawei-Add-Hashmap-frontCache-opt.patch b/huawei-Add-Hashmap-frontCache-opt.patch new file mode 100644 index 0000000000000000000000000000000000000000..490155223fbff409b9248d047067accf983f7a41 --- /dev/null +++ b/huawei-Add-Hashmap-frontCache-opt.patch @@ -0,0 +1,531 @@ +Date: Thu, 13 Mar 2025 17:43:57 +0800 +Subject: Add Hashmap frontCache opt + +--- + src/hotspot/cpu/arm/vm_version_arm_32.cpp | 10 + + src/hotspot/cpu/riscv/vm_version_riscv.cpp | 10 + + src/hotspot/cpu/s390/vm_version_s390.cpp | 10 + + src/hotspot/cpu/x86/vm_version_x86.cpp | 5 + + src/hotspot/cpu/zero/vm_version_zero.cpp | 10 + + src/hotspot/share/prims/unsafe.cpp | 7 + + src/hotspot/share/runtime/globals.hpp | 5 + + .../share/classes/java/util/HashMap.java | 192 +++++++++++++++++- + .../classes/jdk/internal/misc/Unsafe.java | 2 +- + 9 files changed, 249 insertions(+), 2 deletions(-) + +diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp +index 44f2179db..0b4bcdee9 100644 +--- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp ++++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp +@@ -263,6 +263,16 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + ++ if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { ++ FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); ++ warning("HashMap optimization is not supported in this VM."); ++ } ++ ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } ++ + #ifdef COMPILER2 + // C2 is only supported on v7+ VFP at this time + if (_arm_arch < 7 || !has_vfp()) { +diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +index 4ad0b16b6..a740b0301 100644 +--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp ++++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +@@ -228,6 +228,16 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UseBlockZeroing, false); + } + ++ if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { ++ FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); ++ warning("HashMap optimization is not supported in this VM."); ++ } ++ ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } ++ + #ifdef COMPILER2 + c2_initialize(); + #endif // COMPILER2 +diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp +index e3741b29c..44a0275e4 100644 +--- a/src/hotspot/cpu/s390/vm_version_s390.cpp ++++ b/src/hotspot/cpu/s390/vm_version_s390.cpp +@@ -287,6 +287,16 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UsePopCountInstruction, true); + } + ++ if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { ++ FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); ++ warning("HashMap optimization is not supported in this VM."); ++ } ++ ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } ++ + // z/Architecture supports 8-byte compare-exchange operations + // (see Atomic::cmpxchg) + // and 'atomic long memory ops' (see Unsafe_GetLongVolatile). +diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp +index d71d3a93f..6f35090cc 100644 +--- a/src/hotspot/cpu/x86/vm_version_x86.cpp ++++ b/src/hotspot/cpu/x86/vm_version_x86.cpp +@@ -1204,6 +1204,11 @@ void VM_Version::get_processor_features() { + FLAG_SET_DEFAULT(UseFastSerializer, false); + warning("Serializer optimization is not supported in this VM."); + } ++ if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { ++ FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); ++ warning("HashMap optimization is not supported in this VM."); ++ } ++ + #endif + + #ifdef _LP64 +diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp +index a99885a53..94f33f70b 100644 +--- a/src/hotspot/cpu/zero/vm_version_zero.cpp ++++ b/src/hotspot/cpu/zero/vm_version_zero.cpp +@@ -71,6 +71,16 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UseFMA, false); + } + ++ if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { ++ FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); ++ warning("HashMap optimization is not supported in this VM."); ++ } ++ ++ if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { ++ FLAG_SET_DEFAULT(UseFastSerializer, false); ++ warning("Serializer optimization is not supported in this VM."); ++ } ++ + if (UseMD5Intrinsics) { + warning("MD5 intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseMD5Intrinsics, false); +diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp +index 921693473..2fd9ed1d0 100644 +--- a/src/hotspot/share/prims/unsafe.cpp ++++ b/src/hotspot/share/prims/unsafe.cpp +@@ -825,6 +825,11 @@ UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleAr + return ret; + } UNSAFE_END + ++UNSAFE_ENTRY(jboolean, Unsafe_GetUseHashMapIntegerCache(JNIEnv *env, jobject unsafe)) { ++ return UseHashMapIntegerCache; ++} ++UNSAFE_END ++ + UNSAFE_ENTRY(jboolean, Unsafe_GetUseFastSerializer(JNIEnv *env, jobject unsafe)) { + return UseFastSerializer; + } +@@ -905,6 +910,8 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { + {CC "writebackPostSync0", CC "()V", FN_PTR(Unsafe_WriteBackPostSync0)}, + {CC "setMemory0", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory0)}, + ++ {CC "getUseHashMapIntegerCache", CC "()Z", FN_PTR(Unsafe_GetUseHashMapIntegerCache)} ++ , + {CC "shouldBeInitialized0", CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized0)}, + + {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, +diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp +index ac33876d8..231c2ef16 100644 +--- a/src/hotspot/share/runtime/globals.hpp ++++ b/src/hotspot/share/runtime/globals.hpp +@@ -1966,6 +1966,11 @@ const int ObjectAlignmentInBytes = 8; + product(bool, UseFastUnorderedTimeStamps, false, EXPERIMENTAL, \ + "Use platform unstable time where supported for timestamps only") \ + \ ++ product(bool, UseHashMapIntegerCache, false, EXPERIMENTAL, \ ++ "The integer cache is an array of references to objects of" \ ++ "the HashMap Value type, indexed by the unboxed int key value." \ ++ "faster in execution, higher in memory consumption.") \ ++ \ + product(bool, UseEmptySlotsInSupers, true, \ + "Allow allocating fields in empty slots of super-classes") \ + \ +diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java +index 3ec69cfe9..e6f4a0464 100644 +--- a/src/java.base/share/classes/java/util/HashMap.java ++++ b/src/java.base/share/classes/java/util/HashMap.java +@@ -36,6 +36,7 @@ import java.util.function.BiFunction; + import java.util.function.Consumer; + import java.util.function.Function; + import jdk.internal.access.SharedSecrets; ++import jdk.internal.misc.Unsafe; + + /** + * Hash table based implementation of the {@code Map} interface. This +@@ -274,6 +275,28 @@ public class HashMap extends AbstractMap + */ + static final int MIN_TREEIFY_CAPACITY = 64; + ++ /** ++ * Used to get the commandline option: UseHashMapIntegerCache. ++ */ ++ private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ ++ /** ++ * Indicate integerCache can be performed. disable if HashMap.Node.setValue ++ * is directly used to update Node value. ++ */ ++ private static boolean enableIntegerCache = UNSAFE.getUseHashMapIntegerCache(); ++ ++ /** ++ * The smallest table size for create integer cache. ++ */ ++ private static final int MIN_INTEGER_CACHE = 2048; ++ ++ /** ++ * The factor used in create integer cache to guarantee most Key are ++ * Integer and in range. ++ */ ++ private static final float INTEGER_CACHE_FACTOR = 0.95f; ++ + /** + * Basic hash bin node, used for most entries. (See below for + * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) +@@ -300,6 +323,10 @@ public class HashMap extends AbstractMap + } + + public final V setValue(V newValue) { ++ // Disable integerCache in all HashMap instance. ++ if (key != null && key instanceof Integer) { ++ enableIntegerCache = false; ++ } + V oldValue = value; + value = newValue; + return oldValue; +@@ -389,6 +416,12 @@ public class HashMap extends AbstractMap + */ + transient Node[] table; + ++ /** ++ * Cache Value> Map ++ * integerCache[key->intValue] = V ++ */ ++ transient Object[] integerCache; ++ + /** + * Holds cached entrySet(). Note that AbstractMap fields are used + * for keySet() and values(). +@@ -559,7 +592,20 @@ public class HashMap extends AbstractMap + * + * @see #put(Object, Object) + */ ++ @SuppressWarnings("unchecked") + public V get(Object key) { ++ if (integerCache != null) { ++ if (enableIntegerCache == false) { ++ integerCache = null; ++ } ++ else if (key != null && key instanceof Integer) { ++ int val = ((Integer)key).intValue(); ++ if (val >= 0 && val < integerCache.length) { ++ return (V)integerCache[val]; ++ } ++ } ++ } ++ + Node e; + return (e = getNode(key)) == null ? null : e.value; + } +@@ -599,7 +645,18 @@ public class HashMap extends AbstractMap + * key. + */ + public boolean containsKey(Object key) { +- return getNode(key) != null; ++ if (integerCache != null) { ++ if (enableIntegerCache == false) { ++ integerCache = null; ++ } ++ else if (key != null && key instanceof Integer) { ++ int val = ((Integer)key).intValue(); ++ if (val >= 0 && val < integerCache.length && integerCache[val] != null) { ++ return true; ++ } ++ } ++ } ++ return getNode(key) != null; + } + + /** +@@ -631,6 +688,11 @@ public class HashMap extends AbstractMap + final V putVal(int hash, K key, V value, boolean onlyIfAbsent, + boolean evict) { + Node[] tab; Node p; int n, i; ++ ++ if (integerCache != null) { ++ updateIntegerCache(key, value, onlyIfAbsent); ++ } ++ + if ((tab = table) == null || (n = tab.length) == 0) + n = (tab = resize()).length; + if ((p = tab[i = (n - 1) & hash]) == null) +@@ -751,6 +813,8 @@ public class HashMap extends AbstractMap + } + } + } ++ ++ createIntegerCache(); + return newTab; + } + +@@ -850,6 +914,10 @@ public class HashMap extends AbstractMap + p.next = node.next; + ++modCount; + --size; ++ ++ if (integerCache != null) { ++ updateIntegerCache(node.key, null, false); ++ } + afterNodeRemoval(node); + return node; + } +@@ -869,6 +937,7 @@ public class HashMap extends AbstractMap + for (int i = 0; i < tab.length; ++i) + tab[i] = null; + } ++ integerCache = null; + } + + /** +@@ -893,6 +962,82 @@ public class HashMap extends AbstractMap + return false; + } + ++ /** ++ * 1. iterator all Keys and statistic ++ * Integer Key count, total count is size ++ * Integer Key count in range [0, table.length], get Max value. ++ * ++ * 2. Create integer cache ++ */ ++ @SuppressWarnings({"unchecked"}) ++ private final void createIntegerCache() { ++ int n = table.length; ++ int intKeyCount = 0; ++ int intKeyCountInrange = 0; ++ int maxIntKey = 0; ++ if (n < MIN_INTEGER_CACHE || (enableIntegerCache == false)) { ++ integerCache = null; ++ return; ++ } ++ Iterator it = this.keySet().iterator(); ++ while (it.hasNext()) { ++ K key = it.next(); ++ if (key != null && key instanceof Integer) { ++ intKeyCount++; ++ int val = ((Integer)key).intValue(); ++ if (val >= 0 && val < n) { ++ intKeyCountInrange++; ++ if (val > maxIntKey) ++ maxIntKey = val; ++ } ++ } ++ } ++ float keyIntRation = ((float)intKeyCount) / size; ++ float keyIntInRangeRation = ((float)intKeyCountInrange) / size; ++ if (keyIntRation >= INTEGER_CACHE_FACTOR && ++ keyIntInRangeRation >= INTEGER_CACHE_FACTOR) { ++ // compute integerCache size ++ int cacheMapSize = n < (2 * maxIntKey) ? n : (2 * maxIntKey); ++ integerCache = new Object[cacheMapSize]; ++ Iterator> entries = this.entrySet().iterator(); ++ while (entries.hasNext()) { ++ Map.Entry thisEntry = entries.next(); ++ K key = thisEntry.getKey(); ++ V value = thisEntry.getValue(); ++ if (key != null && key instanceof Integer) { ++ int val = ((Integer)key).intValue(); ++ if (val >= 0 && val < integerCache.length) { ++ integerCache[val] = value; ++ } ++ } ++ } ++ } else { ++ integerCache = null; ++ } ++ } ++ ++ /** ++ * put if integerCache null check outside of this call ++ * JIT will not inline this method (not hot) when HashMap is not Integer Key intensive. ++ * Otherwise it will always inline updateIntegerCache method. ++ * ++ */ ++ private final void updateIntegerCache(K key, V value, boolean onlyIfAbsent) { ++ if (enableIntegerCache == false) { ++ integerCache = null; ++ return; ++ } ++ if (key != null && key instanceof Integer) { ++ int val = ((Integer)key).intValue(); ++ if (val >= 0 && val < integerCache.length) { ++ if (onlyIfAbsent && integerCache[val] != null) { ++ return; ++ } ++ integerCache[val] = value; ++ } ++ } ++ } ++ + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are +@@ -1142,7 +1287,19 @@ public class HashMap extends AbstractMap + // Overrides of JDK8 Map extension methods + + @Override ++ @SuppressWarnings("unchecked") + public V getOrDefault(Object key, V defaultValue) { ++ if (integerCache != null) { ++ if (enableIntegerCache == false) { ++ integerCache = null; ++ } else if (key != null && key instanceof Integer) { ++ V value; ++ int val = ((Integer)key).intValue(); ++ if (val >= 0 && val < integerCache.length && (value = (V)integerCache[val]) != null) { ++ return value; ++ } ++ } ++ } + Node e; + return (e = getNode(key)) == null ? defaultValue : e.value; + } +@@ -1163,6 +1320,9 @@ public class HashMap extends AbstractMap + if ((e = getNode(key)) != null && + ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) { + e.value = newValue; ++ if (integerCache != null) { ++ updateIntegerCache(key, newValue, false); ++ } + afterNodeAccess(e); + return true; + } +@@ -1175,6 +1335,9 @@ public class HashMap extends AbstractMap + if ((e = getNode(key)) != null) { + V oldValue = e.value; + e.value = value; ++ if (integerCache != null) { ++ updateIntegerCache(key, value, false); ++ } + afterNodeAccess(e); + return oldValue; + } +@@ -1231,6 +1394,9 @@ public class HashMap extends AbstractMap + return null; + } else if (old != null) { + old.value = v; ++ if (integerCache != null) { ++ updateIntegerCache(key, v, false); ++ } + afterNodeAccess(old); + return v; + } +@@ -1241,6 +1407,11 @@ public class HashMap extends AbstractMap + if (binCount >= TREEIFY_THRESHOLD - 1) + treeifyBin(tab, hash); + } ++ ++ if (integerCache != null) { ++ updateIntegerCache(key, v, false); ++ } ++ + modCount = mc + 1; + ++size; + afterNodeInsertion(true); +@@ -1270,6 +1441,9 @@ public class HashMap extends AbstractMap + if (mc != modCount) { throw new ConcurrentModificationException(); } + if (v != null) { + e.value = v; ++ if (integerCache != null) { ++ updateIntegerCache(key, v, false); ++ } + afterNodeAccess(e); + return v; + } +@@ -1326,6 +1500,9 @@ public class HashMap extends AbstractMap + if (old != null) { + if (v != null) { + old.value = v; ++ if (integerCache != null) { ++ updateIntegerCache(key, v, false); ++ } + afterNodeAccess(old); + } + else +@@ -1339,6 +1516,9 @@ public class HashMap extends AbstractMap + if (binCount >= TREEIFY_THRESHOLD - 1) + treeifyBin(tab, hash); + } ++ if (integerCache != null) { ++ updateIntegerCache(key, v, false); ++ } + modCount = mc + 1; + ++size; + afterNodeInsertion(true); +@@ -1397,6 +1577,9 @@ public class HashMap extends AbstractMap + } + if (v != null) { + old.value = v; ++ if (integerCache != null) { ++ updateIntegerCache(key, v, false); ++ } + afterNodeAccess(old); + } + else +@@ -1410,6 +1593,9 @@ public class HashMap extends AbstractMap + if (binCount >= TREEIFY_THRESHOLD - 1) + treeifyBin(tab, hash); + } ++ if (integerCache != null) { ++ updateIntegerCache(key, value, false); ++ } + ++modCount; + ++size; + afterNodeInsertion(true); +@@ -1443,6 +1629,9 @@ public class HashMap extends AbstractMap + for (Node e : tab) { + for (; e != null; e = e.next) { + e.value = function.apply(e.key, e.value); ++ if (integerCache != null) { ++ updateIntegerCache(e.key, e.value, false); ++ } + } + } + if (modCount != mc) +@@ -1935,6 +2124,7 @@ public class HashMap extends AbstractMap + modCount = 0; + threshold = 0; + size = 0; ++ integerCache = null; + } + + // Callbacks to allow LinkedHashMap post-actions +diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +index 926d30691..58c218753 100644 +--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java ++++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +@@ -3818,7 +3818,7 @@ public final class Unsafe { + private static int convEndian(boolean big, int n) { return big == BIG_ENDIAN ? n : Integer.reverseBytes(n) ; } + private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; } + +- ++ public native boolean getUseHashMapIntegerCache(); + public native boolean getUseFastSerializer(); + private native long allocateMemory0(long bytes); + private native long reallocateMemory0(long address, long bytes); +-- +2.47.0.windows.2 + diff --git a/huawei-Add-KAE-Provider.patch b/huawei-Add-KAE-Provider.patch new file mode 100644 index 0000000000000000000000000000000000000000..b234737ad0ec22dd15687829181ce53b63c8a221 --- /dev/null +++ b/huawei-Add-KAE-Provider.patch @@ -0,0 +1,14479 @@ +Date: Thu, 13 Mar 2025 10:25:51 +0800 +Subject: Add KAE Provider + +--- + make/ZipSecurity.gmk | 1 + + make/autoconf/configure.ac | 1 + + make/autoconf/jdk-options.m4 | 21 + + make/autoconf/spec.gmk.in | 1 + + make/common/Modules.gmk | 13 + + make/conf/module-loader-map.conf | 1 + + .../hotspot/nbproject/configurations.xml | 104 +++ + make/modules/jdk.crypto.kaeprovider/Copy.gmk | 46 + + make/modules/jdk.crypto.kaeprovider/Lib.gmk | 46 + + src/java.base/share/classes/module-info.java | 8 +- + .../share/lib/security/default.policy | 5 + + .../share/classes/module-info.java | 6 + + .../linux/classes/module-info.java | 39 + + .../security/openssl/KAEAESCipher.java | 365 ++++++++ + .../openeuler/security/openssl/KAEConfig.java | 393 +++++++++ + .../security/openssl/KAEDHKeyAgreement.java | 289 +++++++ + .../openssl/KAEDHKeyPairGenerator.java | 183 ++++ + .../openeuler/security/openssl/KAEDigest.java | 264 ++++++ + .../security/openssl/KAEECDHKeyAgreement.java | 146 ++++ + .../openssl/KAEECKeyPairGenerator.java | 151 ++++ + .../openeuler/security/openssl/KAEHMac.java | 227 +++++ + .../openeuler/security/openssl/KAELog.java | 188 +++++ + .../openeuler/security/openssl/KAEMGF1.java | 94 +++ + .../security/openssl/KAEProvider.java | 326 +++++++ + .../security/openssl/KAERSACipher.java | 796 ++++++++++++++++++ + .../openssl/KAERSAKeyPairGenerator.java | 164 ++++ + .../security/openssl/KAERSAPSSSignature.java | 683 +++++++++++++++ + .../security/openssl/KAERSAPaddingType.java | 83 ++ + .../security/openssl/KAERSASignature.java | 365 ++++++++ + .../openssl/KAERSASignatureNative.java | 46 + + .../security/openssl/KAESM4Cipher.java | 370 ++++++++ + .../security/openssl/KAESM4KeyGenerator.java | 74 ++ + .../openssl/KAESymmetricCipherBase.java | 791 +++++++++++++++++ + .../openeuler/security/openssl/KAEUtils.java | 220 +++++ + .../linux/conf/security/kaeprovider.conf | 75 ++ + .../security/openssl/kae_cipher_rsa.c | 471 +++++++++++ + .../openeuler/security/openssl/kae_digest.c | 232 +++++ + .../security/openssl/kae_exception.c | 135 +++ + .../security/openssl/kae_exception.h | 57 ++ + .../org/openeuler/security/openssl/kae_hmac.c | 208 +++++ + .../security/openssl/kae_keyagreement_dh.c | 141 ++++ + .../security/openssl/kae_keyagreement_ecdh.c | 121 +++ + .../openssl/kae_keypairgenerator_dh.c | 132 +++ + .../openssl/kae_keypairgenerator_ec.c | 505 +++++++++++ + .../openssl/kae_keypairgenerator_rsa.c | 173 ++++ + .../org/openeuler/security/openssl/kae_log.h | 33 + + .../openeuler/security/openssl/kae_provider.c | 103 +++ + .../security/openssl/kae_signature_rsa.c | 366 ++++++++ + .../security/openssl/kae_symmetric_cipher.c | 415 +++++++++ + .../org/openeuler/security/openssl/kae_util.c | 246 ++++++ + .../org/openeuler/security/openssl/kae_util.h | 94 +++ + .../openeuler/security/openssl/openssl_ad.h | 10 + + test/jdk/TEST.groups | 3 + + .../KeyAgreement/KeyAgreementTest.java | 11 +- + .../Signature/SignatureGetInstance.java | 6 +- + .../openeuler/security/openssl/AESTest.java | 115 +++ + .../openeuler/security/openssl/DHTest.java | 122 +++ + .../security/openssl/DigestTest.java | 61 ++ + .../openeuler/security/openssl/ECDHTest.java | 114 +++ + .../openeuler/security/openssl/HmacTest.java | 89 ++ + .../security/openssl/KAEConfTest.java | 122 +++ + .../openssl/KAEDisabledAlgorithmsTest.java | 165 ++++ + .../security/openssl/KAEEngineIdTest.java | 77 ++ + .../security/openssl/KAELogTest.java | 127 +++ + .../security/openssl/KAETestHelper.java | 209 +++++ + .../security/openssl/KAEUseEngineTest.java | 263 ++++++ + .../security/openssl/KaeDebugLogTest.java | 89 ++ + .../security/openssl/KaeProviderTest.java | 171 ++++ + .../openeuler/security/openssl/RSATest.java | 115 +++ + .../openeuler/security/openssl/SM3Test.java | 55 ++ + .../openeuler/security/openssl/SM4Test.java | 153 ++++ + .../jca/PreferredProviderNegativeTest.java | 7 +- + .../jdk/sun/security/krb5/auto/BasicProc.java | 4 +- + test/jdk/sun/security/pkcs11/Secmod/policy | 1 + + test/jdk/sun/security/pkcs11/policy | 1 + + .../ssl/CipherSuite/DisabledCurve.java | 4 + + .../SSLSocketImpl/NotifyHandshakeTest.policy | 2 + + .../bench/security/openssl/AESBenchmark.java | 108 +++ + .../security/openssl/AESGCMBenchmark.java | 133 +++ + .../bench/security/openssl/BenchmarkBase.java | 106 +++ + .../openssl/DHKeyAgreementBenchMark.java | 139 +++ + .../openssl/DHKeyPairGeneratorBenchmark.java | 64 ++ + .../security/openssl/DigestBenchmark.java | 69 ++ + .../openssl/ECKeyAgreementBenchmark.java | 88 ++ + .../openssl/ECKeyPairGeneratorBenchmark.java | 63 ++ + .../bench/security/openssl/HMacBenchmark.java | 73 ++ + .../security/openssl/RSACipherBenchmark.java | 107 +++ + .../openssl/RSAKeyPairGeneratorBenchmark.java | 64 ++ + .../openssl/RSAPSSSignatureBenchmark.java | 118 +++ + .../openssl/RSASignatureBenchmark.java | 90 ++ + .../bench/security/openssl/SM3Benchmark.java | 98 +++ + .../bench/security/openssl/SM4Benchmark.java | 157 ++++ + 92 files changed, 13584 insertions(+), 5 deletions(-) + create mode 100644 make/modules/jdk.crypto.kaeprovider/Copy.gmk + create mode 100644 make/modules/jdk.crypto.kaeprovider/Lib.gmk + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/module-info.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEAESCipher.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h + create mode 100644 test/jdk/org/openeuler/security/openssl/AESTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/DHTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/DigestTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/ECDHTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/HmacTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEConfTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAELogTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAETestHelper.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KaeProviderTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/RSATest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/SM3Test.java + create mode 100644 test/jdk/org/openeuler/security/openssl/SM4Test.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/DHKeyPairGeneratorBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/ECKeyAgreementBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/ECKeyPairGeneratorBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSAPSSSignatureBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java + +diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk +index 489bbef49..170b54df6 100644 +--- a/make/ZipSecurity.gmk ++++ b/make/ZipSecurity.gmk +@@ -42,6 +42,7 @@ $(eval $(call SetupZipArchive,BUILD_SEC_BIN_ZIP, \ + modules/java.base/sun/security/internal/spec \ + modules/java.base/com/sun/crypto/provider \ + modules/jdk.crypto.ec/sun/security/ec \ ++ modules/jdk.crypto.kaeprovider/org/openeuler/security/openssl \ + modules/jdk.crypto.mscapi/sun/security/mscapi \ + modules/jdk.crypto.cryptoki/sun/security/pkcs11 \ + modules/jdk.crypto.cryptoki/sun/security/pkcs11/wrapper \ +diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac +index f7e9844a6..55201277c 100644 +--- a/make/autoconf/configure.ac ++++ b/make/autoconf/configure.ac +@@ -256,6 +256,7 @@ HOTSPOT_SETUP_MISC + LIB_TESTS_ENABLE_DISABLE_FAILURE_HANDLER + LIB_TESTS_ENABLE_DISABLE_JTREG_TEST_THREAD_FACTORY + ++JDKOPT_DETECT_KAE + JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST + JDKOPT_EXCLUDE_TRANSLATIONS + JDKOPT_ENABLE_DISABLE_MANPAGES +diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 +index 2cbdf74ae..a858c5e7e 100644 +--- a/make/autoconf/jdk-options.m4 ++++ b/make/autoconf/jdk-options.m4 +@@ -345,6 +345,27 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], + AC_SUBST(SHIP_DEBUG_SYMBOLS) + ]) + ++############################################################################### ++# ++# Enable or disable the kae crypto implementation ++# ++AC_DEFUN_ONCE([JDKOPT_DETECT_KAE], ++[ ++ AC_ARG_ENABLE(kae, [AS_HELP_STRING([--enable-kae], ++ [enable KAE support on aarch64 @<:@disabled@:>@])], ++ [ENABLE_KAE="true"], [ENABLE_KAE="false"]) ++ AC_MSG_CHECKING([if kae has been enabled]) ++ if test "x$enable_kae" = "xyes"; then ++ AC_MSG_RESULT([yes]) ++ elif test "x$enable_kae" = "x" || test "x$enable_kae" = "xno"; then ++ AC_MSG_RESULT([no]) ++ else ++ AC_MSG_ERROR([Invalid value for --enable-kae: $enable_kae]) ++ fi ++ ++ AC_SUBST(ENABLE_KAE) ++]) ++ + ################################################################################ + # + # Native and Java code coverage +diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in +index f6def153c..8336b287a 100644 +--- a/make/autoconf/spec.gmk.in ++++ b/make/autoconf/spec.gmk.in +@@ -804,6 +804,7 @@ TAR_INCLUDE_PARAM:=@TAR_INCLUDE_PARAM@ + TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@ + + # Build setup ++ENABLE_KAE:=@ENABLE_KAE@ + USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ + USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ + USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ +diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk +index 0eb0fb2dd..c3c6a1bf4 100644 +--- a/make/common/Modules.gmk ++++ b/make/common/Modules.gmk +@@ -312,6 +312,19 @@ define ReadImportMetaData + $$(eval $$(call ReadSingleImportMetaData, $$m))) + endef + ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ PLATFORM_MODULES += jdk.crypto.kaeprovider ++ endif ++endif ++ ++################################################################################ ++# Filter out kae specific modules if kae is disabled or cpu is not aarch64 ++ ++ifneq ($(ENABLE_KAE)-$(OPENJDK_TARGET_CPU_ARCH), true-aarch64) ++ MODULES_FILTER += jdk.crypto.kaeprovider ++endif ++ + ################################################################################ + + endif # _MODULES_GMK +diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf +index 2c95b8570..881a68d5a 100644 +--- a/make/conf/module-loader-map.conf ++++ b/make/conf/module-loader-map.conf +@@ -77,6 +77,7 @@ PLATFORM_MODULES= \ + jdk.accessibility \ + jdk.charsets \ + jdk.crypto.cryptoki \ ++ jdk.crypto.kaeprovide \ + jdk.crypto.ec \ + jdk.dynalink \ + jdk.httpserver \ +diff --git a/make/ide/netbeans/hotspot/nbproject/configurations.xml b/make/ide/netbeans/hotspot/nbproject/configurations.xml +index 4f64db4ec..29c5e668b 100644 +--- a/make/ide/netbeans/hotspot/nbproject/configurations.xml ++++ b/make/ide/netbeans/hotspot/nbproject/configurations.xml +@@ -3,6 +3,110 @@ + + + ++ ++ ++ ++ ++ kae_cipher_rsa.c ++ kae_digest.c ++ kae_exception.c ++ kae_exception.h ++ kae_hmac.c ++ kae_keyagreement_dh.c ++ kae_keyagreement_ecdh.c ++ kae_keypairgenerator_dh.c ++ kae_keypairgenerator_ec.c ++ kae_keypairgenerator_rsa.c ++ kae_provider.c ++ kae_signature_rsa.c ++ kae_symmetric_cipher.c ++ kae_util.c ++ kae_util.h ++ kae_log.h ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + nopadding in sunjce ++ if (mode == Mode.GCM) { ++ this.padding = Padding.NOPADDING; ++ } else if (paddingStr.equalsIgnoreCase("NOPADDING")) { ++ this.padding = Padding.NOPADDING; ++ } else if(paddingStr.equalsIgnoreCase("PKCS5PADDING")) { ++ if (mode == Mode.CTR) { ++ throw new NoSuchPaddingException("PKCS#5 padding not supported with CTR mode"); ++ } ++ this.padding = Padding.PKCS5PADDING; ++ } else { ++ throw new NoSuchPaddingException("Unsupported padding " + paddingStr); ++ } ++ } ++ ++ protected void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException { ++ if ((ivBytes == null) || (ivBytes.length != blockSize)) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + blockSize + " bytes long."); ++ } ++ } ++} ++ +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java +new file mode 100644 +index 000000000..a4eb57770 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java +@@ -0,0 +1,393 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.Debug; ++ ++import java.io.BufferedInputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.Properties; ++ ++public class KAEConfig { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ ++ // these property names indicates whether each algorithm uses KAEProvider ++ private static final String[] useKaeProviderPropertyNames = new String[]{ ++ "kae.md5", ++ "kae.sha256", ++ "kae.sha384", ++ "kae.sm3", ++ "kae.aes", ++ "kae.sm4", ++ "kae.hmac", ++ "kae.rsa", ++ "kae.dh", ++ "kae.ec" ++ }; ++ ++ // these property names indicate whether KAE hardware acceleration is enabled for each algorithm ++ private static final String[] useKaeEnginePropertyNames = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ // algorithm names ++ private static final String[] algorithmNames = new String[]{ ++ "md5", ++ "sha256", ++ "sha384", ++ "sm3", ++ "aes-128-ecb", ++ "aes-128-cbc", ++ "aes-128-ctr", ++ "aes-128-gcm", ++ "aes-192-ecb", ++ "aes-192-cbc", ++ "aes-192-ctr", ++ "aes-192-gcm", ++ "aes-256-ecb", ++ "aes-256-cbc", ++ "aes-256-ctr", ++ "aes-256-gcm", ++ "sm4-ecb", ++ "sm4-cbc", ++ "sm4-ctr", ++ "sm4-ofb", ++ "hmac-md5", ++ "hmac-sha1", ++ "hmac-sha224", ++ "hmac-sha256", ++ "hmac-sha384", ++ "hmac-sha512", ++ "rsa", ++ "dh", ++ "ec" ++ }; ++ ++ // algorithm name and algorithm index mapping ++ private static final Map algorithmNameIndexMap = new HashMap<>(); ++ ++ // algorithm name and algorithm category index mapping ++ private static final Map algorithmNameCategoryMap = new HashMap<>(); ++ ++ // whether use KAEProvider for each algorithm ++ private static final boolean[] useKaeProviderFlags = new boolean[algorithmNames.length]; ++ ++ // whether use KAEProvider for each category algorithm ++ private static final Map useKaeProviderCategoryMap = new HashMap<>(); ++ ++ // whether enable the Kunpeng acceleration engine for each algorithm ++ private static final boolean[] useKaeEngineFlags = new boolean[algorithmNames.length]; ++ ++ // The kaeprovider.cnf properties ++ private static Properties props; ++ ++ private KAEConfig() { ++ ++ } ++ ++ static { ++ kaeConfigInit(); ++ } ++ ++ @SuppressWarnings("removal") ++ private static void kaeConfigInit() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ initialize(); ++ return null; ++ } ++ }); ++ } ++ ++ private static File kaePropFile(String filename) { ++ String sep = File.separator; ++ String defaultKaeConf = System.getProperty("java.home") + sep + "conf" + sep + filename; ++ String kaeConf = System.getProperty("kae.conf", defaultKaeConf); ++ return new File(kaeConf); ++ } ++ ++ private static void initialize() { ++ initProperties(); ++ initAlgorithmNameMap(); ++ initUseKaeProviderFlags(); ++ initUseKaeEngineFlags(); ++ } ++ ++ private static void initProperties() { ++ props = new Properties(); ++ File propFile = kaePropFile("kaeprovider.conf"); ++ if (propFile.exists()) { ++ InputStream is = null; ++ try { ++ FileInputStream fis = new FileInputStream(propFile); ++ is = new BufferedInputStream(fis); ++ props.load(is); ++ ++ if (kaeDebug != null) { ++ kaeDebug.println("reading kae properties file: " + ++ propFile); ++ } ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to load kae properties from " + ++ propFile); ++ e.printStackTrace(); ++ } ++ } finally { ++ if (is != null) { ++ try { ++ is.close(); ++ } catch (IOException ioe) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to close input stream"); ++ } ++ } ++ } ++ } ++ } else { ++ if (kaeDebug != null) { ++ kaeDebug.println("not found kae properties file: " + ++ propFile); ++ } ++ } ++ } ++ ++ public static Boolean useKaeProvider(String key) { ++ return useKaeProviderCategoryMap.getOrDefault(key, Boolean.TRUE); ++ } ++ ++ private static void initUseKaeProviderFlags() { ++ boolean[] categoryFlagsForProvider = new boolean[useKaeProviderPropertyNames.length]; ++ Arrays.fill(categoryFlagsForProvider, true); ++ for (int i = 0; i < useKaeProviderPropertyNames.length; i++) { ++ String configValue = privilegedGetOverridable(useKaeProviderPropertyNames[i]); ++ if (configValue != null) { ++ categoryFlagsForProvider[i] = Boolean.parseBoolean(configValue); ++ } ++ useKaeProviderCategoryMap.put(useKaeProviderPropertyNames[i], categoryFlagsForProvider[i]); ++ } ++ int offset = useKaeProviderPropertyNames.length - useKaeEnginePropertyNames.length; ++ int digestAlgorithmLen = offset + 1; ++ // digest ++ System.arraycopy(categoryFlagsForProvider, 0, useKaeProviderFlags, 0, digestAlgorithmLen); ++ ++ // non-digest ++ for (int i = digestAlgorithmLen; i < useKaeProviderFlags.length; i++) { ++ Integer algorithmCategoryIndex = algorithmNameCategoryMap.get(algorithmNames[i]); ++ if (categoryFlagsForProvider[algorithmCategoryIndex + offset]) { ++ useKaeProviderFlags[i] = true; ++ } ++ } ++ ++ if (kaeDebug != null) { ++ kaeDebug.println("useKaeProviderPropertyNames: "); ++ for (int i = 0; i < categoryFlagsForProvider.length; i++) { ++ kaeDebug.println(useKaeProviderPropertyNames[i] + "=" + categoryFlagsForProvider[i]); ++ } ++ ++ kaeDebug.println("useKaeProviderFlags: "); ++ for (int i = 0; i < useKaeProviderFlags.length; i++) { ++ kaeDebug.println(algorithmNames[i] + "=" + useKaeProviderFlags[i]); ++ } ++ } ++ } ++ ++ public static boolean[] getUseKaeProviderFlags() { ++ return useKaeProviderFlags; ++ } ++ ++ private static void initUseKaeEngineFlags() { ++ boolean[] categoryFlagsForEngine = new boolean[]{ ++ true, // digest ++ false, // aes ++ true, // sm4 ++ false, // hmac ++ true, // rsa ++ true, // dh ++ false // ec ++ }; ++ for (int i = 0; i < useKaeEnginePropertyNames.length; i++) { ++ String configValue = privilegedGetOverridable(useKaeEnginePropertyNames[i]); ++ if (configValue != null) { ++ categoryFlagsForEngine[i] = Boolean.parseBoolean(configValue); ++ } ++ } ++ ++ // EC algorithm currently does not support KAE hardware acceleration, temporarily use openssl soft calculation. ++ categoryFlagsForEngine[useKaeEnginePropertyNames.length - 1] = false; ++ ++ for (int i = 0; i < useKaeEngineFlags.length; i++) { ++ Integer algorithmCategoryIndex = algorithmNameCategoryMap.get(algorithmNames[i]); ++ if (categoryFlagsForEngine[algorithmCategoryIndex]) { ++ useKaeEngineFlags[i] = true; ++ } ++ } ++ ++ String[] disabledAlgorithms = getDisabledAlgorithms(); ++ for (String disabledAlgorithm : disabledAlgorithms) { ++ Integer algorithmIndex = algorithmNameIndexMap.get(disabledAlgorithm); ++ if (algorithmIndex != null) { ++ useKaeEngineFlags[algorithmIndex] = false; ++ } ++ } ++ if (kaeDebug != null) { ++ kaeDebug.println("useKaeEnginePropertyNames: "); ++ for (int i = 0; i < categoryFlagsForEngine.length; i++) { ++ kaeDebug.println(useKaeEnginePropertyNames[i] + "=" + categoryFlagsForEngine[i]); ++ } ++ ++ kaeDebug.println("disabledAlgorithms: "); ++ for (int i = 0; i < disabledAlgorithms.length; i++) { ++ kaeDebug.println(disabledAlgorithms[i]); ++ } ++ ++ kaeDebug.println("useKaeEngineFlags: "); ++ for (int i = 0; i < useKaeEngineFlags.length; i++) { ++ kaeDebug.println(algorithmNames[i] + "=" + useKaeEngineFlags[i]); ++ } ++ } ++ } ++ ++ public static boolean[] getUseKaeEngineFlags() { ++ return useKaeEngineFlags; ++ } ++ ++ private static void initAlgorithmNameIndexMap() { ++ for (int i = 0; i < algorithmNames.length; i++) { ++ algorithmNameIndexMap.put(algorithmNames[i], i); ++ } ++ } ++ ++ /* ++ * 0 : digest ++ * 1 : aes ++ * 2 : sm4 ++ * 3 : hmac ++ * 4 : rsa ++ * 5 : dh ++ * 6 : ec ++ */ ++ private static void initAlgorithmNameCategoryMap() { ++ algorithmNameCategoryMap.put("md5", 0); ++ algorithmNameCategoryMap.put("sha256", 0); ++ algorithmNameCategoryMap.put("sha384", 0); ++ algorithmNameCategoryMap.put("sm3", 0); ++ algorithmNameCategoryMap.put("aes-128-ecb", 1); ++ algorithmNameCategoryMap.put("aes-128-cbc", 1); ++ algorithmNameCategoryMap.put("aes-128-ctr", 1); ++ algorithmNameCategoryMap.put("aes-128-gcm", 1); ++ algorithmNameCategoryMap.put("aes-192-ecb", 1); ++ algorithmNameCategoryMap.put("aes-192-cbc", 1); ++ algorithmNameCategoryMap.put("aes-192-ctr", 1); ++ algorithmNameCategoryMap.put("aes-192-gcm", 1); ++ algorithmNameCategoryMap.put("aes-256-ecb", 1); ++ algorithmNameCategoryMap.put("aes-256-cbc", 1); ++ algorithmNameCategoryMap.put("aes-256-ctr", 1); ++ algorithmNameCategoryMap.put("aes-256-gcm", 1); ++ algorithmNameCategoryMap.put("sm4-ecb", 2); ++ algorithmNameCategoryMap.put("sm4-cbc", 2); ++ algorithmNameCategoryMap.put("sm4-ctr", 2); ++ algorithmNameCategoryMap.put("sm4-ofb", 2); ++ algorithmNameCategoryMap.put("hmac-md5", 3); ++ algorithmNameCategoryMap.put("hmac-sha1", 3); ++ algorithmNameCategoryMap.put("hmac-sha224", 3); ++ algorithmNameCategoryMap.put("hmac-sha256", 3); ++ algorithmNameCategoryMap.put("hmac-sha384", 3); ++ algorithmNameCategoryMap.put("hmac-sha512", 3); ++ algorithmNameCategoryMap.put("rsa", 4); ++ algorithmNameCategoryMap.put("dh", 5); ++ algorithmNameCategoryMap.put("ec", 6); ++ } ++ ++ private static void initAlgorithmNameMap() { ++ initAlgorithmNameIndexMap(); ++ initAlgorithmNameCategoryMap(); ++ } ++ ++ private static String[] getDisabledAlgorithms() { ++ String disabledAlgorithms = privilegedGetOverridable("kae.engine.disabledAlgorithms", ++ "sha256,sha384"); ++ return disabledAlgorithms.replaceAll(" ", "").split("\\,"); ++ } ++ ++ @SuppressWarnings("removal") ++ public static String privilegedGetProperty(String key) { ++ if (System.getSecurityManager() == null) { ++ return getProperty(key); ++ } else { ++ return AccessController.doPrivileged((PrivilegedAction) () -> getOverridableProperty(key)); ++ } ++ } ++ ++ @SuppressWarnings("removal") ++ public static String privilegedGetOverridable(String key) { ++ if (System.getSecurityManager() == null) { ++ return getOverridableProperty(key); ++ } else { ++ return AccessController.doPrivileged((PrivilegedAction) () -> getOverridableProperty(key)); ++ } ++ } ++ ++ public static String privilegedGetOverridable(String key, String defaultValue) { ++ String val = privilegedGetOverridable(key); ++ return (val == null) ? defaultValue : val; ++ } ++ ++ private static String getProperty(String key) { ++ String val = props.getProperty(key); ++ if (val != null) ++ val = val.trim(); ++ return val; ++ } ++ ++ private static String getOverridableProperty(String key) { ++ String val = System.getProperty(key); ++ if (val == null) { ++ return getProperty(key); ++ } else { ++ return val; ++ } ++ } ++ ++ public static String getAlgorithmName(int index) { ++ if (index < 0 || index >= algorithmNames.length) { ++ throw new IndexOutOfBoundsException(); ++ } ++ return algorithmNames[index]; ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java +new file mode 100644 +index 000000000..541df07d6 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java +@@ -0,0 +1,289 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.KeyUtil; ++import java.math.BigInteger; ++import java.security.KeyFactory; ++import java.security.InvalidKeyException; ++import java.security.SecureRandom; ++import java.security.Key; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.AccessController; ++import java.security.ProviderException; ++import java.security.PrivilegedAction; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.KeyAgreementSpi; ++import javax.crypto.SecretKey; ++import javax.crypto.ShortBufferException; ++import javax.crypto.interfaces.DHPrivateKey; ++import javax.crypto.interfaces.DHPublicKey; ++import javax.crypto.spec.DHParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++import javax.crypto.spec.DHPublicKeySpec; ++import javax.crypto.SecretKeyFactory; ++import javax.crypto.spec.DESedeKeySpec; ++import javax.crypto.spec.DESKeySpec; ++ ++public class KAEDHKeyAgreement extends KeyAgreementSpi { ++ private boolean generateSecret = false; ++ private BigInteger p; ++ private BigInteger g; ++ private BigInteger x; ++ private BigInteger y; ++ static final int[] AES_KEYSIZES = {16, 24, 32}; ++ static final int BLOWFISH_MAX_KEYSIZE = 56; ++ ++ private static class AllowKDF { ++ private static final boolean VALUE = getValue(); ++ ++ @SuppressWarnings("removal") ++ private static boolean getValue() { ++ return AccessController.doPrivileged( ++ (PrivilegedAction) ++ () -> Boolean.getBoolean("jdk.crypto.KeyAgreement.legacyKDF")); ++ } ++ } ++ ++ public KAEDHKeyAgreement() { ++ } ++ ++ @Override ++ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { ++ try { ++ engineInit(key, null, random); ++ } catch (InvalidAlgorithmParameterException e) { ++ // never happens, because we did not pass any parameters ++ } ++ } ++ ++ @Override ++ protected void engineInit(Key key, AlgorithmParameterSpec params, ++ SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ ++ // ignore "random" parameter, because our implementation does not ++ // require any source of randomness ++ generateSecret = false; ++ p = null; ++ g = null; ++ ++ if ((params != null) && !(params instanceof DHParameterSpec)) { ++ throw new InvalidAlgorithmParameterException("Diffie-Hellman parameters expected"); ++ } ++ ++ if (!(key instanceof DHPrivateKey)) { ++ throw new InvalidKeyException("Diffie-Hellman private key expected"); ++ } ++ ++ DHPrivateKey privateKey = (DHPrivateKey) key; ++ ++ // check if private key parameters are compatible with ++ // initialized ones ++ if (params != null) { ++ p = ((DHParameterSpec) params).getP(); ++ g = ((DHParameterSpec) params).getG(); ++ } ++ ++ BigInteger priv_p = privateKey.getParams().getP(); ++ BigInteger priv_g = privateKey.getParams().getG(); ++ if (p != null && priv_p != null && !(p.equals(priv_p))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ if (g != null && priv_g != null && !(g.equals(priv_g))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ if ((p == null && priv_p == null) || ++ (g == null) && priv_g == null) { ++ throw new InvalidKeyException("Missing parameters"); ++ } ++ p = priv_p; ++ g = priv_g; ++ ++ // store the x value ++ x = privateKey.getX(); ++ } ++ ++ @Override ++ protected Key engineDoPhase(Key key, boolean lastPhase) ++ throws InvalidKeyException, IllegalStateException { ++ if (!(key instanceof DHPublicKey)) { ++ throw new InvalidKeyException("Diffie-Hellman public " ++ + "expected"); ++ } ++ DHPublicKey publicKey = (DHPublicKey) key; ++ if (p == null || g == null) { ++ throw new IllegalStateException("Not initialized"); ++ } ++ BigInteger pub_p = publicKey.getParams().getP(); ++ BigInteger pub_g = publicKey.getParams().getG(); ++ if (pub_p != null && !(p.equals(pub_p))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ if (pub_g != null && !(g.equals(pub_g))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ KeyUtil.validate(publicKey); ++ y = publicKey.getY(); ++ generateSecret = true; ++ if (lastPhase == false) { ++ byte[] intermediate = engineGenerateSecret(); ++ try { ++ KeyFactory fk = KeyFactory.getInstance("DH"); ++ DHPublicKey newPublicKey = (DHPublicKey) fk.generatePublic( ++ new DHPublicKeySpec(new BigInteger(1, intermediate), p, g)); ++ return newPublicKey; ++ } catch (NoSuchAlgorithmException noalg) { ++ throw new ProviderException(noalg); ++ } catch (InvalidKeySpecException ikse) { ++ throw new ProviderException(ikse); ++ } ++ } else { ++ return null; ++ } ++ } ++ ++ @Override ++ protected byte[] engineGenerateSecret() ++ throws IllegalStateException { ++ int expectedLen = (p.bitLength() + 7) >>> 3; ++ byte[] result = new byte[expectedLen]; ++ try { ++ engineGenerateSecret(result, 0); ++ } catch (ShortBufferException shortBufferException) { ++ // should never happen since length are identical ++ } ++ return result; ++ } ++ ++ @Override ++ protected int engineGenerateSecret(byte[] sharedSecret, int offset) ++ throws IllegalStateException, ShortBufferException { ++ if (!generateSecret) { ++ throw new IllegalStateException("Key agreement has not bee complated yet"); ++ } ++ if (sharedSecret == null) { ++ throw new ShortBufferException("No buffer provided for shared secret"); ++ } ++ BigInteger modulus = p; ++ int expectedLen = (modulus.bitLength() + 7) >>> 3; ++ if ((sharedSecret.length - offset) < expectedLen) { ++ throw new ShortBufferException("Buffer too short for shared secret"); ++ } ++ generateSecret = false; ++ byte[] secret = nativeComputeKey(y.toByteArray(), x.toByteArray(), ++ p.toByteArray(), g.toByteArray(), modulus.bitLength()); ++ ++ if (secret.length == expectedLen) { ++ System.arraycopy(secret, 0, sharedSecret, offset, ++ secret.length); ++ } else { ++ // Array too short, pad it w/ leading 0s ++ if (secret.length < expectedLen) { ++ System.arraycopy(secret, 0, sharedSecret, ++ offset + (expectedLen - secret.length), ++ secret.length); ++ } else { ++ // Array too long, check and trim off the excess ++ if ((secret.length == (expectedLen + 1)) && secret[0] == 0) { ++ // ignore the leading sign byte ++ System.arraycopy(secret, 1, sharedSecret, offset, expectedLen); ++ } else { ++ throw new ProviderException("Generated secret is out-of-range"); ++ } ++ } ++ } ++ ++ return expectedLen; ++ } ++ ++ @Override ++ protected SecretKey engineGenerateSecret(String algorithm) ++ throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { ++ if (algorithm == null) { ++ throw new NoSuchAlgorithmException("null algorithm"); ++ } ++ ++ if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") && ++ !AllowKDF.VALUE) { ++ ++ throw new NoSuchAlgorithmException("Unsupported secret key " ++ + "algorithm: " + algorithm); ++ } ++ ++ byte[] secret = engineGenerateSecret(); ++ if (algorithm.equalsIgnoreCase("DES")) { ++ // DES ++ try { ++ SecretKeyFactory factory = SecretKeyFactory.getInstance("DES"); ++ return factory.generateSecret(new DESKeySpec(secret)); ++ } catch (InvalidKeySpecException e) { ++ throw new ProviderException("Generate DES Secret failed.", e); ++ } ++ } else if (algorithm.equalsIgnoreCase("DESede") ++ || algorithm.equalsIgnoreCase("TripleDES")) { ++ // Triple DES ++ try { ++ SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); ++ return factory.generateSecret(new DESedeKeySpec(secret)); ++ } catch (InvalidKeySpecException e) { ++ throw new ProviderException("Generate DESede Secret failed.", e); ++ } ++ } else if (algorithm.equalsIgnoreCase("Blowfish")) { ++ // Blowfish ++ int keysize = secret.length; ++ if (keysize >= BLOWFISH_MAX_KEYSIZE) ++ keysize = BLOWFISH_MAX_KEYSIZE; ++ return new SecretKeySpec(secret, 0, keysize, "Blowfish"); ++ } else if (algorithm.equalsIgnoreCase("AES")) { ++ int idx = AES_KEYSIZES.length - 1; ++ int keysize = secret.length; ++ SecretKeySpec secretKey = null; ++ while (secretKey == null && idx >= 0) { ++ if (keysize >= AES_KEYSIZES[idx]) { ++ keysize = AES_KEYSIZES[idx]; ++ secretKey = new SecretKeySpec(secret, 0, keysize, "AES"); ++ } ++ idx--; ++ } ++ if (secretKey == null) { ++ throw new InvalidKeyException("Key material is too short"); ++ } ++ return secretKey; ++ } else if (algorithm.equals("TlsPremasterSecret")) { ++ // remove leading zero bytes per RFC 5246 Section 8.1.2 ++ return new SecretKeySpec( ++ KeyUtil.trimZeroes(secret), "TlsPremasterSecret"); ++ } else { ++ throw new NoSuchAlgorithmException("Unsupported secret key " ++ + "algorithm: " + algorithm); ++ } ++ } ++ protected native byte[] nativeComputeKey(byte[] y, byte[] x, byte[] p, byte[] g, int pSize); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java +new file mode 100644 +index 000000000..74134eef5 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.math.BigInteger; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.KeyPairGeneratorSpi; ++import java.security.SecureRandom; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.KeyPair; ++import java.security.NoSuchAlgorithmException; ++import java.security.InvalidParameterException; ++import java.security.GeneralSecurityException; ++import java.security.ProviderException; ++import java.security.KeyFactory; ++import java.security.spec.InvalidKeySpecException; ++import sun.security.jca.JCAUtil; ++import sun.security.provider.ParameterCache; ++import javax.crypto.spec.DHPublicKeySpec; ++import javax.crypto.spec.DHPrivateKeySpec; ++import javax.crypto.spec.DHParameterSpec; ++import javax.crypto.interfaces.DHPublicKey; ++import javax.crypto.interfaces.DHPrivateKey; ++ ++import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE; ++ ++public class KAEDHKeyPairGenerator ++ extends KeyPairGeneratorSpi { ++ private DHParameterSpec parameterSpec; ++ // The size in bits of the random exponent (private value) ++ private int pSize; ++ // The size in bits of the random exponent (private value) ++ private int lSize; ++ private SecureRandom random; ++ ++ @SuppressWarnings("this-escape") ++ public KAEDHKeyPairGenerator() { ++ super(); ++ initialize(DEF_DH_KEY_SIZE, null); ++ } ++ ++ private static void checkKeySize(int keySize) { ++ if ((keySize < 512) || (keySize > 8192) || ((keySize & 0x3F) != 0)) { ++ throw new InvalidParameterException( ++ "DH key size must be multiple of 64, and can only range " + ++ "from 512 to 8192(inclusize). " + ++ "The specific key size " + keySize + " is not supported"); ++ } ++ } ++ @Override ++ public void initialize(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ ++ if (!(params instanceof DHParameterSpec)){ ++ throw new InvalidAlgorithmParameterException ++ ("Inappropriate parameter type"); ++ } ++ ++ parameterSpec = (DHParameterSpec) params; ++ pSize = parameterSpec.getP().bitLength(); ++ ++ try { ++ checkKeySize(pSize); ++ } catch (InvalidParameterException e) { ++ throw new InvalidAlgorithmParameterException(e.getMessage()); ++ } ++ ++ // exponent size is optional, could be 0 ++ lSize = parameterSpec.getL(); ++ ++ // Require exponentSize < primeSize ++ if ((lSize != 0) && (lSize > pSize)) { ++ throw new InvalidAlgorithmParameterException ++ ("Exponent size must not be larger than modulus size"); ++ } ++ ++ this.random = random; ++ } ++ ++ @Override ++ public void initialize(int keysize, SecureRandom random) { ++ checkKeySize(keysize); ++ this.parameterSpec = ParameterCache.getCachedDHParameterSpec(keysize); ++ if ((this.parameterSpec == null) && (keysize > 1024)) { ++ throw new InvalidParameterException("Unsupported " + keysize + "-bit DH parameter generation."); ++ } ++ this.pSize = keysize; ++ this.lSize = 0; ++ this.random = random; ++ } ++ ++ @Override ++ public KeyPair generateKeyPair() { ++ ++ if (random == null) { ++ random = JCAUtil.getSecureRandom(); ++ } ++ ++ if (parameterSpec == null) { ++ try { ++ parameterSpec = ParameterCache.getDHParameterSpec(pSize, random); ++ } catch (GeneralSecurityException e) { ++ // should never happen ++ throw new ProviderException(e); ++ } ++ } ++ ++ BigInteger p = parameterSpec.getP(); ++ BigInteger g = parameterSpec.getG(); ++ ++ if (lSize <= 0) { ++ lSize = pSize >> 1; ++ // use an exponent size of (pSize / 2) but at least 384 bits ++ if (lSize < 384) { ++ lSize = 384; ++ } ++ } ++ byte[][] keys; ++ try { ++ keys = nativeGenerateKeyPair(p.toByteArray(), g.toByteArray(), lSize); ++ } catch (Exception e){ ++ throw new ProviderException("Invoke nativeGenerateKeyPair failed.", e); ++ } ++ ++ // check keys ++ checkKeys(keys); ++ ++ BigInteger pubKey = new BigInteger(keys[0]); ++ BigInteger priKey = new BigInteger(keys[1]); ++ ++ try{ ++ KeyFactory fk = KeyFactory.getInstance("DH"); ++ DHPublicKey publicKey = (DHPublicKey)fk.generatePublic(new DHPublicKeySpec(pubKey, p , g)); ++ DHPrivateKey privateKey = (DHPrivateKey)fk.generatePrivate(new DHPrivateKeySpec(priKey, p, g)); ++ return new KeyPair(publicKey, privateKey); ++ } catch (NoSuchAlgorithmException noalg) { ++ throw new ProviderException(noalg); ++ } catch (InvalidKeySpecException ikse) { ++ throw new ProviderException(ikse); ++ } ++ } ++ ++ private void checkKeys(byte[][] keys) { ++ if (keys == null) { ++ throw new ProviderException("Invalid keys, keys is null."); ++ } ++ // The keys needs to contain at least 2 byte arrays, which are public and private keys. ++ if (keys.length < 2) { ++ throw new ProviderException("Invalid keys, keys length is less than 2."); ++ } ++ for (int i = 0; i < keys.length; i++) { ++ if (keys[i] == null) { ++ throw new ProviderException("Invalid keys, keys[" + i + "]" + "is null."); ++ } ++ } ++ } ++ ++ protected native static byte[][] nativeGenerateKeyPair(byte[] p, byte[] g, int lSize); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java +new file mode 100644 +index 000000000..aca5f4b29 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java +@@ -0,0 +1,264 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.DigestException; ++import java.security.MessageDigestSpi; ++import java.security.ProviderException; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++/** ++ * KAE Digest ++ */ ++abstract class KAEDigest extends MessageDigestSpi implements Cloneable { ++ ++ public static final class MD5 extends KAEDigest { ++ private static final long initContext = nativeInit("md5"); ++ ++ public MD5() { ++ super("md5", 16, initContext); ++ } ++ } ++ ++ public static final class SM3 extends KAEDigest { ++ private static final long initContext = nativeInit("sm3"); ++ ++ public SM3() { ++ super("sm3", 32, initContext); ++ } ++ } ++ ++ public static final class SHA256 extends KAEDigest { ++ private static final long initContext = nativeInit("sha256"); ++ ++ public SHA256() { ++ super("sha256", 32, initContext); ++ } ++ } ++ ++ public static final class SHA384 extends KAEDigest { ++ private static final long initContext = nativeInit("sha384"); ++ ++ public SHA384() { ++ super("sha384", 48, initContext); ++ } ++ } ++ ++ private final int digestLength; ++ ++ private final String algorithm; ++ private final long initContext; ++ ++ // field for ensuring native memory is freed ++ private DigestContextRef contextRef = null; ++ ++ KAEDigest(String algorithm, int digestLength, long initContext) { ++ this.algorithm = algorithm; ++ this.digestLength = digestLength; ++ this.initContext = initContext; ++ } ++ ++ private static class DigestContextRef extends PhantomReference ++ implements Comparable { ++ ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ private final long ctxAddress; ++ ++ DigestContextRef(KAEDigest kaeDigest, long ctxAddress) { ++ super(kaeDigest, referenceQueue); ++ this.ctxAddress = ctxAddress; ++ if (!disableKaeDispose) { ++ referenceList.add(this); ++ drainRefQueueBounded(); ++ } ++ } ++ ++ @Override ++ public int compareTo(DigestContextRef other) { ++ if (this.ctxAddress == other.ctxAddress) { ++ return 0; ++ } else { ++ return (this.ctxAddress < other.ctxAddress) ? -1 : 1; ++ } ++ } ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ DigestContextRef next = (DigestContextRef) referenceQueue.poll(); ++ if (next == null) { ++ break; ++ } ++ next.dispose(); ++ } ++ } ++ ++ void dispose() { ++ if (!disableKaeDispose) { ++ referenceList.remove(this); ++ try { ++ nativeFree(ctxAddress); ++ } finally { ++ this.clear(); ++ } ++ } else { ++ nativeFree(ctxAddress); ++ } ++ } ++ } ++ ++ // single byte update. See JCA doc. ++ @Override ++ protected synchronized void engineUpdate(byte input) { ++ byte[] oneByte = new byte[]{input}; ++ engineUpdate(oneByte, 0, 1); ++ } ++ ++ ++ // array update. See JCA doc. ++ @Override ++ protected synchronized void engineUpdate(byte[] input, int offset, int len) { ++ if (len == 0 || input == null) { ++ return; ++ } ++ if ((offset < 0) || (len < 0) || (offset > input.length - len)) { ++ throw new ArrayIndexOutOfBoundsException(); ++ } ++ if (contextRef == null) { ++ contextRef = createDigestContext(this); ++ } ++ ++ try { ++ nativeUpdate(contextRef.ctxAddress, input, offset, len); ++ } catch (Exception e) { ++ engineReset(); ++ throw new ProviderException("nativeUpdate failed for " + algorithm, e); ++ } ++ } ++ ++ ++ // return the digest. See JCA doc. ++ @Override ++ protected synchronized byte[] engineDigest() { ++ final byte[] output = new byte[digestLength]; ++ try { ++ engineDigest(output, 0, digestLength); ++ } catch (Exception e) { ++ throw new ProviderException("Internal error", e); ++ } ++ return output; ++ } ++ ++ // return the digest in the specified array. See JCA doc. ++ @Override ++ protected int engineDigest(byte[] output, int offset, int len) throws DigestException { ++ if (output == null) { ++ return 0; ++ } ++ if (len < digestLength) { ++ throw new DigestException("Length must be at least " ++ + digestLength + " for " + algorithm + " digests"); ++ } ++ if ((offset < 0) || (len < 0) || (offset > output.length - len)) { ++ throw new DigestException("Buffer too short to store digest"); ++ } ++ if (contextRef == null) { ++ contextRef = createDigestContext(this); ++ } ++ try { ++ nativeDigest(contextRef.ctxAddress, output, offset, digestLength); ++ } catch (Exception e) { ++ throw new ProviderException("Invoke nativeDigest failed for " + algorithm, e); ++ } finally { ++ engineReset(); ++ } ++ return digestLength; ++ } ++ ++ // reset this object. See JCA doc. ++ @Override ++ protected synchronized void engineReset() { ++ if (contextRef != null) { ++ contextRef.dispose(); ++ contextRef = null; ++ } ++ } ++ ++ // return digest length. See JCA doc. ++ @Override ++ protected int engineGetDigestLength() { ++ return digestLength; ++ } ++ ++ @Override ++ public synchronized Object clone() throws CloneNotSupportedException { ++ KAEDigest kaeDigest = (KAEDigest) super.clone(); ++ if (kaeDigest.contextRef != null && kaeDigest.contextRef.ctxAddress != 0) { ++ long addr; ++ try { ++ addr = nativeClone(kaeDigest.contextRef.ctxAddress); ++ } catch (Exception e) { ++ throw new ProviderException("Invoke nativeClone failed for " + algorithm, e); ++ } ++ kaeDigest.contextRef = new DigestContextRef(kaeDigest, addr); ++ } ++ return kaeDigest; ++ } ++ ++ private DigestContextRef createDigestContext(KAEDigest kaeDigest) { ++ long addr; ++ try { ++ addr = nativeClone(initContext); ++ } catch (Exception e) { ++ throw new ProviderException("Invoke nativeInit failed for " + algorithm, e); ++ } ++ if (addr == 0) { ++ throw new RuntimeException("Cannot initialize EVP_MD_CTX for " + algorithm); ++ } ++ return new DigestContextRef(kaeDigest, addr); ++ } ++ ++ // return pointer to the context ++ protected native static long nativeInit(String algorithmName); ++ ++ // update the input byte ++ protected native static void nativeUpdate(long ctxAddress, byte[] input, int offset, int inLen); ++ ++ // digest and store the digest message to output ++ protected native static int nativeDigest(long ctxAddress, byte[] output, int offset, int len); ++ ++ // digest clone ++ protected static native long nativeClone(long ctxAddress); ++ ++ // free the specified context ++ protected native static void nativeFree(long ctxAddress); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java +new file mode 100644 +index 000000000..29dc09889 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java +@@ -0,0 +1,146 @@ ++/* ++ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.ec.ECKeyFactory; ++ ++import java.math.BigInteger; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.InvalidKeyException; ++import java.security.Key; ++import java.security.NoSuchAlgorithmException; ++import java.security.PrivateKey; ++import java.security.SecureRandom; ++import java.security.interfaces.ECPrivateKey; ++import java.security.interfaces.ECPublicKey; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.ECParameterSpec; ++import java.security.spec.ECPoint; ++import javax.crypto.KeyAgreementSpi; ++import javax.crypto.SecretKey; ++import javax.crypto.ShortBufferException; ++import javax.crypto.spec.SecretKeySpec; ++ ++public class KAEECDHKeyAgreement extends KeyAgreementSpi { ++ private ECPrivateKey privateKey; ++ private ECPublicKey publicKey; ++ ++ // Length of the secret to be derived. ++ private int expectedSecretLen; ++ private String curveName; ++ ++ @Override ++ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { ++ if (!(key instanceof PrivateKey)) { ++ throw new InvalidKeyException("Key must be instance of PrivateKey"); ++ } ++ privateKey = (ECPrivateKey) ECKeyFactory.toECKey(key); ++ publicKey = null; ++ } ++ ++ @Override ++ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("Parameters not supported"); ++ } ++ engineInit(key, random); ++ } ++ ++ @Override ++ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { ++ if (privateKey == null) { ++ throw new IllegalStateException("Not initialized"); ++ } ++ if (publicKey != null) { ++ throw new IllegalStateException("Phase already executed"); ++ } ++ if (!lastPhase) { ++ throw new IllegalStateException ++ ("Only two party agreement supported, lastPhase must be true"); ++ } ++ if (!(key instanceof ECPublicKey)) { ++ throw new InvalidKeyException ++ ("Key must be a PublicKey with algorithm EC"); ++ } ++ ++ publicKey = (ECPublicKey) key; ++ ECParameterSpec params = publicKey.getParams(); ++ int keyLenBits = params.getCurve().getField().getFieldSize(); ++ // Bits to bytes. ++ expectedSecretLen = (keyLenBits + 7) >> 3; ++ ++ curveName = KAEUtils.getCurveBySize(keyLenBits); ++ if (curveName == null) { ++ throw new InvalidParameterException("unknown keyLenBits " + keyLenBits); ++ } ++ if (KAEUtils.getCurveByAlias(curveName) != null) { ++ curveName = KAEUtils.getCurveByAlias(curveName); ++ } ++ return null; ++ } ++ ++ @Override ++ protected byte[] engineGenerateSecret() throws IllegalStateException { ++ if ((privateKey == null) || (publicKey == null)) { ++ throw new IllegalStateException("Not initialized correctly"); ++ } ++ ECPoint w = publicKey.getW(); ++ BigInteger wX = w.getAffineX(); ++ BigInteger wY = w.getAffineY(); ++ ++ BigInteger s = privateKey.getS(); ++ byte[] secret = nativeGenerateSecret(curveName, wX.toByteArray(), wY.toByteArray(), s.toByteArray()); ++ if (secret == null || secret.length != expectedSecretLen) { ++ throw new RuntimeException("nativeGenerateSecret error. Expected: " + expectedSecretLen + ", actual: " + (secret == null ? "null" : secret.length)); ++ } ++ return secret; ++ } ++ ++ @Override ++ protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { ++ if (offset + expectedSecretLen > sharedSecret.length) { ++ throw new ShortBufferException("Need " + expectedSecretLen + ++ " bytes, only " + (sharedSecret.length - offset) + "available"); ++ } ++ byte[] secret = engineGenerateSecret(); ++ System.arraycopy(secret, 0, sharedSecret, offset, secret.length); ++ return secret.length; ++ } ++ ++ @Override ++ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, ++ NoSuchAlgorithmException, InvalidKeyException { ++ if (algorithm == null) { ++ throw new NoSuchAlgorithmException("Algorithm must not be null"); ++ } ++ return new SecretKeySpec(engineGenerateSecret(), algorithm); ++ } ++ ++ protected static native byte[] nativeGenerateSecret(String curveName, byte[] wX, byte[] wY, byte[] s); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java +new file mode 100644 +index 000000000..73d8551b1 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java +@@ -0,0 +1,151 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.ec.ECPrivateKeyImpl; ++import sun.security.ec.ECPublicKeyImpl; ++ ++import java.math.BigInteger; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.KeyPair; ++import java.security.KeyPairGeneratorSpi; ++import java.security.ProviderException; ++import java.security.SecureRandom; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.ECFieldFp; ++import java.security.spec.ECField; ++import java.security.spec.ECGenParameterSpec; ++import java.security.spec.ECParameterSpec; ++import java.security.spec.ECPoint; ++import java.security.spec.EllipticCurve; ++ ++import java.lang.reflect.Constructor; ++import java.lang.reflect.InvocationTargetException; ++ ++public class KAEECKeyPairGenerator extends KeyPairGeneratorSpi { ++ private ECParameterSpec param = null; ++ private final int defaultKeySize = 256; ++ ++ @Override ++ public void initialize(int keysize, SecureRandom random) { ++ String curveName = KAEUtils.getCurveBySize(keysize); ++ if (curveName == null) { ++ throw new InvalidParameterException("unknown key size " + keysize); ++ } ++ if (KAEUtils.getCurveByAlias(curveName) != null) { ++ curveName = KAEUtils.getCurveByAlias(curveName); ++ } ++ this.param = getParamsByCurve(curveName); ++ } ++ ++ private ECParameterSpec getParamsByCurve(String curveName) { ++ byte[][] params = nativeGenerateParam(curveName); ++ if (params == null) { ++ throw new InvalidParameterException("unknown curve " + curveName); ++ } ++ BigInteger p = new BigInteger(params[0]); ++ BigInteger a = new BigInteger(params[1]); ++ BigInteger b = new BigInteger(params[2]); ++ BigInteger x = new BigInteger(params[3]); ++ BigInteger y = new BigInteger(params[4]); ++ BigInteger order = new BigInteger(params[5]); ++ BigInteger cofactor = new BigInteger(params[6]); ++ ECField field = new ECFieldFp(p); ++ EllipticCurve curve = new EllipticCurve(field, a, b); ++ ECPoint g = new ECPoint(x, y); ++ ECParameterSpec spec = new ECParameterSpec(curve, g, order, cofactor.intValue()); ++ return spec; ++ } ++ ++ @Override ++ public void initialize(AlgorithmParameterSpec param, SecureRandom random) throws InvalidAlgorithmParameterException { ++ if (param instanceof ECParameterSpec) { ++ this.param = (ECParameterSpec) param; ++ } else if (param instanceof ECGenParameterSpec) { ++ ECGenParameterSpec ecParam = (ECGenParameterSpec)param; ++ String curveName = ecParam.getName(); ++ if (KAEUtils.getCurveByAlias(curveName) != null) { ++ curveName = KAEUtils.getCurveByAlias(curveName); ++ } ++ this.param = getParamsByCurve(curveName); ++ } else { ++ throw new InvalidAlgorithmParameterException("ECParameterSpec or ECGenParameterSpec for EC"); ++ } ++ } ++ ++ @Override ++ public KeyPair generateKeyPair() { ++ if (param == null) { ++ String curveName = KAEUtils.getCurveBySize(defaultKeySize); ++ param = getParamsByCurve(curveName); ++ } ++ EllipticCurve curve = param.getCurve(); ++ ECFieldFp field = (ECFieldFp) curve.getField(); ++ BigInteger p = field.getP(); ++ BigInteger a = curve.getA(); ++ BigInteger b = curve.getB(); ++ ECPoint generator = param.getGenerator(); ++ BigInteger x = generator.getAffineX(); ++ BigInteger y = generator.getAffineY(); ++ BigInteger order = param.getOrder(); ++ int cofactor = param.getCofactor(); ++ ++ byte[][] keys = nativeGenerateKeyPair(p.toByteArray(), a.toByteArray(), ++ b.toByteArray(), x.toByteArray(), y.toByteArray(), order.toByteArray(), cofactor); ++ if (keys == null) { ++ throw new RuntimeException("nativeGenerateKeyPair failed"); ++ } ++ BigInteger wX = new BigInteger(keys[0]); ++ BigInteger wY = new BigInteger(keys[1]); ++ BigInteger s = new BigInteger(keys[2]); ++ ECPoint w = new ECPoint(wX, wY); ++ ++ ECPrivateKeyImpl privateKey = null; ++ ECPublicKeyImpl publicKey = null; ++ try { ++ Class pubKeyImpl = Class.forName("sun.security.ec.ECPublicKeyImpl"); ++ Constructor conPubKeyImpl = pubKeyImpl.getDeclaredConstructor(ECPoint.class, ECParameterSpec.class); ++ conPubKeyImpl.setAccessible(true); ++ publicKey = (ECPublicKeyImpl) conPubKeyImpl.newInstance(w, param); ++ ++ Class priKeyImpl = Class.forName("sun.security.ec.ECPrivateKeyImpl"); ++ Constructor conPriKeyImpl = priKeyImpl.getDeclaredConstructor(BigInteger.class, ECParameterSpec.class); ++ conPriKeyImpl.setAccessible(true); ++ privateKey = (ECPrivateKeyImpl) conPriKeyImpl.newInstance(s, param); ++ } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | ++ IllegalAccessException | InvocationTargetException e) { ++ throw new ProviderException(e); ++ } ++ return new KeyPair(publicKey, privateKey); ++ } ++ ++ protected static native byte[][] nativeGenerateParam(String curveName); ++ ++ protected static native byte[][] nativeGenerateKeyPair(byte[] p, byte[] a, byte[] b, byte[] x, byte[] y, ++ byte[] order, int cofactor); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java +new file mode 100644 +index 000000000..3ca909aa1 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java +@@ -0,0 +1,227 @@ ++/* ++ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.MacSpi; ++import javax.crypto.SecretKey; ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++public abstract class KAEHMac extends MacSpi { ++ ++ private final String algorithm; ++ ++ /** ++ * The secret key used in this keyed HMAC. ++ */ ++ private byte[] keyBytes; ++ ++ /** ++ * Holds the output size of the message digest. ++ */ ++ private final int digestSize; ++ ++ /** ++ * Holds a dummy buffer for writing single bytes to the digest. ++ */ ++ private final byte[] singleByte = new byte[1]; ++ ++ private HmacContextRef contextRef = null; ++ ++ private KAEHMac(String algo, int size) { ++ this.algorithm = algo; ++ this.digestSize = size; ++ } ++ ++ private static class HmacContextRef extends PhantomReference ++ implements Comparable { ++ ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ private final long address; ++ ++ HmacContextRef(KAEHMac kaeHMac, long address) { ++ super(kaeHMac, referenceQueue); ++ this.address = address; ++ if (!disableKaeDispose) { ++ referenceList.add(this); ++ drainRefQueueBounded(); ++ } ++ } ++ ++ @Override ++ public int compareTo(HmacContextRef other) { ++ if (this.address == other.address) { ++ return 0; ++ } else { ++ return (this.address < other.address) ? -1 : 1; ++ } ++ } ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ HmacContextRef next = (HmacContextRef) referenceQueue.poll(); ++ if (next == null) break; ++ next.dispose(true); ++ } ++ } ++ ++ void dispose(boolean needFree) { ++ if (!disableKaeDispose) { ++ referenceList.remove(this); ++ try { ++ if (needFree) { ++ nativeFree(address); ++ } ++ } finally { ++ this.clear(); ++ } ++ } else { ++ nativeFree(address); ++ } ++ } ++ } ++ ++ private void checkAndInitHmacContext () { ++ try { ++ if (contextRef == null) { ++ long ctxAddr = nativeInit(keyBytes, keyBytes.length, algorithm); ++ contextRef = new HmacContextRef(this, ctxAddr); ++ } ++ } ++ catch (Exception e) { ++ throw new ProviderException(e.getMessage()) ; ++ } ++ } ++ ++ @Override ++ protected int engineGetMacLength() { ++ return digestSize; ++ } ++ ++ @Override ++ protected void engineInit(Key key, AlgorithmParameterSpec params) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ if (!(key instanceof SecretKey)) { ++ throw new InvalidKeyException("key must be a SecretKey"); ++ } ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("unknown parameter type"); ++ } ++ keyBytes = key.getEncoded(); ++ if (keyBytes == null) { ++ throw new InvalidKeyException("key cannot be encoded"); ++ } ++ } ++ ++ @Override ++ protected void engineUpdate(byte input) { ++ singleByte[0] = input; ++ engineUpdate(singleByte, 0, 1); ++ } ++ ++ @Override ++ protected void engineUpdate(byte[] input, int offset, int len) { ++ checkAndInitHmacContext(); ++ try { ++ nativeUpdate(contextRef.address, input, offset, len); ++ } ++ catch (Exception e) { ++ engineReset(); ++ throw new ProviderException(e.getMessage()); ++ } ++ } ++ ++ ++ @Override ++ protected byte[] engineDoFinal() { ++ final byte[] output = new byte[digestSize]; ++ checkAndInitHmacContext(); ++ final byte[] res; ++ try { ++ int bytesWritten = nativeFinal(contextRef.address, output, 0, digestSize); ++ res = new byte[bytesWritten]; ++ System.arraycopy(output, 0, res, 0, bytesWritten); ++ } ++ catch (Exception e) { ++ engineReset(); ++ throw new ProviderException(e.getMessage()); ++ } ++ return res; ++ } ++ ++ @Override ++ protected void engineReset() { ++ if (contextRef != null) { ++ contextRef.dispose(true); ++ contextRef = null; ++ } ++ } ++ ++ public static final class HmacMD5 extends KAEHMac { ++ public HmacMD5() { ++ super("MD5", 16); ++ } ++ } ++ public static final class HmacSHA1 extends KAEHMac { ++ public HmacSHA1() { ++ super("SHA1", 20); ++ } ++ } ++ public static final class HmacSHA224 extends KAEHMac { ++ public HmacSHA224() throws NoSuchAlgorithmException { ++ super("SHA224", 28); ++ } ++ } ++ public static final class HmacSHA256 extends KAEHMac { ++ public HmacSHA256() throws NoSuchAlgorithmException { ++ super("SHA256", 32); ++ } ++ } ++ public static final class HmacSHA384 extends KAEHMac { ++ public HmacSHA384() throws NoSuchAlgorithmException { ++ super("SHA384", 48); ++ } ++ } ++ public static final class HmacSHA512 extends KAEHMac { ++ public HmacSHA512() throws NoSuchAlgorithmException { ++ super("SHA512", 64); ++ } ++ } ++ ++ protected static native long nativeInit(byte[] key, int len, String algo); ++ ++ protected static native void nativeUpdate(long ctxAddr, byte[] input, int inOffset, int inLen); ++ ++ protected static native int nativeFinal(long ctxAddr, byte[] output, int outOffset, int inLen); ++ ++ protected static native void nativeFree(long ctxAddr); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java +new file mode 100644 +index 000000000..33c1c430f +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java +@@ -0,0 +1,188 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.Debug; ++ ++import java.io.BufferedWriter; ++import java.io.File; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.StandardOpenOption; ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.text.SimpleDateFormat; ++import java.util.Arrays; ++import java.util.Date; ++ ++public class KAELog { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ private static File logFile; ++ private static boolean exist; ++ ++ private KAELog() { ++ ++ } ++ ++ static { ++ kaeLogInit(); ++ } ++ ++ @SuppressWarnings("removal") ++ private static void kaeLogInit() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ initialize(); ++ return null; ++ } ++ }); ++ } ++ ++ private static void initialize() { ++ if (!enableKaeLog()) { ++ if (kaeDebug != null) { ++ kaeDebug.println("kae logging is not enabled"); ++ } ++ return; ++ } ++ ++ logFile = kaeLogFile("kae.log"); ++ File parentFile = logFile.getParentFile(); ++ if (!parentFile.exists()) { ++ try { ++ Files.createDirectories(parentFile.toPath()); ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("failed to create directory :" + parentFile); ++ e.printStackTrace(); ++ } ++ return; ++ } ++ } ++ ++ if (logFile.exists()) { ++ if (kaeDebug != null) { ++ kaeDebug.println("found kae log file :" + logFile); ++ } ++ exist = true; ++ } else { ++ if (kaeDebug != null) { ++ kaeDebug.println("not found kae log file :" + logFile); ++ } ++ try { ++ Path path = Files.createFile(logFile.toPath()); ++ if (path != null) { ++ exist = true; ++ } ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to create new kae log file :" + logFile); ++ e.printStackTrace(); ++ } ++ } ++ ++ if (exist) { ++ if (kaeDebug != null) { ++ kaeDebug.println("create new kae log file :" + logFile); ++ } ++ } ++ } ++ } ++ ++ public static boolean enableKaeLog() { ++ String debug = KAEConfig.privilegedGetOverridable("kae.log"); ++ return Boolean.parseBoolean(debug); ++ } ++ ++ private static File kaeLogFile(String filename) { ++ String sep = File.separator; ++ String defaultKaeLog = System.getProperty("user.dir") + sep + filename; ++ String kaeLog = KAEConfig.privilegedGetOverridable("kae.log.file", defaultKaeLog); ++ return new File(kaeLog); ++ } ++ ++ private static String getLogTime() { ++ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ++ return simpleDateFormat.format(new Date()); ++ } ++ ++ public static void log(String engineId, Throwable throwable, boolean[] engineFlags, boolean[] kaeProviderFlags) { ++ if (engineFlags.length != kaeProviderFlags.length) { ++ if (kaeDebug != null) { ++ kaeDebug.println("The length of engineFlags is not equal to the length of kaeProviderFlags."); ++ kaeDebug.println(String.format("engineFlags : %s", Arrays.toString(engineFlags))); ++ kaeDebug.println(String.format("kaeProviderFlags : %s", Arrays.toString(kaeProviderFlags))); ++ } ++ return; ++ } ++ if (!exist) { ++ return; ++ } ++ ++ try (BufferedWriter writer = Files.newBufferedWriter(logFile.toPath(), ++ StandardOpenOption.APPEND)) { ++ logEngine(writer, engineId, throwable); ++ writer.newLine(); ++ logAlgorithmStrategy(writer, engineFlags, kaeProviderFlags); ++ writer.newLine(); ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("write kae log failed"); ++ e.printStackTrace(); ++ } ++ } ++ } ++ ++ // log engine ++ private static void logEngine(BufferedWriter writer, String engineId, Throwable throwable) throws IOException { ++ writer.write(String.format("[%s] ", getLogTime())); ++ if (throwable == null) { ++ writer.write(String.format("%s engine was found.", engineId)); ++ } else if (throwable instanceof RuntimeException) { ++ writer.write(String.format("%s engine was not found. %s", engineId, throwable.getMessage())); ++ } else { ++ writer.write(throwable.getMessage()); ++ } ++ } ++ ++ // log algorithm strategy ++ private static void logAlgorithmStrategy(BufferedWriter writer, boolean[] engineFlags, boolean[] kaeProviderFlags) ++ throws IOException { ++ writer.write(String.format("[%s] ", getLogTime())); ++ writer.write("The implementation strategy of each algorithm is as follows : "); ++ for (int i = 0; i < engineFlags.length; i++) { ++ writer.newLine(); ++ String algorithmName = KAEConfig.getAlgorithmName(i); ++ String message; ++ if (kaeProviderFlags[i]) { ++ String detail = engineFlags[i] ? "enable KAE hardware acceleration" : "Use openssl soft calculation"; ++ message = String.format(" %-11s => %s: %s", algorithmName, "KAEProvider", detail); ++ } else { ++ message = String.format(" %-11s => %s", algorithmName, "Non-KAEProvider"); ++ } ++ writer.write(message); ++ } ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java +new file mode 100644 +index 000000000..dc79a3f62 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2018, 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++package org.openeuler.security.openssl; ++ ++import java.security.*; ++ ++/** ++ * This class implements the MGF1 mask generation function defined in PKCS#1 ++ * v2.2 B.2.1 (https://tools.ietf.org/html/rfc8017#appendix-B.2.1). A mask ++ * generation function takes an octet string of variable length and a ++ * desired output length as input and outputs an octet string of the ++ * desired length. MGF1 is a mask generation function based on a hash ++ * function, i.e. message digest algorithm. ++ * ++ * @since 11 ++ */ ++final class KAEMGF1 { ++ ++ private final MessageDigest md; ++ ++ /** ++ * Construct an instance of MGF1 based on the specified digest algorithm. ++ */ ++ KAEMGF1(String mdAlgo) throws NoSuchAlgorithmException { ++ this.md = MessageDigest.getInstance(mdAlgo); ++ } ++ ++ /** ++ * Using the specified seed bytes, generate the mask, xor the mask ++ * with the specified output buffer and store the result into the ++ * output buffer (essentially replaced in place). ++ * ++ * @param seed the buffer holding the seed bytes ++ * @param seedOfs the index of the seed bytes ++ * @param seedLen the length of the seed bytes to be used by MGF1 ++ * @param maskLen the intended length of the generated mask ++ * @param out the output buffer holding the mask ++ * @param outOfs the index of the output buffer for the mask ++ */ ++ void generateAndXor(byte[] seed, int seedOfs, int seedLen, int maskLen, ++ byte[] out, int outOfs) throws RuntimeException { ++ byte[] C = new byte[4]; // 32 bit counter ++ byte[] digest = new byte[md.getDigestLength()]; ++ while (maskLen > 0) { ++ md.update(seed, seedOfs, seedLen); ++ md.update(C); ++ try { ++ md.digest(digest, 0, digest.length); ++ } catch (DigestException e) { ++ // should never happen ++ throw new RuntimeException(e.toString()); ++ } ++ for (int i = 0; (i < digest.length) && (maskLen > 0); maskLen--) { ++ out[outOfs++] ^= digest[i++]; ++ } ++ if (maskLen > 0) { ++ // increment counter ++ for (int i = C.length - 1; (++C[i] == 0) && (i > 0); i--) { ++ // empty ++ } ++ } ++ } ++ } ++ ++ /** ++ * Returns the name of this MGF1 instance, i.e. "MGF1" followed by the ++ * digest algorithm it based on. ++ */ ++ String getName() { ++ return "KAEMGF1" + md.getAlgorithm(); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java +new file mode 100644 +index 000000000..b3c1fb022 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java +@@ -0,0 +1,326 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.Debug; ++ ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.security.Provider; ++import static sun.security.util.SecurityConstants.PROVIDER_VER; ++ ++/** ++ * KAE Provider ++ */ ++@SuppressWarnings("serial") ++public class KAEProvider extends Provider { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ ++ // default engine id ++ private static final String DEFAULT_ENGINE_ID = "kae"; ++ ++ static { ++ initialize(); ++ } ++ ++ private static void initialize() { ++ loadLibrary(); ++ initOpenssl(); ++ } ++ ++ // load kae.so ++ @SuppressWarnings("removal") ++ private static void loadLibrary() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Object run() { ++ System.loadLibrary("j2kae"); ++ return null; ++ } ++ }); ++ } ++ ++ // init openssl ++ private static void initOpenssl() { ++ boolean useGlobalMode = useGlobalMode(); ++ String engineId = getEngineId(); ++ boolean[] algorithmKaeFlags = KAEConfig.getUseKaeEngineFlags(); ++ Throwable throwable = null; ++ try { ++ initOpenssl(useGlobalMode, engineId, algorithmKaeFlags); ++ } catch (Throwable t) { ++ throwable = t; ++ if (kaeDebug != null) { ++ kaeDebug.println("initOpenssl failed : " + throwable.getMessage()); ++ } ++ } ++ boolean[] engineFlags = getEngineFlags(); ++ boolean[] kaeProviderFlags = KAEConfig.getUseKaeProviderFlags(); ++ KAELog.log(engineId, throwable, engineFlags, kaeProviderFlags); ++ } ++ ++ // get engine id ++ private static String getEngineId() { ++ return KAEConfig.privilegedGetOverridable("kae.engine.id", DEFAULT_ENGINE_ID); ++ } ++ ++ // whether to set libcrypto.so to GLOBAL mode, by default libcrypto.so is LOCAL mode ++ private static boolean useGlobalMode() { ++ String explicitLoad = KAEConfig.privilegedGetOverridable( ++ "kae.libcrypto.useGlobalMode", "false"); ++ return Boolean.parseBoolean(explicitLoad); ++ } ++ ++ @SuppressWarnings({"deprecation", "this-escape"}) ++ public KAEProvider() { ++ super("KAEProvider", PROVIDER_VER, "KAE provider"); ++ if (KAEConfig.useKaeProvider("kae.md5")) { ++ putMD5(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sha256")) { ++ putSHA256(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sha384")) { ++ putSHA384(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sm3")) { ++ putSM3(); ++ } ++ if (KAEConfig.useKaeProvider("kae.aes")) { ++ putAES(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sm4")) { ++ putSM4(); ++ } ++ if (KAEConfig.useKaeProvider("kae.hmac")) { ++ putHMAC(); ++ } ++ if (KAEConfig.useKaeProvider("kae.rsa")) { ++ putRSA(); ++ putSignatureRSA(); ++ } ++ if (KAEConfig.useKaeProvider("kae.dh")) { ++ putDH(); ++ } ++ if (KAEConfig.useKaeProvider("kae.ec")) { ++ putEC(); ++ } ++ } ++ ++ private void putAES() { ++ final String blockModes = "ECB|CBC|CTR|GCM"; ++ final String blockPads = "NOPADDING|PKCS5PADDING"; ++ ++ put("Cipher.AES SupportedModes", blockModes); ++ put("Cipher.AES SupportedPaddings", blockPads); ++ put("Cipher.AES", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$PKCS5Padding"); ++ ++ put("Cipher.AES/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Cbc$PKCS5Padding"); ++ put("Cipher.AES/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES/CBC/PKCS7Padding", "AES/CBC/PKCS5Padding"); ++ put("Cipher.AES/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$NoPadding"); ++ put("Cipher.AES/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES/ECB/PKCS7Padding", "AES/ECB/PKCS5Padding"); ++ put("Cipher.AES/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ctr$NoPadding"); ++ put("Cipher.AES/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES/GCM/PKCS5Padding", "AES/GCM/NoPadding"); // PKCS5Padding -> noPadding ++ ++ put("Cipher.AES_128/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Cbc$PKCS5Padding"); ++ put("Cipher.AES_128/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES_128/CBC/PKCS7Padding", "AES_128/CBC/PKCS5Padding"); ++ put("Cipher.AES_128/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ecb$NoPadding"); ++ put("Cipher.AES_128/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES_128/ECB/PKCS7Padding", "AES_128/ECB/PKCS5Padding"); ++ put("Cipher.AES_128/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ctr$NoPadding"); ++ put("Cipher.AES_128/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES_128/GCM/PKCS5Padding", "AES/GCM/NoPadding"); ++ ++ put("Cipher.AES_192/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Cbc$PKCS5Padding"); ++ put("Cipher.AES_192/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES_192/CBC/PKCS7Padding", "AES_192/CBC/PKCS5Padding"); ++ put("Cipher.AES_192/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ecb$NoPadding"); ++ put("Cipher.AES_192/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES_192/ECB/PKCS7Padding", "AES_192/ECB/PKCS5Padding"); ++ put("Cipher.AES_192/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ctr$NoPadding"); ++ put("Cipher.AES_192/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES_192/GCM/PKCS5Padding", "AES/GCM/NoPadding"); ++ ++ put("Cipher.AES_256/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Cbc$PKCS5Padding"); ++ put("Cipher.AES_256/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES_256/CBC/PKCS7Padding", "AES_256/CBC/PKCS5Padding"); ++ put("Cipher.AES_256/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ecb$NoPadding"); ++ put("Cipher.AES_256/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES_256/ECB/PKCS7Padding", "AES_256/ECB/PKCS5Padding"); ++ put("Cipher.AES_256/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ctr$NoPadding"); ++ put("Cipher.AES_256/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES_256/GCM/PKCS5Padding", "AES/GCM/NoPadding"); ++ } ++ ++ private void putMD5() { ++ put("MessageDigest.MD5", "org.openeuler.security.openssl.KAEDigest$MD5"); ++ } ++ ++ private void putSHA256() { ++ put("MessageDigest.SHA-256", "org.openeuler.security.openssl.KAEDigest$SHA256"); ++ } ++ ++ private void putSHA384() { ++ put("MessageDigest.SHA-384", "org.openeuler.security.openssl.KAEDigest$SHA384"); ++ } ++ ++ private void putSM3() { ++ put("MessageDigest.SM3", "org.openeuler.security.openssl.KAEDigest$SM3"); ++ } ++ ++ private void putSM4() { ++ final String blockModes = "ECB|CBC|CTR|OFB"; ++ final String blockPads = "NOPADDING|PKCS5PADDING"; ++ ++ put("Cipher.SM4 SupportedModes", blockModes); ++ put("Cipher.SM4 SupportedPaddings", blockPads); ++ put("Cipher.SM4", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ecb$PKCS5Padding"); ++ ++ put("Cipher.SM4/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Cbc$PKCS5Padding"); ++ put("Cipher.SM4/CBC/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.SM4/CBC/PKCS7Padding", "SM4/CBC/PKCS5Padding"); ++ put("Cipher.SM4/ECB/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ecb$NoPadding"); ++ put("Cipher.SM4/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.SM4/ECB/PKCS7Padding", "SM4/ECB/PKCS5Padding"); ++ put("Cipher.SM4/CTR/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ctr$NoPadding"); ++ put("Cipher.SM4/OFB/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ofb$NoPadding"); ++ put("Cipher.SM4/OFB/PKCS5Padding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ofb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.SM4/OFB/PKCS7Padding", "SM4/OFB/PKCS5Padding"); ++ ++ put("KeyGenerator.SM4", "org.openeuler.security.openssl.KAESM4KeyGenerator"); ++ put("AlgorithmParameters.SM4", "com.sun.crypto.provider.AESParameters"); ++ } ++ ++ private void putRSA() { ++ // rsa ++ put("KeyPairGenerator.RSA", "org.openeuler.security.openssl.KAERSAKeyPairGenerator$Legacy"); ++ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); ++ put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); ++ ++ put("KeyPairGenerator.RSASSA-PSS", "org.openeuler.security.openssl.KAERSAKeyPairGenerator$PSS"); ++ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ put("Cipher.RSA", "org.openeuler.security.openssl.KAERSACipher"); ++ put("Cipher.RSA SupportedModes", "ECB"); ++ put("Cipher.RSA SupportedPaddings", ++ "NOPADDING|PKCS1PADDING|OAEPPADDING" ++ + "|OAEPWITHMD5ANDMGF1PADDING" ++ + "|OAEPWITHSHA1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-256ANDMGF1PADDING" ++ + "|OAEPWITHSHA-384ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); ++ put("Cipher.RSA SupportedKeyClasses", ++ "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"); ++ } ++ ++ private void putHMAC() { ++ put("MAC.HmacMD5", "org.openeuler.security.openssl.KAEHMac$HmacMD5"); ++ put("MAC.HmacSHA1", "org.openeuler.security.openssl.KAEHMac$HmacSHA1"); ++ put("MAC.HmacSHA224", "org.openeuler.security.openssl.KAEHMac$HmacSHA224"); ++ put("MAC.HmacSHA256", "org.openeuler.security.openssl.KAEHMac$HmacSHA256"); ++ put("MAC.HmacSHA384", "org.openeuler.security.openssl.KAEHMac$HmacSHA384"); ++ put("MAC.HmacSHA512", "org.openeuler.security.openssl.KAEHMac$HmacSHA512"); ++ } ++ ++ private void putDH() { ++ put("KeyPairGenerator.DiffieHellman", "org.openeuler.security.openssl.KAEDHKeyPairGenerator"); ++ put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman"); ++ put("KeyAgreement.DiffieHellman", "org.openeuler.security.openssl.KAEDHKeyAgreement"); ++ put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); ++ } ++ ++ private void putSignatureRSA() { ++ put("Signature.MD5withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$MD5withRSA"); ++ put("Signature.SHA1withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA1withRSA"); ++ put("Signature.SHA224withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA224withRSA"); ++ put("Signature.SHA256withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA256withRSA"); ++ put("Signature.SHA384withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA384withRSA"); ++ put("Signature.SHA512withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA512withRSA"); ++ ++ // alias ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ ++ put("Signature.RSASSA-PSS", "org.openeuler.security.openssl.KAERSAPSSSignature"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ // attributes for supported key classes ++ String rsaKeyClasses = "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"; ++ put("Signature.MD5withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA1withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA224withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA256withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA384withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA512withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.RSASSA-PSS SupportedKeyClasses", rsaKeyClasses); ++ } ++ ++ private void putEC() { ++ put("KeyPairGenerator.EC", "org.openeuler.security.openssl.KAEECKeyPairGenerator"); ++ put("Alg.Alias.KeyPairGenerator.EllipticCurve", "EC"); ++ put("KeyAgreement.ECDH", "org.openeuler.security.openssl.KAEECDHKeyAgreement"); ++ } ++ ++ // init openssl ++ static native void initOpenssl(boolean useGlobalMode, String engineId, boolean[] algorithmKaeFlags) ++ throws RuntimeException; ++ ++ static native boolean[] getEngineFlags(); ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java +new file mode 100644 +index 000000000..a45fb0dac +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java +@@ -0,0 +1,796 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; ++import sun.security.jca.Providers; ++import sun.security.rsa.RSACore; ++import sun.security.rsa.RSAKeyFactory; ++import sun.security.rsa.RSAPadding; ++import sun.security.util.KeyUtil; ++ ++import javax.crypto.*; ++import javax.crypto.spec.OAEPParameterSpec; ++import javax.crypto.spec.PSource; ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.*; ++import java.security.interfaces.RSAKey; ++import java.security.interfaces.RSAPrivateCrtKey; ++import java.security.interfaces.RSAPrivateKey; ++import java.security.interfaces.RSAPublicKey; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.InvalidParameterSpecException; ++import java.security.spec.MGF1ParameterSpec; ++import java.util.Arrays; ++import java.util.Locale; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++ ++/** ++ * RSA cipher implementation. Supports RSA en/decryption and signing/verifying ++ * using both PKCS#1 v1.5 and OAEP (v2.2) paddings and without padding (raw RSA). ++ * Note that raw RSA is supported mostly for completeness and should only be ++ * used in rare cases. ++ *

    ++ * Objects should be instantiated by calling Cipher.getInstance() using the ++ * following algorithm names: ++ * . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 v1.5 padding. ++ * . "RSA/ECB/OAEPwithandMGF1Padding" (or "RSA/ECB/OAEPPadding") for ++ * PKCS#1 v2.2 padding. ++ * . "RSA/ECB/NoPadding" for rsa RSA. ++ *

    ++ * We only do one RSA operation per doFinal() call. If the application passes ++ * more data via calls to update() or doFinal(), we throw an ++ * IllegalBlockSizeException when doFinal() is called (see JCE API spec). ++ * Bulk encryption using RSA does not make sense and is not standardized. ++ *

    ++ * Note: RSA keys should be at least 512 bits long ++ */ ++public final class KAERSACipher extends CipherSpi { ++ // constant for an empty byte array ++ private final static byte[] B0 = new byte[0]; ++ ++ // mode constant for public key encryption ++ private final static int MODE_ENCRYPT = 1; ++ ++ // mode constant for private key decryption ++ private final static int MODE_DECRYPT = 2; ++ ++ // mode constant for private key encryption (signing) ++ private final static int MODE_SIGN = 3; ++ ++ // mode constant for public key decryption (verifying) ++ private final static int MODE_VERIFY = 4; ++ ++ // current mode, one of MODE_* above. Set when init() is called ++ private int mode; ++ ++ // active padding type, one of PAD_* above. Set by setPadding() ++ private KAERSAPaddingType paddingType; ++ ++ // padding object ++ private RSAPadding padding; ++ ++ // cipher parameter for OAEP padding and TLS RSA premaster secret ++ private AlgorithmParameterSpec spec = null; ++ ++ // buffer for the data ++ private byte[] buffer; ++ ++ // offset into the buffer (number of bytes buffered) ++ private int bufOfs; ++ ++ // size of the output ++ private int outputSize; ++ ++ // hash algorithm for OAEP ++ private String oaepHashAlgorithm = "SHA-1"; ++ ++ // the source of randomness ++ private SecureRandom random; ++ ++ private RSAKey rsaKey; ++ ++ // rsa key holder ++ private KAERSAKeyHolder rsaKeyHolder; ++ ++ ++ public KAERSACipher() { ++ paddingType = KAERSAPaddingType.PKCS1Padding; ++ } ++ ++ // modes do not make sense for RSA, but allow ECB ++ // see JCE spec ++ @Override ++ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { ++ if (!mode.equalsIgnoreCase("ECB")) { ++ throw new NoSuchAlgorithmException("Unsupported mode " + mode); ++ } ++ } ++ ++ // set the padding type ++ // see JCE spec ++ @Override ++ protected void engineSetPadding(String paddingName) ++ throws NoSuchPaddingException { ++ if (KAERSAPaddingType.NoPadding.getName().equalsIgnoreCase(paddingName)) { ++ paddingType = KAERSAPaddingType.NoPadding; ++ } else if (KAERSAPaddingType.PKCS1Padding.getName().equalsIgnoreCase(paddingName)) { ++ paddingType = KAERSAPaddingType.PKCS1Padding; ++ } else { ++ String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH); ++ if ("oaeppadding".equals(lowerPadding)) { ++ paddingType = KAERSAPaddingType.OAEP; ++ } else if (lowerPadding.startsWith("oaepwith") && ++ lowerPadding.endsWith("andmgf1padding")) { ++ paddingType = KAERSAPaddingType.OAEP; ++ // "oaepwith" length is 8 ++ // "andmgf1padding" length is 14 ++ oaepHashAlgorithm = ++ paddingName.substring(8, paddingName.length() - 14); ++ // check if MessageDigest appears to be available ++ // avoid getInstance() call here ++ if (Providers.getProviderList().getService ++ ("MessageDigest", oaepHashAlgorithm) == null) { ++ throw new NoSuchPaddingException ++ ("MessageDigest not available for " + paddingName); ++ } ++ } else { ++ throw new NoSuchPaddingException ++ ("Padding " + paddingName + " not supported"); ++ } ++ } ++ } ++ ++ // return 0 as block size, we are not a block cipher ++ // see JCE spec ++ @Override ++ protected int engineGetBlockSize() { ++ return 0; ++ } ++ ++ // return the output size ++ // see JCE spec ++ @Override ++ protected int engineGetOutputSize(int inputLen) { ++ return outputSize; ++ } ++ ++ // no iv, return null ++ // see JCE spec ++ @Override ++ protected byte[] engineGetIV() { ++ return null; ++ } ++ ++ // see JCE spec ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ if (spec != null && spec instanceof OAEPParameterSpec) { ++ try { ++ AlgorithmParameters params = ++ AlgorithmParameters.getInstance("OAEP"); ++ params.init(spec); ++ return params; ++ } catch (NoSuchAlgorithmException nsae) { ++ // should never happen ++ throw new RuntimeException("Cannot find OAEP " + ++ " AlgorithmParameters implementation in SunJCE provider"); ++ } catch (InvalidParameterSpecException ipse) { ++ // should never happen ++ throw new RuntimeException("OAEPParameterSpec not supported"); ++ } ++ } else { ++ return null; ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected void engineInit(int opmode, Key key, SecureRandom random) ++ throws InvalidKeyException { ++ try { ++ init(opmode, key, random, null); ++ } catch (InvalidAlgorithmParameterException iape) { ++ // never thrown when null parameters are used; ++ // but re-throw it just in case ++ throw new InvalidKeyException("Wrong parameters", iape); ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ init(opmode, key, random, params); ++ } ++ ++ // see JCE spec ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ if (params == null) { ++ init(opmode, key, random, null); ++ } else { ++ try { ++ OAEPParameterSpec oaepParameterSpec = ++ params.getParameterSpec(OAEPParameterSpec.class); ++ init(opmode, key, random, oaepParameterSpec); ++ } catch (InvalidParameterSpecException ipse) { ++ InvalidAlgorithmParameterException iape = ++ new InvalidAlgorithmParameterException("Wrong parameter"); ++ iape.initCause(ipse); ++ throw iape; ++ } ++ } ++ } ++ ++ // check TlsRsaPremasterSecretParameterSpec ++ @SuppressWarnings("deprecation") ++ private void checkTlsRsaPremasterSecretParameterSpec(AlgorithmParameterSpec params) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { ++ throw new InvalidAlgorithmParameterException( ++ "Parameters not supported"); ++ } ++ } ++ ++ // check OAEPParameterSpec ++ private void checkOAEPParameterSpec(AlgorithmParameterSpec params) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof OAEPParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("Wrong Parameters for OAEP Padding"); ++ } ++ ++ // check MGF algorithm ++ OAEPParameterSpec oaepParameterSpec = (OAEPParameterSpec) params; ++ String mgfName = oaepParameterSpec.getMGFAlgorithm(); ++ if (!mgfName.equalsIgnoreCase("MGF1")) { ++ throw new InvalidAlgorithmParameterException ++ ("Unsupported MGF algo: " + mgfName); ++ } ++ ++ // check PSource algorithm ++ PSource pSource = oaepParameterSpec.getPSource(); ++ String pSourceAlgorithm = pSource.getAlgorithm(); ++ if (!pSourceAlgorithm.equalsIgnoreCase("PSpecified")) { ++ throw new InvalidAlgorithmParameterException ++ ("Unsupported pSource algo: " + pSourceAlgorithm); ++ } ++ } ++ ++ // compute OAEP data buffer length ++ private int getOAEPBufferLen(int outputSize, OAEPParameterSpec oaepParameterSpec, boolean encrypt) ++ throws InvalidKeyException { ++ if (!encrypt) { ++ return outputSize; ++ } ++ String mdName = oaepParameterSpec.getDigestAlgorithm(); ++ String mgfMdName = ((MGF1ParameterSpec) oaepParameterSpec.getMGFParameters()) ++ .getDigestAlgorithm(); ++ int digestLen = KAEUtils.getDigestLength(mdName); ++ int bufferLen = outputSize - 2 - 2 * digestLen; ++ if (bufferLen < 0) { ++ throw new InvalidKeyException ++ ("Key is too short for encryption using OAEPPadding" + ++ " with " + mdName + " and MGF1" + mgfMdName); ++ } ++ return bufferLen; ++ } ++ ++ // non-CRT private key, use the jdk soft calculation. ++ private boolean useJdkSoftCalculation() { ++ return (rsaKey instanceof RSAPrivateKey) && !(rsaKey instanceof RSAPrivateCrtKey); ++ } ++ ++ // get the rsa padding ++ private RSAPadding getRSAPadding(KAERSAPaddingType paddingType, int paddedSize, ++ SecureRandom random, AlgorithmParameterSpec spec) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ RSAPadding rsaPadding; ++ if (KAERSAPaddingType.NoPadding.equals(paddingType)) { ++ rsaPadding = RSAPadding.getInstance(RSAPadding.PAD_NONE, paddedSize, random); ++ } else if (KAERSAPaddingType.PKCS1Padding.equals(paddingType)) { ++ int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 ++ : RSAPadding.PAD_BLOCKTYPE_1; ++ rsaPadding = RSAPadding.getInstance(blockType, paddedSize, random); ++ } else { ++ rsaPadding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, paddedSize, ++ random, (OAEPParameterSpec) spec); ++ } ++ return rsaPadding; ++ } ++ ++ private boolean isEncrypt(int opmode) throws InvalidKeyException { ++ boolean encrypt; ++ switch (opmode) { ++ case Cipher.ENCRYPT_MODE: ++ case Cipher.WRAP_MODE: ++ encrypt = true; ++ break; ++ case Cipher.DECRYPT_MODE: ++ case Cipher.UNWRAP_MODE: ++ encrypt = false; ++ break; ++ default: ++ throw new InvalidKeyException("Unknown mode: " + opmode); ++ } ++ return encrypt; ++ } ++ ++ // initialize this cipher ++ private void init(int opmode, Key key, SecureRandom random, AlgorithmParameterSpec params) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ // check the key, and convert to RSAKey ++ rsaKey = RSAKeyFactory.toRSAKey(key); ++ ++ // init mode ++ boolean encrypt = isEncrypt(opmode); ++ if (key instanceof RSAPublicKey) { ++ mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; ++ } else { ++ mode = encrypt ? MODE_SIGN : MODE_DECRYPT; ++ } ++ ++ int bufferLen = RSACore.getByteLength(rsaKey.getModulus()); ++ outputSize = bufferLen; ++ bufOfs = 0; ++ if (KAERSAPaddingType.PKCS1Padding.equals(paddingType)) { ++ if (params != null) { ++ checkTlsRsaPremasterSecretParameterSpec(params); ++ spec = params; ++ this.random = random; // for TLS RSA premaster secret ++ } ++ if (encrypt) { ++ bufferLen -= 11; ++ } ++ } else if (KAERSAPaddingType.OAEP.equals(paddingType)) { ++ if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) { ++ throw new InvalidKeyException ++ ("OAEP cannot be used to sign or verify signatures"); ++ } ++ if (params != null) { ++ checkOAEPParameterSpec(params); ++ spec = params; ++ } else { ++ spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", ++ MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); ++ } ++ bufferLen = getOAEPBufferLen(bufferLen, (OAEPParameterSpec) spec, encrypt); ++ } ++ buffer = new byte[bufferLen]; ++ ++ if (useJdkSoftCalculation()) { ++ this.padding = getRSAPadding(paddingType, outputSize, random, spec); ++ } ++ } ++ ++ // internal update method ++ private void update(byte[] in, int inOfs, int inLen) { ++ if ((inLen == 0) || (in == null)) { ++ return; ++ } ++ if (inLen > (buffer.length - bufOfs)) { ++ bufOfs = buffer.length + 1; ++ return; ++ } ++ System.arraycopy(in, inOfs, buffer, bufOfs, inLen); ++ bufOfs += inLen; ++ } ++ ++ // encrypt or decrypt for NoPadding or PKCS1Padding ++ private int doCryptNotOAEPPadding(long keyAddress, byte[] input, byte[] output) throws BadPaddingException { ++ int resultSize; ++ switch (mode) { ++ case MODE_SIGN: ++ resultSize = nativeRSAPrivateEncrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ case MODE_VERIFY: ++ resultSize = nativeRSAPublicDecrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ case MODE_ENCRYPT: ++ resultSize = nativeRSAPublicEncrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ case MODE_DECRYPT: ++ resultSize = nativeRSAPrivateDecrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ default: ++ throw new AssertionError("Internal error"); ++ } ++ return resultSize; ++ } ++ ++ ++ // encrypt or decrypt for OAEPPadding ++ private int doCryptOAEPPadding(long keyAddress, byte[] input, byte[] output, OAEPParameterSpec oaepParameterSpec) ++ throws BadPaddingException { ++ // oaep digest algorithm ++ String oaepMdAlgorithm = KAEUtils.getKAEDigestName(oaepParameterSpec.getDigestAlgorithm()); ++ // mgf1 digest algorithm ++ MGF1ParameterSpec mgf1ParameterSpec = (MGF1ParameterSpec) oaepParameterSpec.getMGFParameters(); ++ String mgf1MdAlgorithm = KAEUtils.getKAEDigestName(mgf1ParameterSpec.getDigestAlgorithm()); ++ // label ++ PSource pSource = oaepParameterSpec.getPSource(); ++ byte[] label = ((PSource.PSpecified) pSource).getValue(); ++ int resultSize; ++ switch (mode) { ++ case MODE_ENCRYPT: ++ resultSize = nativeRSAEncryptOAEPPadding(keyAddress, input.length, input, output, paddingType.getId(), ++ oaepMdAlgorithm, mgf1MdAlgorithm, label); ++ break; ++ case MODE_DECRYPT: ++ resultSize = nativeRSADecryptOAEPPadding(keyAddress, input.length, input, output, paddingType.getId(), ++ oaepMdAlgorithm, mgf1MdAlgorithm, label); ++ break; ++ default: ++ throw new AssertionError("Internal error"); ++ } ++ return resultSize; ++ } ++ ++ // get input bytes ++ private byte[] getInputBytes(byte[] buffer, int bufOfs, KAERSAPaddingType paddingType) { ++ if (bufOfs == buffer.length) { ++ return buffer; ++ } ++ ++ // if padding type is NoPadding , data should move to end ++ final byte[] input; ++ if (KAERSAPaddingType.NoPadding.equals(paddingType)) { ++ input = new byte[buffer.length]; ++ System.arraycopy(buffer, 0, input, buffer.length - bufOfs, bufOfs); ++ } else { ++ input = Arrays.copyOf(buffer, bufOfs); ++ } ++ return input; ++ } ++ ++ // internal doFinal() method. Here we perform the actual RSA operation ++ private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException { ++ if (bufOfs > buffer.length) { ++ throw new IllegalBlockSizeException("Data must not be longer " ++ + "than " + buffer.length + " bytes"); ++ } ++ ++ if (useJdkSoftCalculation()) { ++ return doFinalForJdkSoftCalculation(padding); ++ } ++ ++ // get input bytes ++ final byte[] input = getInputBytes(buffer, bufOfs, paddingType); ++ ++ try { ++ rsaKeyHolder = new KAERSAKeyHolder(this, rsaKey); ++ } catch (InvalidKeyException e) { ++ throw new RuntimeException(e.getMessage()); ++ } ++ ++ long keyAddress = rsaKeyHolder.keyAddress; ++ byte[] output = new byte[outputSize]; ++ int cipherTextLength; ++ try { ++ if (KAERSAPaddingType.OAEP.equals(paddingType)) { ++ // do crypt for OAEPPadding ++ cipherTextLength = doCryptOAEPPadding(keyAddress, input, output, (OAEPParameterSpec) spec); ++ } else { ++ // do crypt for NoPadding or PKCS1Padding ++ cipherTextLength = doCryptNotOAEPPadding(keyAddress, input, output); ++ } ++ ++ // If mode is signing or verifying , and the length of the ciphertext is less than output length, ++ // just keep output length ciphertext. ++ if ((mode == MODE_VERIFY || mode == MODE_DECRYPT) && cipherTextLength != output.length) { ++ output = Arrays.copyOf(output, cipherTextLength); ++ } ++ } finally { ++ bufOfs = 0; ++ resetKeyHolder(); ++ } ++ return output; ++ } ++ ++ private byte[] doFinalForJdkSoftCalculation(RSAPadding padding) throws BadPaddingException { ++ try { ++ byte[] data; ++ switch (mode) { ++ case MODE_SIGN: ++ data = padding.pad(buffer, 0, bufOfs); ++ return RSACore.rsa(data, (RSAPrivateKey) rsaKey, true); ++ case MODE_DECRYPT: ++ byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); ++ data = RSACore.rsa(decryptBuffer, (RSAPrivateKey) rsaKey, false); ++ return padding.unpad(data); ++ default: ++ throw new AssertionError("Internal error"); ++ } ++ } finally { ++ bufOfs = 0; ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { ++ update(in, inOfs, inLen); ++ return B0; ++ } ++ ++ // see JCE spec ++ @Override ++ protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, ++ int outOfs) { ++ update(in, inOfs, inLen); ++ return 0; ++ } ++ ++ // see JCE spec ++ @Override ++ protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) ++ throws BadPaddingException, IllegalBlockSizeException { ++ update(in, inOfs, inLen); ++ return doFinal(); ++ } ++ ++ // see JCE spec ++ @Override ++ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) ++ throws ShortBufferException, BadPaddingException, IllegalBlockSizeException { ++ if (outputSize > out.length - outOfs) { ++ throw new ShortBufferException ++ ("Need " + outputSize + " bytes for output"); ++ } ++ update(in, inOfs, inLen); ++ byte[] result = doFinal(); ++ int length = result.length; ++ System.arraycopy(result, 0, out, outOfs, length); ++ return length; ++ } ++ ++ // see JCE spec ++ @Override ++ protected byte[] engineWrap(Key key) throws InvalidKeyException, ++ IllegalBlockSizeException { ++ byte[] encoded = key.getEncoded(); ++ if ((encoded == null) || (encoded.length == 0)) { ++ throw new InvalidKeyException("Could not obtain encoded key"); ++ } ++ if (encoded.length > buffer.length) { ++ throw new InvalidKeyException("Key is too long for wrapping"); ++ } ++ update(encoded, 0, encoded.length); ++ try { ++ return doFinal(); ++ } catch (BadPaddingException e) { ++ // should not occur ++ throw new InvalidKeyException("Wrapping failed", e); ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ @SuppressWarnings("deprecation") ++ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, int type) ++ throws InvalidKeyException, NoSuchAlgorithmException { ++ if (wrappedKey.length > buffer.length) { ++ throw new InvalidKeyException("Key is too long for unwrapping"); ++ } ++ ++ boolean isTlsRsaPremasterSecret = "TlsRsaPremasterSecret".equals(algorithm); ++ Exception failover = null; ++ byte[] encoded = null; ++ ++ update(wrappedKey, 0, wrappedKey.length); ++ try { ++ encoded = doFinal(); ++ } catch (BadPaddingException e) { ++ if (isTlsRsaPremasterSecret) { ++ failover = e; ++ } else { ++ throw new InvalidKeyException("Unwrapping failed", e); ++ } ++ } catch (IllegalBlockSizeException e) { ++ // should not occur, handled with length check above ++ throw new InvalidKeyException("Unwrapping failed", e); ++ } ++ ++ if (isTlsRsaPremasterSecret) { ++ if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { ++ throw new IllegalStateException( ++ "No TlsRsaPremasterSecretParameterSpec specified"); ++ } ++ ++ // polish the TLS premaster secret ++ encoded = KeyUtil.checkTlsPreMasterSecretKey( ++ ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), ++ ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), ++ random, encoded, (failover != null)); ++ } ++ return KAEUtils.ConstructKeys.constructKey(encoded, algorithm, type); ++ } ++ ++ // see JCE spec ++ @Override ++ protected int engineGetKeySize(Key key) throws InvalidKeyException { ++ RSAKey newRSAKey = RSAKeyFactory.toRSAKey(key); ++ return newRSAKey.getModulus().bitLength(); ++ } ++ ++ // reset the key holder ++ private void resetKeyHolder() { ++ if (rsaKeyHolder != null) { ++ rsaKeyHolder.dispose(true); ++ rsaKeyHolder = null; ++ } ++ } ++ ++ // create KAE rsa key ++ protected static native long nativeCreateRSAPrivateCrtKey(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q, ++ byte[] dmp1, byte[] dmq1, byte[] iqmp); ++ ++ // create KAE rsa public key ++ protected static native long nativeCreateRSAPublicKey(byte[] n, byte[] e); ++ ++ // encrypt by private key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPrivateEncrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // decrypt by private key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPrivateDecrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // encrypt by public key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPublicEncrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // decrypt by public key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPublicDecrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // encrypt by public for padding type (OAEPPADDING) ++ protected static native int nativeRSAEncryptOAEPPadding(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType, String oaepMdAlgo, String mgf1MdAlgo, ++ byte[] label) throws BadPaddingException; ++ ++ // decrypt by public for padding type (OAEPPADDING) ++ protected static native int nativeRSADecryptOAEPPadding(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType, String oaepMdAlgo, String mgf1MdAlgo, ++ byte[] label) throws BadPaddingException; ++ ++ // free the key ++ protected static native void nativeFreeKey(long keyAddress); ++ ++ /** ++ * The rsa openssl key holder , use PhantomReference in case of native memory leaks ++ */ ++ private static class KAERSAKeyHolder extends PhantomReference ++ implements Comparable { ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private final long keyAddress; ++ ++ KAERSAKeyHolder(KAERSACipher rsaCipher, RSAKey rsaKey) throws InvalidKeyException { ++ super(rsaCipher, referenceQueue); ++ this.keyAddress = getKeyAddress(rsaKey); ++ referenceList.add(this); ++ drainRefQueueBounded(); ++ } ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ KAERSAKeyHolder next = (KAERSAKeyHolder) referenceQueue.poll(); ++ if (next == null) { ++ break; ++ } ++ next.dispose(true); ++ } ++ } ++ ++ void dispose(boolean needFree) { ++ referenceList.remove(this); ++ try { ++ if (needFree) { ++ nativeFreeKey(keyAddress); ++ } ++ } finally { ++ this.clear(); ++ } ++ } ++ ++ @Override ++ public int compareTo(KAERSAKeyHolder other) { ++ if (this.keyAddress == other.keyAddress) { ++ return 0; ++ } else { ++ return (this.keyAddress < other.keyAddress) ? -1 : 1; ++ } ++ } ++ ++ private long getKeyAddress(RSAKey rsaKey) throws InvalidKeyException { ++ long address; ++ if (rsaKey instanceof RSAPrivateCrtKey) { // RSAPrivateCrtKeyImpl ++ address = getKeyAddress((RSAPrivateCrtKey) rsaKey); ++ } else if (rsaKey instanceof RSAPublicKey) { // RSAPublicKeyImpl ++ address = getKeyAddress((RSAPublicKey) rsaKey); ++ } else { ++ throw new InvalidKeyException("Invalid RSAKey implement " + rsaKey.getClass()); ++ } ++ return address; ++ } ++ ++ private long getKeyAddress(RSAPrivateCrtKey key) throws InvalidKeyException { ++ checkKey(key); ++ try { ++ return nativeCreateRSAPrivateCrtKey( ++ key.getModulus().toByteArray(), ++ key.getPublicExponent().toByteArray(), ++ key.getPrivateExponent().toByteArray(), ++ key.getPrimeP().toByteArray(), ++ key.getPrimeQ().toByteArray(), ++ key.getPrimeExponentP().toByteArray(), ++ key.getPrimeExponentQ().toByteArray(), ++ key.getCrtCoefficient().toByteArray()); ++ } catch (Exception e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ private long getKeyAddress(RSAPublicKey key) throws InvalidKeyException { ++ checkKey(key); ++ try { ++ return nativeCreateRSAPublicKey( ++ key.getModulus().toByteArray(), ++ key.getPublicExponent().toByteArray() ++ ); ++ } catch (Exception e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ private void checkKey(RSAPrivateCrtKey key) throws InvalidKeyException { ++ boolean isInValidKey = key.getModulus() == null ++ || key.getPublicExponent() == null ++ || key.getPrivateExponent() == null ++ || key.getPrimeP() == null ++ || key.getPrimeQ() == null ++ || key.getPrimeExponentP() == null ++ || key.getPrimeExponentQ() == null ++ || key.getCrtCoefficient() == null; ++ if (isInValidKey) { ++ throw new InvalidKeyException("Invalid RSA private key"); ++ } ++ } ++ ++ private void checkKey(RSAPublicKey key) throws InvalidKeyException { ++ if (key.getModulus() == null || key.getPublicExponent() == null) { ++ throw new InvalidKeyException("Invalid RSA public key"); ++ } ++ } ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java +new file mode 100644 +index 000000000..88bd30574 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.rsa.*; ++import sun.security.rsa.RSAUtil.KeyType; ++import sun.security.util.SecurityProviderConstants; ++ ++import java.math.BigInteger; ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.RSAKeyGenParameterSpec; ++ ++public abstract class KAERSAKeyPairGenerator extends KeyPairGeneratorSpi { ++ // public exponent to use ++ private BigInteger publicExponent; ++ ++ // size of the key to generate, >= KAERSAKeyFactory.MIN_MODLEN ++ private int keySize; ++ ++ private final KeyType type; ++ ++ private AlgorithmParameterSpec keyParams; ++ ++ ++ KAERSAKeyPairGenerator(KeyType keyType, int keySize) { ++ this.type = keyType; ++ initialize(keySize, null); ++ } ++ ++ // initialize the generator. See JCA doc ++ @Override ++ public void initialize(int keySize, SecureRandom random) { ++ try { ++ initialize(new RSAKeyGenParameterSpec(keySize, ++ RSAKeyGenParameterSpec.F4), null); ++ } catch (InvalidAlgorithmParameterException iape) { ++ throw new InvalidParameterException(iape.getMessage()); ++ } ++ } ++ ++ // second initialize method. See JCA doc ++ @Override ++ public void initialize(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof RSAKeyGenParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("Params must be instance of RSAKeyGenParameterSpec"); ++ } ++ ++ RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) params; ++ int tmpKeySize = rsaSpec.getKeysize(); ++ BigInteger tmpPublicExponent = rsaSpec.getPublicExponent(); ++ keyParams = rsaSpec.getKeyParams(); ++ ++ if (tmpPublicExponent == null) { ++ tmpPublicExponent = RSAKeyGenParameterSpec.F4; ++ } else { ++ if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) { ++ throw new InvalidAlgorithmParameterException ++ ("Public exponent must be 3 or larger"); ++ } ++ if (tmpPublicExponent.bitLength() > tmpKeySize) { ++ throw new InvalidAlgorithmParameterException ++ ("Public exponent must be smaller than key size"); ++ } ++ } ++ ++ // do not allow unreasonably large key sizes, probably user error ++ try { ++ RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent, ++ 512, 64 * 1024); ++ } catch (InvalidKeyException e) { ++ throw new InvalidAlgorithmParameterException( ++ "Invalid key sizes", e); ++ } ++ ++ this.keySize = tmpKeySize; ++ this.publicExponent = tmpPublicExponent; ++ } ++ ++ // generate the keypair. See JCA doc ++ @Override ++ public KeyPair generateKeyPair() { ++ // get the KAE RSA key Parameters ++ byte[][] params = nativeGenerateKeyPair(keySize, publicExponent.toByteArray()); ++ ++ try { ++ // check KAE RSA key Parameters ++ checkKAERSAParams(params); ++ ++ BigInteger n = new BigInteger(params[0]); ++ BigInteger e = new BigInteger(params[1]); ++ BigInteger d = new BigInteger(params[2]); ++ BigInteger p = new BigInteger(params[3]); ++ BigInteger q = new BigInteger(params[4]); ++ BigInteger pe = new BigInteger(params[5]); ++ BigInteger qe = new BigInteger(params[6]); ++ BigInteger coeff = new BigInteger(params[7]); ++ ++ // public key ++ PublicKey publicKey = RSAPublicKeyImpl.newKey(type, keyParams, n, e); ++ ++ // private key ++ PrivateKey privateKey = RSAPrivateCrtKeyImpl.newKey(type, keyParams, n, e, d, p, q, pe, qe, coeff); ++ ++ return new KeyPair(publicKey, privateKey); ++ } catch (InvalidKeyException ex) { ++ throw new RuntimeException(ex); ++ } ++ } ++ ++ // check KAE RSA key Parameters ++ private void checkKAERSAParams(byte[][] params) throws InvalidKeyException { ++ if (params == null || params.length < 8) { ++ throw new InvalidKeyException("Invalid KAE RSA key Parameter"); ++ } ++ ++ for (int i = 0; i < params.length; i++) { ++ if (params[i] == null) { ++ throw new InvalidKeyException("Invalid KAE RSA key Parameter , params[" + i + "] = null"); ++ } ++ } ++ } ++ ++ public static final class Legacy extends KAERSAKeyPairGenerator { ++ public Legacy() { ++ super(KeyType.RSA, SecurityProviderConstants.DEF_RSA_KEY_SIZE); ++ } ++ } ++ ++ public static final class PSS extends KAERSAKeyPairGenerator { ++ public PSS() { ++ super(KeyType.PSS, SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE); ++ } ++ } ++ ++ // generate key pair ++ static native byte[][] nativeGenerateKeyPair(int keySize, byte[] publicExponent) throws RuntimeException; ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java +new file mode 100644 +index 000000000..065317148 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java +@@ -0,0 +1,683 @@ ++/* ++ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++package org.openeuler.security.openssl; ++ ++import java.io.IOException; ++import java.nio.ByteBuffer; ++ ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.PSSParameterSpec; ++import java.security.spec.MGF1ParameterSpec; ++import java.security.interfaces.*; ++ ++import java.util.Arrays; ++import java.util.HashSet; ++import java.util.Locale; ++import java.util.Set; ++ ++import sun.security.rsa.PSSParameters; ++import sun.security.rsa.RSACore; ++import sun.security.jca.JCAUtil; ++ ++import javax.crypto.BadPaddingException; ++ ++/** ++ * PKCS#1 v2.2 RSASSA-PSS signatures with various message digest algorithms. ++ * RSASSA-PSS implementation takes the message digest algorithm, MGF algorithm, ++ * and salt length values through the required signature PSS parameters. ++ * We support SHA-1, SHA-224, SHA-256, SHA-384, SHA-512. ++ * The Openssl does not support rsa signatures with SHA-512/224 and SHA-512/256 as the digest algorithm, ++ * so we have not implemented them. ++ * The Openssl does not support non-CRT private key , when signing with a non-CRT private key, we use the sun sign. ++ */ ++@SuppressWarnings({"deprecation", "removal"}) ++public class KAERSAPSSSignature extends SignatureSpi { ++ // openssl unsupport rsa sign with digest algorithm ++ private static final Set UNSUPPORTED_DIGEST_ALGORITHM = new HashSet<>( ++ Arrays.asList("SHA-512/224", "SHA-512/256")); ++ ++ private static final byte[] EIGHT_BYTES_OF_ZEROS = new byte[8]; ++ ++ // message digest implementation we use for hashing the data ++ private MessageDigest md; ++ ++ // flag indicating whether the digest is reset ++ private boolean digestReset = true; ++ ++ // private key, if initialized for signing ++ private RSAPrivateKey privKey = null; ++ ++ // public key, if initialized for verifying ++ private RSAPublicKey pubKey = null; ++ ++ // PSS parameters from signatures and keys respectively ++ private PSSParameterSpec sigParams = null; ++ ++ // PRNG used to generate salt bytes if none given ++ private SecureRandom random; ++ ++ /** ++ * Construct a new RSAPSSSignatur with arbitrary digest algorithm ++ */ ++ public KAERSAPSSSignature() { ++ this.md = null; ++ } ++ ++ // initialize for verification. See JCA doc ++ @Override ++ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { ++ if (!(publicKey instanceof RSAPublicKey)) { ++ throw new InvalidKeyException("key must be RSAPublicKey"); ++ } ++ this.pubKey = (RSAPublicKey) isValid((RSAKey) publicKey); ++ this.privKey = null; ++ resetDigest(); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { ++ engineInitSign(privateKey, null); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { ++ if (!(privateKey instanceof RSAPrivateKey)) { ++ throw new InvalidKeyException("key must be RSAPrivateKey"); ++ } ++ this.privKey = (RSAPrivateKey) isValid((RSAKey) privateKey); ++ this.pubKey = null; ++ this.random = ++ (random == null ? JCAUtil.getSecureRandom() : random); ++ resetDigest(); ++ } ++ ++ /** ++ * Utility method for checking the key PSS parameters against signature ++ * PSS parameters. ++ * Returns false if any of the digest/MGF algorithms and trailerField ++ * values does not match or if the salt length in key parameters is ++ * larger than the value in signature parameters. ++ */ ++ private static boolean isCompatible(AlgorithmParameterSpec keyParams, PSSParameterSpec sigParams) { ++ if (keyParams == null) { ++ // key with null PSS parameters means no restriction ++ return true; ++ } ++ if (!(keyParams instanceof PSSParameterSpec)) { ++ return false; ++ } ++ // nothing to compare yet, defer the check to when sigParams is set ++ if (sigParams == null) { ++ return true; ++ } ++ PSSParameterSpec pssKeyParams = (PSSParameterSpec) keyParams; ++ // first check the salt length requirement ++ if (pssKeyParams.getSaltLength() > sigParams.getSaltLength()) { ++ return false; ++ } ++ ++ // compare equality of the rest of fields based on DER encoding ++ PSSParameterSpec keyParams2 = ++ new PSSParameterSpec(pssKeyParams.getDigestAlgorithm(), ++ pssKeyParams.getMGFAlgorithm(), ++ pssKeyParams.getMGFParameters(), ++ sigParams.getSaltLength(), ++ pssKeyParams.getTrailerField()); ++ ++ // skip the JCA overhead ++ try { ++ byte[] encoded = PSSParameters.getEncoded(keyParams2); ++ byte[] encoded2 = PSSParameters.getEncoded(sigParams); ++ return Arrays.equals(encoded, encoded2); ++ } catch (IOException e) { ++ return false; ++ } ++ } ++ ++ /** ++ * Validate the specified RSAKey and its associated parameters against ++ * internal signature parameters. ++ */ ++ private RSAKey isValid(RSAKey rsaKey) throws InvalidKeyException { ++ try { ++ AlgorithmParameterSpec keyParams = rsaKey.getParams(); ++ // validate key parameters ++ if (!isCompatible(rsaKey.getParams(), this.sigParams)) { ++ throw new InvalidKeyException ++ ("Key contains incompatible PSS parameter values"); ++ } ++ // validate key length ++ if (this.sigParams != null) { ++ Integer hLen = ++ KAEUtils.getDigestLength(this.sigParams.getDigestAlgorithm()); ++ if (hLen == null) { ++ throw new ProviderException("Unsupported digest algo: " + ++ this.sigParams.getDigestAlgorithm()); ++ } ++ checkKeyLength(rsaKey, hLen, this.sigParams.getSaltLength()); ++ } ++ return rsaKey; ++ } catch (SignatureException e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ /** ++ * Validate the specified Signature PSS parameters. ++ */ ++ private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p) throws InvalidAlgorithmParameterException { ++ if (p == null) { ++ throw new InvalidAlgorithmParameterException ++ ("Parameters cannot be null"); ++ } ++ if (!(p instanceof PSSParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("parameters must be type PSSParameterSpec"); ++ } ++ // no need to validate again if same as current signature parameters ++ PSSParameterSpec params = (PSSParameterSpec) p; ++ if (params == this.sigParams) { ++ return params; ++ } ++ ++ RSAKey key = (this.privKey == null ? this.pubKey : this.privKey); ++ // check against keyParams if set ++ if (key != null) { ++ if (!isCompatible(key.getParams(), params)) { ++ throw new InvalidAlgorithmParameterException ++ ("Signature parameters does not match key parameters"); ++ } ++ } ++ // now sanity check the parameter values ++ if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) { ++ throw new InvalidAlgorithmParameterException("Only supports MGF1"); ++ } ++ if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) { ++ throw new InvalidAlgorithmParameterException("Only supports TrailerFieldBC(1)"); ++ } ++ String digestAlgo = params.getDigestAlgorithm(); ++ // check key length again ++ if (key != null) { ++ try { ++ int hLen = KAEUtils.getDigestLength(digestAlgo); ++ checkKeyLength(key, hLen, params.getSaltLength()); ++ } catch (SignatureException e) { ++ throw new InvalidAlgorithmParameterException(e); ++ } ++ } ++ return params; ++ } ++ ++ /** ++ * Ensure the object is initialized with key and parameters and ++ * reset digest ++ */ ++ private void ensureInit() throws SignatureException { ++ RSAKey key = (this.privKey == null ? this.pubKey : this.privKey); ++ if (key == null) { ++ throw new SignatureException("Missing key"); ++ } ++ if (this.sigParams == null) { ++ // Parameters are required for signature verification ++ throw new SignatureException ++ ("Parameters required for RSASSA-PSS signatures"); ++ } ++ } ++ ++ /** ++ * Utility method for checking key length against digest length and ++ * salt length ++ */ ++ private static void checkKeyLength(RSAKey key, int digestLen, int saltLen) throws SignatureException { ++ if (key != null) { ++ int keyLength = getKeyLengthInBits(key) >> 3; ++ int minLength = Math.addExact(Math.addExact(digestLen, saltLen), 2); ++ if (keyLength < minLength) { ++ throw new SignatureException ++ ("Key is too short, need min " + minLength); ++ } ++ } ++ } ++ ++ /** ++ * Reset the message digest if it is not already reset. ++ */ ++ private void resetDigest() { ++ if (digestReset == false) { ++ this.md.reset(); ++ digestReset = true; ++ } ++ } ++ ++ /** ++ * Return the message digest value. ++ */ ++ private byte[] getDigestValue() { ++ digestReset = true; ++ return this.md.digest(); ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte b) throws SignatureException { ++ ensureInit(); ++ this.md.update(b); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { ++ ensureInit(); ++ this.md.update(b, off, len); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(ByteBuffer b) { ++ try { ++ ensureInit(); ++ } catch (SignatureException se) { ++ // hack for working around API bug ++ throw new RuntimeException(se.getMessage()); ++ } ++ this.md.update(b); ++ digestReset = false; ++ } ++ ++ // determine whether the digest is valid ++ private boolean isValidDigest() { ++ String digestName = this.md.getAlgorithm(); ++ if (UNSUPPORTED_DIGEST_ALGORITHM.contains(digestName.toUpperCase(Locale.ROOT))) { ++ return false; ++ } ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ String mgfDigestName = ""; ++ if (mgfParams != null) { ++ mgfDigestName = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } ++ return !UNSUPPORTED_DIGEST_ALGORITHM.contains(mgfDigestName.toUpperCase(Locale.ROOT)); ++ } ++ ++ // determine whether use kae sign ++ private boolean useKaeSign() { ++ return (privKey instanceof RSAPrivateCrtKey) && isValidDigest(); ++ } ++ ++ // sun sign ++ private byte[] sunSign(byte[] mHash) throws SignatureException { ++ try { ++ byte[] encoded = encodeSignature(mHash); ++ return RSACore.rsa(encoded, privKey, true); ++ } catch (GeneralSecurityException e) { ++ throw new SignatureException("Could not sign data", e); ++ } catch (IOException e) { ++ throw new SignatureException("Could not encode data", e); ++ } ++ } ++ ++ // kae sign ++ private byte[] kaeSign(byte[] mHash) throws SignatureException { ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.sigParams.getDigestAlgorithm()); ++ String mgfDigestName = kaeDigestName; ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ if (mgfParams != null) { ++ mgfDigestName = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } ++ String mgf1DigestName = KAEUtils.getKAEDigestName(mgfDigestName); ++ ++ RSAPrivateCrtKey privateCrtKey = (RSAPrivateCrtKey) privKey; ++ long keyAddress = KAERSACipher.nativeCreateRSAPrivateCrtKey( ++ privateCrtKey.getModulus().toByteArray(), ++ privateCrtKey.getPublicExponent().toByteArray(), ++ privateCrtKey.getPrivateExponent().toByteArray(), ++ privateCrtKey.getPrimeP().toByteArray(), ++ privateCrtKey.getPrimeQ().toByteArray(), ++ privateCrtKey.getPrimeExponentP().toByteArray(), ++ privateCrtKey.getPrimeExponentQ().toByteArray(), ++ privateCrtKey.getCrtCoefficient().toByteArray()); ++ byte[] bytes; ++ try { ++ bytes = KAERSASignatureNative.pssSign(keyAddress, kaeDigestName, mHash, ++ KAERSAPaddingType.PKCS1PssPadding.getId(), ++ mgf1DigestName, this.sigParams.getSaltLength()); ++ } catch (SignatureException e) { ++ throw e; ++ } finally { ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ return bytes; ++ } ++ ++ // sign the data and return the signature. See JCA doc ++ @Override ++ protected byte[] engineSign() throws SignatureException { ++ ensureInit(); ++ byte[] mHash = getDigestValue(); ++ if (useKaeSign()) { ++ return kaeSign(mHash); ++ } ++ return sunSign(mHash); ++ } ++ ++ // determine whether use kae verify ++ private boolean useKaeVerify() { ++ return isValidDigest(); ++ } ++ ++ // sun verify ++ private boolean sunVerify(byte[] mHash, byte[] sigBytes) throws SignatureException { ++ try { ++ byte[] decrypted = RSACore.rsa(sigBytes, this.pubKey); ++ return decodeSignature(mHash, decrypted); ++ } catch (javax.crypto.BadPaddingException e) { ++ // occurs if the app has used the wrong RSA public key ++ // or if sigBytes is invalid ++ // return false rather than propagating the exception for ++ // compatibility/ease of use ++ return false; ++ } catch (IOException e) { ++ throw new SignatureException("Signature encoding error", e); ++ } finally { ++ resetDigest(); ++ } ++ } ++ ++ // kae verify ++ private boolean kaeVerify(byte[] mHash, byte[] sigBytes) throws SignatureException { ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.sigParams.getDigestAlgorithm()); ++ String mgfDigestName = kaeDigestName; ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ if (mgfParams != null) { ++ mgfDigestName = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } ++ String mgf1KaeDigestName = KAEUtils.getKAEDigestName(mgfDigestName); ++ ++ long keyAddress = KAERSACipher.nativeCreateRSAPublicKey(this.pubKey.getModulus().toByteArray(), ++ this.pubKey.getPublicExponent().toByteArray()); ++ boolean verify; ++ try { ++ verify = KAERSASignatureNative.pssVerify(keyAddress, kaeDigestName, mHash, ++ KAERSAPaddingType.PKCS1PssPadding.getId(), mgf1KaeDigestName, ++ this.sigParams.getSaltLength(), sigBytes); ++ } catch (SignatureException e) { ++ throw e; ++ } catch (BadPaddingException e) { ++ // occurs if the app has used the wrong RSA public key ++ // or if sigBytes is invalid or sourceBytes is invalid ++ // return false rather than propagating the exception for ++ // compatibility/ease of use ++ return false; ++ } finally { ++ resetDigest(); ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ return verify; ++ } ++ ++ // verify the data and return the result. See JCA doc ++ // should be reset to the state after engineInitVerify call. ++ @Override ++ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { ++ ensureInit(); ++ if (sigBytes.length != RSACore.getByteLength(this.pubKey)) { ++ throw new SignatureException("Signature length not correct: got " + ++ sigBytes.length + " but was expecting " + ++ RSACore.getByteLength(this.pubKey)); ++ } ++ byte[] mHash = getDigestValue(); ++ if (useKaeVerify()) { ++ return kaeVerify(mHash, sigBytes); ++ } ++ return sunVerify(mHash, sigBytes); ++ } ++ ++ // return the modulus length in bits ++ private static int getKeyLengthInBits(RSAKey k) { ++ if (k != null) { ++ return k.getModulus().bitLength(); ++ } ++ return -1; ++ } ++ ++ /** ++ * Encode the digest 'mHash', return the to-be-signed data. ++ * Also used by the PKCS#11 provider. ++ */ ++ private byte[] encodeSignature(byte[] mHash) throws IOException, DigestException { ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ String mgfDigestAlgo; ++ if (mgfParams != null) { ++ mgfDigestAlgo = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } else { ++ mgfDigestAlgo = this.md.getAlgorithm(); ++ } ++ try { ++ int emBits = getKeyLengthInBits(this.privKey) - 1; ++ int emLen = (emBits + 7) >> 3; ++ int hLen = this.md.getDigestLength(); ++ int dbLen = emLen - hLen - 1; ++ int sLen = this.sigParams.getSaltLength(); ++ ++ // maps DB into the corresponding region of EM and ++ // stores its bytes directly into EM ++ byte[] em = new byte[emLen]; ++ ++ // step7 and some of step8 ++ em[dbLen - sLen - 1] = (byte) 1; // set DB's padding2 into EM ++ em[em.length - 1] = (byte) 0xBC; // set trailer field of EM ++ ++ if (!digestReset) { ++ throw new ProviderException("Digest should be reset"); ++ } ++ // step5: generates M' using padding1, mHash, and salt ++ this.md.update(EIGHT_BYTES_OF_ZEROS); ++ digestReset = false; // mark digest as it now has data ++ this.md.update(mHash); ++ if (sLen != 0) { ++ // step4: generate random salt ++ byte[] salt = new byte[sLen]; ++ this.random.nextBytes(salt); ++ this.md.update(salt); ++ ++ // step8: set DB's salt into EM ++ System.arraycopy(salt, 0, em, dbLen - sLen, sLen); ++ } ++ // step6: generate H using M' ++ this.md.digest(em, dbLen, hLen); // set H field of EM ++ digestReset = true; ++ ++ // step7 and 8 are already covered by the code which setting up ++ // EM as above ++ ++ // step9 and 10: feed H into MGF and xor with DB in EM ++ KAEMGF1 mgf1 = new KAEMGF1(mgfDigestAlgo); ++ mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0); ++ // step11: set the leftmost (8emLen - emBits) bits of the leftmost ++ // octet to 0 ++ int numZeroBits = (emLen << 3) - emBits; ++ if (numZeroBits != 0) { ++ byte mask = (byte) (0xff >>> numZeroBits); ++ em[0] = (byte) (em[0] & mask); ++ } ++ ++ // step12: em should now holds maskedDB || hash h || 0xBC ++ return em; ++ } catch (NoSuchAlgorithmException | RuntimeException e) { ++ e.printStackTrace(); ++ throw new IOException(e.toString()); ++ } ++ } ++ ++ private String getMgfDigestAlgo() { ++ String mgfDigestAlgo; ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ if (mgfParams != null) { ++ mgfDigestAlgo = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } else { ++ mgfDigestAlgo = this.md.getAlgorithm(); ++ } ++ return mgfDigestAlgo; ++ } ++ ++ private void generateAndXor(String mgfDigestAlgo, byte[] em, int dbLen, int hLen) throws IOException { ++ try { ++ KAEMGF1 mgf1 = new KAEMGF1(mgfDigestAlgo); ++ mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0); ++ } catch (NoSuchAlgorithmException | RuntimeException e) { ++ e.printStackTrace(); ++ throw new IOException(e.toString()); ++ } ++ } ++ ++ /** ++ * Decode the signature data. Verify that the object identifier matches ++ * and return the message digest. ++ */ ++ private boolean decodeSignature(byte[] mHash, byte[] em) throws IOException { ++ int hLen = mHash.length; ++ int sLen = this.sigParams.getSaltLength(); ++ int emLen = em.length; ++ int emBits = getKeyLengthInBits(this.pubKey) - 1; ++ ++ // step3 ++ if (emLen < (hLen + sLen + 2)) { ++ return false; ++ } ++ ++ // step4 ++ if (em[emLen - 1] != (byte) 0xBC) { ++ return false; ++ } ++ ++ // step6: check if the leftmost (8emLen - emBits) bits of the leftmost ++ // octet are 0 ++ int numZeroBits = (emLen << 3) - emBits; ++ if (numZeroBits != 0) { ++ byte mask = (byte) (0xff << (8 - numZeroBits)); ++ if ((em[0] & mask) != 0) { ++ return false; ++ } ++ } ++ ++ // step 7 and 8 ++ int dbLen = emLen - hLen - 1; ++ ++ // generateAndXor ++ String mgfDigestAlgo = getMgfDigestAlgo(); ++ generateAndXor(mgfDigestAlgo, em, dbLen, hLen); ++ ++ // step9: set the leftmost (8emLen - emBits) bits of the leftmost ++ // octet to 0 ++ if (numZeroBits != 0) { ++ byte mask = (byte) (0xff >>> numZeroBits); ++ em[0] = (byte) (em[0] & mask); ++ } ++ ++ // step10 ++ int index = 0; ++ for (; index < dbLen - sLen - 1; index++) { ++ if (em[index] != 0) { ++ return false; ++ } ++ } ++ if (em[index] != 0x01) { ++ return false; ++ } ++ // step12 and 13 ++ this.md.update(EIGHT_BYTES_OF_ZEROS); ++ digestReset = false; ++ this.md.update(mHash); ++ if (sLen > 0) { ++ this.md.update(em, (dbLen - sLen), sLen); ++ } ++ byte[] digest2 = this.md.digest(); ++ digestReset = true; ++ ++ // step14 ++ byte[] digestInEM = Arrays.copyOfRange(em, dbLen, emLen - 1); ++ return MessageDigest.isEqual(digest2, digestInEM); ++ } ++ ++ // set parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected void engineSetParameter(String param, Object value) throws InvalidParameterException { ++ throw new UnsupportedOperationException("setParameter() not supported"); ++ } ++ ++ @Override ++ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { ++ this.sigParams = validateSigParams(params); ++ // disallow changing parameters when digest has been used ++ if (!digestReset) { ++ throw new ProviderException ++ ("Cannot set parameters during operations"); ++ } ++ String newHashAlg = this.sigParams.getDigestAlgorithm(); ++ // re-allocate md if not yet assigned or algorithm changed ++ if ((this.md == null) || ++ !(this.md.getAlgorithm().equalsIgnoreCase(newHashAlg))) { ++ try { ++ this.md = MessageDigest.getInstance(newHashAlg); ++ } catch (NoSuchAlgorithmException nsae) { ++ // should not happen as we pick default digest algorithm ++ throw new InvalidAlgorithmParameterException("Unsupported digest algorithm " + newHashAlg, nsae); ++ } ++ } ++ } ++ ++ // get parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected Object engineGetParameter(String param) throws InvalidParameterException { ++ throw new UnsupportedOperationException("getParameter() not supported"); ++ } ++ ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ AlgorithmParameters ap = null; ++ if (this.sigParams != null) { ++ try { ++ ap = AlgorithmParameters.getInstance("RSASSA-PSS"); ++ ap.init(this.sigParams); ++ } catch (GeneralSecurityException gse) { ++ throw new ProviderException(gse.getMessage()); ++ } ++ } ++ return ap; ++ } ++} ++ +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +new file mode 100644 +index 000000000..35e7f2f67 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.util.Arrays; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.Set; ++ ++enum KAERSAPaddingType { ++ // raw RSA ++ PKCS1Padding(1, "PKCS1Padding"), ++ ++ // PKCS#1 v1.5 RSA ++ NoPadding(3, "NoPadding"), ++ ++ // PKCS#2 v2.2 OAEP with MGF1 ++ OAEP(4, "OAEP", new HashSet<>( ++ Arrays.asList( ++ "OAEPPADDING", ++ "OAEPWITHMD5ANDMGF1PADDING", ++ "OAEPWITHSHA1ANDMGF1PADDING", ++ "OAEPWITHMD5ANDMGF1PADDING", ++ "OAEPWITHSHA1ANDMGF1PADDING", ++ "OAEPWITHSHA-1ANDMGF1PADDING", ++ "OAEPWITHSHA-224ANDMGF1PADDING", ++ "OAEPWITHSHA-256ANDMGF1PADDING", ++ "OAEPWITHSHA-384ANDMGF1PADDING", ++ "OAEPWITHSHA-512ANDMGF1PADDING", ++ "OAEPWITHSHA-512/224ANDMGF1PADDING", ++ "OAEPWITHSHA-512/256ANDMGF1PADDING")) ++ ), ++ ++ // PSS ++ PKCS1PssPadding(6, "RSA_PKCS1_PSS_PADDING"); ++ ++ private final int id; ++ private final String name; ++ private final Set supportPaddings; ++ ++ public int getId() { ++ return id; ++ } ++ ++ public String getName() { ++ return name; ++ } ++ ++ KAERSAPaddingType(int id, String name) { ++ this(id, name, Collections.singleton(name)); ++ } ++ ++ KAERSAPaddingType(int id, String name, Set supportPaddings) { ++ this.id = id; ++ this.name = name; ++ this.supportPaddings = supportPaddings; ++ } ++ ++ public Set getSupportPaddings() { ++ return supportPaddings; ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java +new file mode 100644 +index 000000000..b91a8cdaa +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java +@@ -0,0 +1,365 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.io.IOException; ++import java.nio.ByteBuffer; ++ ++import java.security.*; ++import java.security.interfaces.*; ++import java.security.spec.AlgorithmParameterSpec; ++ ++import sun.security.rsa.RSACore; ++import sun.security.rsa.RSAKeyFactory; ++import sun.security.rsa.RSAPadding; ++import sun.security.rsa.RSAUtil; ++import sun.security.rsa.RSAUtil.KeyType; ++import sun.security.util.*; ++import sun.security.x509.AlgorithmId; ++ ++import javax.crypto.BadPaddingException; ++ ++/** ++ * We support support rsa signatures with MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 as the digest algorithm. ++ * The Openssl does not support rsa signatures with SHA-512/224 and SHA-512/256 as the digest algorithm, ++ * so we have not implemented them. ++ * The Openssl does not support non-CRT private key , when signing with a non-CRT private key, we use the sun sign. ++ */ ++public abstract class KAERSASignature extends SignatureSpi { ++ // we sign an ASN.1 SEQUENCE of AlgorithmId and digest ++ // it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest] ++ // this means the encoded length is (8 + digestOID.length + digest.length) ++ private static final int BASE_LENGTH = 8; ++ ++ private String digestAlgorithm; ++ ++ // object identifier for the message digest algorithm used ++ private final ObjectIdentifier digestOID; ++ ++ // length of the encoded signature blob ++ private final int encodedLength; ++ ++ // message digest implementation we use ++ private final MessageDigest md; ++ ++ // flag indicating whether the digest is reset ++ private boolean digestReset; ++ ++ // private key, if initialized for signing ++ private RSAPrivateKey privateKey; ++ ++ // public key, if initialized for verifying ++ private RSAPublicKey publicKey; ++ ++ // padding to use, set when the initSign/initVerify is called ++ private RSAPadding padding; ++ ++ /** ++ * Construct a new RSASignature. Used by subclasses. ++ */ ++ KAERSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) { ++ this.digestAlgorithm = algorithm; ++ this.digestOID = digestOID; ++ try { ++ md = MessageDigest.getInstance(algorithm); ++ } catch (NoSuchAlgorithmException e) { ++ throw new ProviderException(e); ++ } ++ digestReset = true; ++ encodedLength = BASE_LENGTH + oidLength + md.getDigestLength(); ++ } ++ ++ // initialize for verification. See JCA doc ++ @Override ++ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { ++ RSAPublicKey rsaKey = (RSAPublicKey) RSAKeyFactory.toRSAKey(publicKey); ++ this.privateKey = null; ++ this.publicKey = rsaKey; ++ initCommon(rsaKey, null); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { ++ engineInitSign(privateKey, null); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { ++ RSAPrivateKey rsaKey = ++ (RSAPrivateKey) RSAKeyFactory.toRSAKey(privateKey); ++ this.privateKey = rsaKey; ++ this.publicKey = null; ++ initCommon(rsaKey, random); ++ } ++ ++ /** ++ * Init code common to sign and verify. ++ */ ++ private void initCommon(RSAKey rsaKey, SecureRandom random) throws InvalidKeyException { ++ try { ++ RSAUtil.checkParamsAgainstType(KeyType.RSA, rsaKey.getParams()); ++ } catch (ProviderException e) { ++ throw new InvalidKeyException("Invalid key for RSA signatures", e); ++ } ++ resetDigest(); ++ int keySize = RSACore.getByteLength(rsaKey); ++ try { ++ padding = RSAPadding.getInstance ++ (RSAPadding.PAD_BLOCKTYPE_1, keySize, random); ++ } catch (InvalidAlgorithmParameterException iape) { ++ throw new InvalidKeyException(iape.getMessage()); ++ } ++ int maxDataSize = padding.getMaxDataSize(); ++ if (encodedLength > maxDataSize) { ++ throw new InvalidKeyException ++ ("Key is too short for this signature algorithm"); ++ } ++ } ++ ++ /** ++ * Reset the message digest if it is not already reset. ++ */ ++ private void resetDigest() { ++ if (digestReset == false) { ++ md.reset(); ++ digestReset = true; ++ } ++ } ++ ++ /** ++ * Return the message digest value. ++ */ ++ private byte[] getDigestValue() { ++ digestReset = true; ++ return md.digest(); ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte b) throws SignatureException { ++ md.update(b); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { ++ md.update(b, off, len); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(ByteBuffer b) { ++ md.update(b); ++ digestReset = false; ++ } ++ ++ // sign the data and return the signature. See JCA doc ++ @Override ++ protected byte[] engineSign() throws SignatureException { ++ if (privateKey == null) { ++ throw new SignatureException("Missing private key"); ++ } ++ ++ byte[] digest = getDigestValue(); ++ if (useKaeSign()) { ++ return kaeSign(digest); ++ } ++ return sunSign(digest); ++ } ++ ++ // determine if use kae sign , openssl do not support non-CRT private key ++ private boolean useKaeSign() { ++ return privateKey instanceof RSAPrivateCrtKey; ++ } ++ ++ // sun sign ++ private byte[] sunSign(byte[] digest) throws SignatureException { ++ try { ++ byte[] encoded = encodeSignature(digestOID, digest); ++ byte[] padded = padding.pad(encoded); ++ return RSACore.rsa(padded, privateKey, true); ++ } catch (GeneralSecurityException e) { ++ throw new SignatureException("Could not sign data", e); ++ } catch (IOException e) { ++ throw new SignatureException("Could not encode data", e); ++ } ++ } ++ ++ // kae sign ++ private byte[] kaeSign(byte[] digest) throws SignatureException { ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.digestAlgorithm); ++ RSAPrivateCrtKey privateCrtKey = (RSAPrivateCrtKey) privateKey; ++ long keyAddress = KAERSACipher.nativeCreateRSAPrivateCrtKey( ++ privateCrtKey.getModulus().toByteArray(), ++ privateCrtKey.getPublicExponent().toByteArray(), ++ privateCrtKey.getPrivateExponent().toByteArray(), ++ privateCrtKey.getPrimeP().toByteArray(), ++ privateCrtKey.getPrimeQ().toByteArray(), ++ privateCrtKey.getPrimeExponentP().toByteArray(), ++ privateCrtKey.getPrimeExponentQ().toByteArray(), ++ privateCrtKey.getCrtCoefficient().toByteArray()); ++ byte[] sigBytes; ++ try { ++ sigBytes = KAERSASignatureNative.rsaSign(keyAddress, ++ kaeDigestName, digest, KAERSAPaddingType.PKCS1Padding.getId()); ++ } catch (SignatureException e) { ++ throw e; ++ } finally { ++ // free keyAddress ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ return sigBytes; ++ } ++ ++ // verify the data and return the result. See JCA doc ++ @Override ++ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { ++ if (publicKey == null) { ++ throw new SignatureException("Missing public key"); ++ } ++ ++ boolean verify; ++ long keyAddress = 0L; ++ try { ++ if (sigBytes.length != RSACore.getByteLength(publicKey)) { ++ throw new SignatureException("Signature length not correct: got " + ++ sigBytes.length + " but was expecting " + ++ RSACore.getByteLength(publicKey)); ++ } ++ ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.digestAlgorithm); ++ byte[] digest = getDigestValue(); ++ keyAddress = KAERSACipher.nativeCreateRSAPublicKey(publicKey.getModulus().toByteArray(), ++ publicKey.getPublicExponent().toByteArray()); ++ verify = KAERSASignatureNative.rsaVerify(keyAddress, ++ kaeDigestName, digest, KAERSAPaddingType.PKCS1Padding.getId(), sigBytes); ++ } catch (SignatureException e) { ++ throw e; ++ } catch (BadPaddingException e) { ++ // occurs if the app has used the wrong RSA public key ++ // or if sigBytes is invalid or sourceBytes is invalid ++ // return false rather than propagating the exception for ++ // compatibility/ease of use ++ return false; ++ } finally { ++ // reset digest ++ resetDigest(); ++ // free keyAddress ++ if (keyAddress != 0L) { ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ } ++ return verify; ++ } ++ ++ /** ++ * Encode the digest, return the to-be-signed data. ++ * Also used by the PKCS#11 provider. ++ */ ++ public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest) throws IOException { ++ DerOutputStream out = new DerOutputStream(); ++ new AlgorithmId(oid).encode(out); ++ out.putOctetString(digest); ++ DerValue result = ++ new DerValue(DerValue.tag_Sequence, out.toByteArray()); ++ return result.toByteArray(); ++ } ++ ++ // set parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected void engineSetParameter(String param, Object value) throws InvalidParameterException { ++ throw new UnsupportedOperationException("setParameter() not supported"); ++ } ++ ++ // See JCA doc ++ @Override ++ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("No parameters accepted"); ++ } ++ } ++ ++ // get parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected Object engineGetParameter(String param) throws InvalidParameterException { ++ throw new UnsupportedOperationException("getParameter() not supported"); ++ } ++ ++ // See JCA doc ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ return null; ++ } ++ ++ // Nested class for MD5withRSA signatures ++ public static final class MD5withRSA extends KAERSASignature { ++ public MD5withRSA() { ++ super("MD5", AlgorithmId.MD5_oid, 10); ++ } ++ } ++ ++ // Nested class for SHA1withRSA signatures ++ public static final class SHA1withRSA extends KAERSASignature { ++ public SHA1withRSA() { ++ super("SHA-1", AlgorithmId.SHA_oid, 7); ++ } ++ } ++ ++ // Nested class for SHA224withRSA signatures ++ public static final class SHA224withRSA extends KAERSASignature { ++ public SHA224withRSA() { ++ super("SHA-224", AlgorithmId.SHA224_oid, 11); ++ } ++ } ++ ++ // Nested class for SHA256withRSA signatures ++ public static final class SHA256withRSA extends KAERSASignature { ++ public SHA256withRSA() { ++ super("SHA-256", AlgorithmId.SHA256_oid, 11); ++ } ++ } ++ ++ // Nested class for SHA384withRSA signatures ++ public static final class SHA384withRSA extends KAERSASignature { ++ public SHA384withRSA() { ++ super("SHA-384", AlgorithmId.SHA384_oid, 11); ++ } ++ } ++ ++ // Nested class for SHA512withRSA signatures ++ public static final class SHA512withRSA extends KAERSASignature { ++ public SHA512withRSA() { ++ super("SHA-512", AlgorithmId.SHA512_oid, 11); ++ } ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java +new file mode 100644 +index 000000000..dda2f068d +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.BadPaddingException; ++import java.security.SignatureException; ++ ++public class KAERSASignatureNative { ++ // rsa sign ++ protected static native byte[] rsaSign(long keyAddress, String digestName, byte[] digestBytes, int paddingType) ++ throws SignatureException; ++ ++ // rsa verify ++ protected static native boolean rsaVerify(long keyAddress, String digestName, byte[] digestBytes, int paddingType, ++ byte[] sigBytes) throws SignatureException, BadPaddingException; ++ ++ // rsa pss sign ++ protected static native byte[] pssSign(long keyAddress, String digestName, byte[] digestBytes, int paddingType, ++ String mgf1DigestName, int saltLen) throws SignatureException; ++ ++ // rsa pss verify ++ protected static native boolean pssVerify(long keyAddress, String digestName, byte[] digestBytes, int paddingType, ++ String mgf1DigestName, int saltLen, byte[] sigBytes) throws SignatureException, BadPaddingException; ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java +new file mode 100644 +index 000000000..a3e47606d +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java +@@ -0,0 +1,370 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.Debug; ++ ++import java.nio.ByteBuffer; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidKeyException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Key; ++import java.security.ProviderException; ++import java.util.Locale; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.ShortBufferException; ++ ++/* ++ * This class currently supports: ++ * - SM4/ECB/NOPADDING ++ * - SM4/ECB/PKCS5PADDING ++ * - SM4/CBC/NOPADDING ++ * - SM4/CBC/PKCS5PADDING ++ * - SM4/CTR/NOPADDING ++ * - SM4/OFB/NOPADDING ++ * - SM4/OFB/PKCS5PADDING ++ */ ++abstract class KAESM4Cipher extends KAESymmetricCipherBase { ++ ++ private static final Debug debug = Debug.getInstance("kae"); ++ ++ /* ++ * SM4 max chunk size of each encryption or decryption ++ * when input data does not have an accessible byte[] ++ */ ++ private static final int DEFAULT_KAE_SM4_MAX_CHUNK_SIZE = 4096; ++ private static int KAE_SM4_MAX_CHUNK_SIZE; ++ static { ++ initSM4MaxChunkSize(); ++ } ++ ++ private static void initSM4MaxChunkSize() { ++ String maxChunkSize = KAEConfig.privilegedGetOverridable("kae.sm4.maxChunkSize", ++ DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ""); ++ try { ++ KAE_SM4_MAX_CHUNK_SIZE = Integer.parseInt(maxChunkSize); ++ } catch (NumberFormatException e) { ++ // When parsing string argument to signed decimal integer fails, uses the default chunk size (4096) ++ KAE_SM4_MAX_CHUNK_SIZE = DEFAULT_KAE_SM4_MAX_CHUNK_SIZE; ++ if (debug != null) { ++ debug.println("The configured block size (" + maxChunkSize + ") cannot be converted to an integer, " + ++ "uses the default chunk size (" + DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ")"); ++ e.printStackTrace(); ++ } ++ return; ++ } ++ // when the configured chunk size is less than or equal to 0, uses the default chunk size (4096) ++ if (KAE_SM4_MAX_CHUNK_SIZE <= 0) { ++ KAE_SM4_MAX_CHUNK_SIZE = DEFAULT_KAE_SM4_MAX_CHUNK_SIZE; ++ if (debug != null) { ++ debug.println("The configured chunk size (" + KAE_SM4_MAX_CHUNK_SIZE + ") is less than " + ++ "or equal to 0, uses the default chunk size (" + DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ")"); ++ } ++ return; ++ } ++ if (debug != null) { ++ debug.println("The configured chunk size is " + KAE_SM4_MAX_CHUNK_SIZE); ++ } ++ } ++ ++ /** ++ * Used by the engineUpdate(ByteBuffer, ByteBuffer) and ++ * engineDoFinal(ByteBuffer, ByteBuffer) methods. ++ */ ++ private static int getSM4MaxChunkSize(int totalSize) { ++ return Math.min(KAE_SM4_MAX_CHUNK_SIZE, totalSize); ++ } ++ ++ public static class Sm4 extends KAESM4Cipher { ++ public Sm4(Mode mode, Padding padding) { ++ super(mode, padding, 16); ++ } ++ ++ public static class Cbc extends Sm4 { ++ public Cbc(Padding padding) { ++ super(Mode.CBC, padding); ++ } ++ public static class NoPadding extends Cbc { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Cbc { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ ++ public static class Ecb extends Sm4 { ++ public Ecb(Padding padding) { ++ super(Mode.ECB, padding); ++ } ++ public static class NoPadding extends Ecb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ecb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ ++ public static class Ctr extends Sm4 { ++ public Ctr(Padding padding) { ++ super(Mode.CTR, padding); ++ } ++ public static class NoPadding extends Ctr { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ } ++ ++ public static class Ofb extends Sm4 { ++ public Ofb(Padding padding) { ++ super(Mode.OFB, padding); ++ } ++ public static class NoPadding extends Ofb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ofb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ } ++ ++ KAESM4Cipher(Mode mode, Padding padding, int fixedKeySize) { ++ super(mode, padding, fixedKeySize, "SM4"); ++ } ++ ++ protected void checkKey(Key key) throws InvalidKeyException { ++ if (key == null || key.getEncoded() == null) { ++ throw new InvalidKeyException("Key cannot be null"); ++ } else { ++ int keyLen = key.getEncoded().length; ++ if (keyLen != fixedKeySize) { ++ throw new InvalidKeyException("Only " + fixedKeySize + "-byte keys are accepted. Got: " + keyLen); ++ } ++ } ++ } ++ ++ protected String getCipherName(int keyLength, Mode mode) { ++ return "sm4" + "-" + mode.toString().toLowerCase(Locale.US); ++ } ++ ++ @Override ++ protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException { ++ if (modeStr == null) { ++ throw new NoSuchAlgorithmException("null mode"); ++ } ++ ++ if (modeStr.equalsIgnoreCase("ECB")) { ++ mode = Mode.ECB; ++ } else if (modeStr.equalsIgnoreCase("CBC")) { ++ mode = Mode.CBC; ++ } else if (modeStr.equalsIgnoreCase("CTR")) { ++ mode = Mode.CTR; ++ } else if (modeStr.equalsIgnoreCase("OFB")) { ++ mode = Mode.OFB; ++ } else { ++ throw new NoSuchAlgorithmException("Unsupported mode " + mode); ++ } ++ } ++ ++ @Override ++ protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException { ++ if (paddingStr == null) { ++ throw new NoSuchPaddingException("null padding"); ++ } ++ if (paddingStr.equalsIgnoreCase("PKCS7PADDING")) { ++ paddingStr = "PKCS5Padding"; ++ } ++ ++ if (paddingStr.equalsIgnoreCase("NOPADDING")) { ++ this.padding = Padding.NOPADDING; ++ } else if(paddingStr.equalsIgnoreCase("PKCS5PADDING")) { ++ if (mode == Mode.CTR) { ++ throw new NoSuchPaddingException("PKCS#5 padding not supported with CTR mode"); ++ } ++ this.padding = Padding.PKCS5PADDING; ++ } else { ++ throw new NoSuchPaddingException("Unsupported padding " + paddingStr); ++ } ++ } ++ ++ @Override ++ protected int engineUpdate(ByteBuffer input, ByteBuffer output) throws ShortBufferException { ++ try { ++ return bufferCrypt(input, output, true); ++ } catch (IllegalBlockSizeException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } catch (BadPaddingException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } ++ } ++ ++ @Override ++ protected int engineDoFinal(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { ++ return bufferCrypt(input, output, false); ++ } ++ ++ /** ++ * Implementation for encryption using ByteBuffers. Used for both ++ * engineUpdate() and engineDoFinal(). ++ */ ++ private int bufferCrypt(ByteBuffer input, ByteBuffer output, ++ boolean isUpdate) throws ShortBufferException, ++ IllegalBlockSizeException, BadPaddingException { ++ if ((input == null) || (output == null)) { ++ throw new NullPointerException ++ ("Input and output buffers must not be null"); ++ } ++ int inPos = input.position(); ++ int inLimit = input.limit(); ++ int inLen = inLimit - inPos; ++ if (isUpdate && (inLen == 0)) { ++ return 0; ++ } ++ int outLenNeeded = engineGetOutputSize(inLen); ++ ++ if (output.remaining() < outLenNeeded) { ++ throw new ShortBufferException("Need at least " + outLenNeeded ++ + " bytes of space in output buffer"); ++ } ++ ++ // detecting input and output buffer overlap may be tricky ++ // we can only write directly into output buffer when we ++ // are 100% sure it's safe to do so ++ ++ boolean a1 = input.hasArray(); ++ boolean a2 = output.hasArray(); ++ int total = 0; ++ ++ if (a1) { // input has an accessible byte[] ++ byte[] inArray = input.array(); ++ int inOfs = input.arrayOffset() + inPos; ++ ++ byte[] outArray; ++ if (a2) { // output has an accessible byte[] ++ outArray = output.array(); ++ int outPos = output.position(); ++ int outOfs = output.arrayOffset() + outPos; ++ ++ // check array address and offsets and use temp output buffer ++ // if output offset is larger than input offset and ++ // falls within the range of input data ++ boolean useTempOut = false; ++ if (inArray == outArray && ++ ((inOfs < outOfs) && (outOfs < inOfs + inLen))) { ++ useTempOut = true; ++ outArray = new byte[outLenNeeded]; ++ outOfs = 0; ++ } ++ if (isUpdate) { ++ total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs); ++ } else { ++ total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs); ++ } ++ if (useTempOut) { ++ output.put(outArray, outOfs, total); ++ } else { ++ // adjust output position manually ++ output.position(outPos + total); ++ } ++ } else { // output does not have an accessible byte[] ++ if (isUpdate) { ++ outArray = engineUpdate(inArray, inOfs, inLen); ++ } else { ++ outArray = engineDoFinal(inArray, inOfs, inLen); ++ } ++ if (outArray != null && outArray.length != 0) { ++ output.put(outArray); ++ total = outArray.length; ++ } ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } else { // input does not have an accessible byte[] ++ // have to assume the worst, since we have no way of determine ++ // if input and output overlaps or not ++ byte[] tempOut = new byte[outLenNeeded]; ++ int outOfs = 0; ++ ++ byte[] tempIn = new byte[getSM4MaxChunkSize(inLen)]; ++ do { ++ int chunk = Math.min(inLen, tempIn.length); ++ if (chunk > 0) { ++ input.get(tempIn, 0, chunk); ++ } ++ int n; ++ if (isUpdate || (inLen > chunk)) { ++ n = engineUpdate(tempIn, 0, chunk, tempOut, outOfs); ++ } else { ++ n = engineDoFinal(tempIn, 0, chunk, tempOut, outOfs); ++ } ++ outOfs += n; ++ total += n; ++ inLen -= chunk; ++ } while (inLen > 0); ++ if (total > 0) { ++ output.put(tempOut, 0, total); ++ } ++ } ++ ++ return total; ++ } ++ ++ protected void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException { ++ if (ivBytes == null) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: iv is null "); ++ } ++ if (mode == Mode.CTR) { ++ // For compatibility, SM4 CTR allows 8 < IV < blockSize, the remaining bytes will be filled with 0 in engineInit ++ if (ivBytes.length < 8 || ivBytes.length > blockSize) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: CTR mode requires IV of at least" + ++ "8 bytes, and no greater than " + blockSize + "bytes"); ++ } ++ return; ++ } ++ if (ivBytes.length != blockSize) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + blockSize + " bytes long."); ++ } ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java +new file mode 100644 +index 000000000..3f60e804f +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei in the LICENSE file that accompanied this code. ++ * ++ * 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 visit https://gitee.com/openeuler/bgmprovider if you need additional ++ * information or have any questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.KeyGeneratorSpi; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.SecureRandom; ++import java.security.spec.AlgorithmParameterSpec; ++ ++public class KAESM4KeyGenerator extends KeyGeneratorSpi { ++ private byte[] key; ++ private int keySize = 16; // default keysize (in number of bytes) ++ private SecureRandom random; ++ ++ @Override ++ protected void engineInit(SecureRandom random) { ++ this.random = random; ++ } ++ ++ @Override ++ protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ throw new InvalidAlgorithmParameterException ++ ("SM4 key generation does not take any parameters"); ++ } ++ ++ @Override ++ protected void engineInit(int keysize, SecureRandom random) { ++ if (keysize != 128) { ++ throw new InvalidParameterException("SM4 requires a 128 bit key"); ++ } ++ this.keySize = keysize / 8; ++ engineInit(random); ++ } ++ ++ private static class SecureRandomHolder { ++ static final SecureRandom RANDOM = new SecureRandom(); ++ } ++ ++ @Override ++ protected SecretKey engineGenerateKey() { ++ key = new byte[keySize]; ++ if (random == null) { ++ random = SecureRandomHolder.RANDOM; ++ } ++ random.nextBytes(key); ++ return new SecretKeySpec(key, "SM4"); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java +new file mode 100644 +index 000000000..7b5433b38 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java +@@ -0,0 +1,791 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.jca.JCAUtil; ++ ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.nio.ByteBuffer; ++import java.security.*; ++import java.security.spec.*; ++import java.util.Arrays; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++import javax.crypto.*; ++import javax.crypto.spec.GCMParameterSpec; ++import javax.crypto.spec.IvParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/* ++ * Cipher wrapper class utilizing openssl APIs. ++ */ ++abstract class KAESymmetricCipherBase extends CipherSpi { ++ enum Padding { ++ NOPADDING, ++ PKCS5PADDING ++ } ++ ++ enum Mode { ++ ECB, ++ CBC, ++ CTR, ++ OFB, ++ GCM ++ } ++ ++ protected final String keyAlgo; ++ protected final int blockSize = 16; ++ protected Mode mode; ++ protected Padding padding; ++ protected int fixedKeySize; ++ ++ private CipherContextRef pCtx = null; ++ private byte[] keyValue; ++ protected byte[] iv; ++ private boolean initialized = false; ++ private boolean encrypt = false; ++ private int bytesBuffered = 0; ++ ++ private boolean calledUpdate; ++ private String cipherName; ++ ++ // for gcm ++ private final int defaultGcmTagLen = blockSize; ++ private final int defaultGcmIvLen = 12; ++ private int tagLengthInBytes; ++ private byte[] lastEncKey = null; ++ private byte[] lastEncIv = null; ++ private byte[] aad; ++ ++ private static PublicKey constructPublicKey(byte[] encodedKey, String encodedKeyAlgorithm) ++ throws NoSuchAlgorithmException, InvalidKeyException { ++ PublicKey key; ++ try { ++ KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm); ++ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); ++ key = keyFactory.generatePublic(keySpec); ++ } catch (NoSuchAlgorithmException e) { ++ throw new NoSuchAlgorithmException("No provider found for " + encodedKeyAlgorithm + " KeyFactory"); ++ } catch (InvalidKeySpecException e) { ++ throw new InvalidKeyException("Cannot construct public key", e); ++ } ++ return key; ++ } ++ ++ private static PrivateKey constructPrivateKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException { ++ PrivateKey key = null; ++ try { ++ KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm); ++ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); ++ key = keyFactory.generatePrivate(keySpec); ++ } catch (NoSuchAlgorithmException e) { ++ throw new NoSuchAlgorithmException("No provider found for " + encodedKeyAlgorithm + " KeyFactory"); ++ } catch (InvalidKeySpecException e) { ++ throw new InvalidKeyException("Cannot construct private key", e); ++ } ++ return key; ++ } ++ ++ private static SecretKey constructSecretKey(byte[] encodedKey, String encodedKeyAlgorithm) { ++ return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); ++ } ++ ++ static final Key constructKey(int keyType, byte[] encodedKey, ++ String encodedKeyAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException { ++ Key res = null; ++ switch (keyType) { ++ case Cipher.SECRET_KEY: ++ res = constructSecretKey(encodedKey, encodedKeyAlgorithm); ++ break; ++ case Cipher.PRIVATE_KEY: ++ res = constructPrivateKey(encodedKey, encodedKeyAlgorithm); ++ break; ++ case Cipher.PUBLIC_KEY: ++ res = constructPublicKey(encodedKey, encodedKeyAlgorithm); ++ break; ++ default: ++ throw new InvalidKeyException("Unknown keytype " + keyType); ++ } ++ return res; ++ } ++ ++ KAESymmetricCipherBase(Mode mode, Padding padding, int fixedKeySize, String keyAlgo) { ++ this.mode = mode; ++ this.padding = padding; ++ this.fixedKeySize = fixedKeySize; ++ this.keyAlgo = keyAlgo; ++ } ++ ++ private static class CipherContextRef extends PhantomReference ++ implements Comparable { ++ private static ReferenceQueue refQueue = new ReferenceQueue<>(); ++ private static Set refList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ final long ctxAddress; ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ CipherContextRef next = (CipherContextRef) refQueue.poll(); ++ if (next == null) { ++ break; ++ } ++ next.dispose(true); ++ } ++ } ++ ++ CipherContextRef(KAESymmetricCipherBase kaeCipher, long ctxAddress) { ++ super(kaeCipher, refQueue); ++ this.ctxAddress = ctxAddress; ++ if (!disableKaeDispose) { ++ refList.add(this); ++ drainRefQueueBounded(); ++ } ++ } ++ ++ @Override ++ public int compareTo(CipherContextRef o) { ++ if (this.ctxAddress == o.ctxAddress) { ++ return 0; ++ } else { ++ return (this.ctxAddress < o.ctxAddress) ? -1 : 1; ++ } ++ } ++ ++ void dispose(boolean needFree) { ++ if (!disableKaeDispose) { ++ refList.remove(this); ++ try { ++ if (needFree) { ++ nativeFree(ctxAddress); ++ } ++ } finally { ++ this.clear(); ++ } ++ } else { ++ nativeFree(ctxAddress); ++ } ++ } ++ } ++ ++ @Override ++ protected int engineGetBlockSize() { ++ return blockSize; ++ } ++ ++ @Override ++ protected int engineGetOutputSize(int inputLen) { ++ return getOutputSizeByOperation(inputLen, true); ++ } ++ ++ @Override ++ protected byte[] engineGetIV() { ++ return iv == null ? null : iv.clone(); ++ } ++ ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ if (iv == null) { ++ return null; ++ } ++ AlgorithmParameterSpec spec; ++ AlgorithmParameters params; ++ String algName = keyAlgo; ++ if (mode == Mode.GCM) { ++ algName = "GCM"; ++ spec = new GCMParameterSpec(tagLengthInBytes * 8, iv.clone()); ++ } else { ++ spec = new IvParameterSpec(iv.clone()); ++ } ++ try { ++ params = AlgorithmParameters.getInstance(algName); ++ params.init(spec); ++ return params; ++ } catch (GeneralSecurityException e) { ++ throw new RuntimeException("Could not encode parameters", e); ++ } ++ } ++ ++ @Override ++ protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { ++ try { ++ engineInit(opmode, key, (AlgorithmParameterSpec) null, random); ++ } catch (InvalidAlgorithmParameterException e) { ++ throw new InvalidKeyException("init() failed", e); ++ } ++ } ++ ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameters params, ++ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { ++ AlgorithmParameterSpec spec = null; ++ String paramType = null; ++ if (params != null) { ++ try { ++ if (mode == Mode.GCM) { ++ spec = params.getParameterSpec(GCMParameterSpec.class); ++ paramType = "GCM"; ++ } else { ++ spec = params.getParameterSpec(IvParameterSpec.class); ++ paramType = "IV"; ++ } ++ } catch (InvalidParameterSpecException e) { ++ throw new InvalidAlgorithmParameterException("Could not decode " + paramType, e); ++ } ++ } ++ engineInit(opmode, key, spec, random); ++ } ++ ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, ++ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { ++ checkKey(key); ++ boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); ++ ++ byte[] ivBytes = null; ++ int tagLen = -1; ++ if (params != null) { ++ if (mode == Mode.GCM) { ++ if (params instanceof GCMParameterSpec) { ++ tagLen = ((GCMParameterSpec)params).getTLen(); ++ checkTagLen(tagLen); ++ tagLen = tagLen >> 3; ++ ivBytes = ((GCMParameterSpec)params).getIV(); ++ } else { ++ throw new InvalidAlgorithmParameterException("Unsupported parameter: " + params); ++ } ++ } else { ++ if (params instanceof IvParameterSpec) { ++ ivBytes = ((IvParameterSpec) params).getIV(); ++ checkIvBytes(ivBytes); ++ } else { ++ throw new InvalidKeyException("IvParameterSpec required. Received: " + params.getClass().getName()); ++ } ++ } ++ } ++ if (mode == Mode.ECB) { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("No Parameters for ECB mode"); ++ } ++ } else if (ivBytes == null) { ++ if (doEncrypt) { ++ if (mode == Mode.GCM) { ++ ivBytes = new byte[defaultGcmIvLen]; ++ } else { ++ ivBytes = new byte[blockSize]; ++ } ++ if (random == null) { ++ random = JCAUtil.getSecureRandom(); ++ } ++ random.nextBytes(ivBytes); ++ } else { ++ throw new InvalidAlgorithmParameterException("Parameters required for decryption"); ++ } ++ } else if (keyAlgo.equalsIgnoreCase("SM4") && ivBytes.length < blockSize) { ++ byte[] temp = new byte[blockSize]; ++ System.arraycopy(ivBytes, 0, temp, 0, ivBytes.length); ++ ivBytes = temp; ++ } ++ implInit(doEncrypt, key.getEncoded(), ivBytes, tagLen); ++ } ++ ++ private void checkTagLen(int tagLen) throws InvalidAlgorithmParameterException { ++ if ((tagLen < 96) || (tagLen > 128) || ((tagLen & 0x07) != 0)) { ++ throw new InvalidAlgorithmParameterException ++ ("Unsupported TLen value; must be one of {128, 120, 112, 104, 96}"); ++ } ++ } ++ ++ protected abstract void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException; ++ ++ protected abstract String getCipherName(int keyLength, Mode mode); ++ ++ private void implInit(boolean encrypt, byte[] keyVal, byte[] ivVal, int tagLen) ++ throws InvalidAlgorithmParameterException { ++ reset(true); ++ this.encrypt = encrypt; ++ this.keyValue = keyVal; ++ this.iv = ivVal; ++ this.cipherName = getCipherName(keyValue.length * 8, mode); ++ ++ if (mode == Mode.GCM) { ++ if (tagLen == -1) { ++ tagLen = defaultGcmTagLen; ++ } ++ this.tagLengthInBytes = tagLen; ++ if (encrypt) { ++ // Check key+iv for encryption in GCM mode. ++ boolean requireReinit = Arrays.equals(ivVal, lastEncIv) && MessageDigest.isEqual(keyVal, lastEncKey); ++ if (requireReinit) { ++ throw new InvalidAlgorithmParameterException("Cannot reuse iv for GCM encryption"); ++ } ++ lastEncIv = ivVal; ++ lastEncKey = keyVal; ++ } ++ } ++ ++ // OpenSSL only supports PKCS5 Padding. ++ long pCtxVal; ++ try { ++ pCtxVal = nativeInit(cipherName, encrypt, keyValue, iv, padding == Padding.PKCS5PADDING); ++ } catch (RuntimeException e) { ++ throw new ProviderException("Invoke nativeInit failed for " + cipherName, e); ++ } ++ ++ initialized = (pCtxVal != 0L); ++ if (initialized) { ++ pCtx = new CipherContextRef(this, pCtxVal); ++ } else { ++ throw new NullPointerException("pCtxVal == 0"); ++ } ++ calledUpdate = false; ++ } ++ ++ protected abstract void checkKey(Key key) throws InvalidKeyException; ++ ++ @Override ++ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { ++ byte[] out = new byte[getOutputSizeByOperation(inputLen, false)]; ++ int outLen = implUpdate(input, inputOffset, inputLen, out, 0); ++ if (outLen == 0) { ++ return new byte[0]; ++ } else if (out.length != outLen) { ++ out = Arrays.copyOf(out, outLen); ++ } ++ return out; ++ } ++ ++ @Override ++ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, ++ int outputOffset) throws ShortBufferException { ++ int min = getOutputSizeByOperation(inputLen, false); ++ if (output == null || output.length - outputOffset < min) { ++ throw new ShortBufferException("min " + min + "-byte buffer needed"); ++ } ++ return implUpdate(input, inputOffset, inputLen, output, outputOffset); ++ } ++ ++ private int implUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { ++ ensureInitialized(); ++ if (inputLen <= 0) { ++ return 0; ++ } ++ int outLen; ++ try { ++ outLen = nativeUpdate(pCtx.ctxAddress, input, inputOffset, inputLen, output, outputOffset, ++ mode == Mode.GCM, aad); ++ aad = null; ++ } catch (ArrayIndexOutOfBoundsException e) { ++ reset(true); ++ throw new ProviderException("Invoke nativeUpdate failed for " + cipherName, e); ++ } ++ bytesBuffered += (inputLen - outLen); ++ ++ calledUpdate = true; ++ return outLen; ++ } ++ ++ protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) { ++ int ret; ++ ++ if (inLen <= 0) { ++ inLen = 0; ++ } ++ if (padding == Padding.NOPADDING) { ++ ret = inLen + bytesBuffered; ++ } else { ++ int len = inLen + bytesBuffered; ++ ++ // The amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1) for encrypt. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CipherUpdate.html} for details. ++ len += (len % blockSize != 0 || encrypt) ? blockSize : 0; ++ ret = len - (len % blockSize); ++ } ++ if (mode == Mode.GCM && isDoFinal) { ++ if (encrypt) { ++ ret = ret + tagLengthInBytes; ++ } else { ++ ret = Math.max(0, ret - tagLengthInBytes); ++ } ++ } ++ return ret; ++ } ++ ++ @Override ++ protected byte[] engineDoFinal(byte[] input, int inputOffset, ++ int inputLen) throws IllegalBlockSizeException, BadPaddingException { ++ byte[] out = new byte[getOutputSizeByOperation(inputLen, true)]; ++ try { ++ int outLen = engineDoFinal(input, inputOffset, inputLen, out, 0); ++ if (out.length != outLen) { ++ out = Arrays.copyOf(out, outLen); ++ } ++ return out; ++ } catch (ShortBufferException e) { ++ throw new ProviderException(e); ++ } ++ } ++ ++ @Override ++ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, ++ int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { ++ int outLen = 0; ++ int min = getOutputSizeByOperation(inputLen, true); ++ if (output == null || output.length - outputOffset < min) { ++ throw new ShortBufferException("min " + min + "-byte buffer needed"); ++ } ++ ++ int updateLen = inputLen; ++ if (mode == Mode.GCM && !encrypt) { ++ // Remove tagLengthInBytes suffix in GCM decrypt. ++ updateLen = inputLen - tagLengthInBytes; ++ } ++ outLen = implUpdate(input, inputOffset, updateLen, output, outputOffset); ++ outputOffset += outLen; ++ ++ byte[] gcmTag = null; ++ if (mode == Mode.GCM && !encrypt) { ++ if (inputLen - outLen != tagLengthInBytes) { ++ throw new AEADBadTagException("Tag mismatch!"); ++ } ++ // The last tagLengthInBytees in the input arg gcmTag. ++ gcmTag = Arrays.copyOfRange(input, inputOffset + inputLen - tagLengthInBytes, inputOffset + inputLen); ++ } ++ ++ outLen += implDoFinal(output, outputOffset, gcmTag); ++ return outLen; ++ } ++ ++ @Override ++ protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { ++ byte[] res = null; ++ try { ++ byte[] encodedKey = key.getEncoded(); ++ if (encodedKey == null || encodedKey.length == 0) { ++ throw new InvalidKeyException("Cannot get an encoding of the key to be wrapped"); ++ } ++ res = engineDoFinal(encodedKey, 0, encodedKey.length); ++ } catch (BadPaddingException e) { ++ // Should never happen ++ } ++ return res; ++ } ++ ++ @Override ++ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, ++ int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { ++ byte[] encodedKey; ++ try { ++ encodedKey = engineDoFinal(wrappedKey, 0, wrappedKey.length); ++ } catch (IllegalBlockSizeException | BadPaddingException e) { ++ throw (InvalidKeyException) (new InvalidKeyException()).initCause(e); ++ } ++ return constructKey(wrappedKeyType, encodedKey, wrappedKeyAlgorithm); ++ } ++ ++ @Override ++ protected void engineUpdateAAD(ByteBuffer byteBuffer) { ++ if (aad == null) { ++ aad = new byte[byteBuffer.remaining()]; ++ byteBuffer.get(aad); ++ } else { ++ int newSize = aad.length + byteBuffer.remaining(); ++ byte[] newaad = new byte[newSize]; ++ System.arraycopy(aad, 0, newaad, 0, aad.length); ++ byteBuffer.get(newaad, aad.length, byteBuffer.remaining()); ++ aad = newaad; ++ } ++ } ++ ++ @Override ++ protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { ++ if (aad == null) { ++ aad = Arrays.copyOfRange(input, inputOffset, inputOffset + inputLen); ++ } else { ++ int newSize = aad.length + inputLen; ++ byte[] newaad = new byte[newSize]; ++ System.arraycopy(aad, 0, newaad, 0, aad.length); ++ System.arraycopy(input, inputOffset, newaad, aad.length, inputLen); ++ aad = newaad; ++ } ++ } ++ ++ private int implDoFinal(byte[] out, int outputOffset, byte[] gcmTag) ++ throws BadPaddingException, IllegalBlockSizeException { ++ if (!encrypt && !calledUpdate) { ++ return 0; ++ } ++ ensureInitialized(); ++ ++ int outLen; ++ try { ++ if (mode == Mode.GCM) { ++ outLen = nativeFinalGcm(pCtx.ctxAddress, out, outputOffset, mode == Mode.GCM, tagLengthInBytes, ++ gcmTag, encrypt); ++ } else { ++ outLen = nativeFinal(pCtx.ctxAddress, out, outputOffset); ++ } ++ } catch (ArrayIndexOutOfBoundsException | BadPaddingException e) { ++ if (e instanceof AEADBadTagException) { ++ throw e; // AEADBadTagException is expected for some tests ++ } else if (e instanceof BadPaddingException) { ++ if (padding == Padding.NOPADDING || e.getMessage().contains("wrong final block length")) { ++ throw new IllegalBlockSizeException("Input length not multiple of " + blockSize + " bytes"); ++ } else { ++ throw e; ++ } ++ } else { ++ throw new ProviderException("Invoke nativeFinal failed for " + cipherName, e); ++ } ++ } finally { ++ reset(true); ++ } ++ ++ return outLen; ++ } ++ ++ protected void reset(boolean doCancel) { ++ initialized = false; ++ bytesBuffered = 0; ++ calledUpdate = false; ++ ++ // for gcm ++ aad = null; ++ ++ if (pCtx != null) { ++ pCtx.dispose(doCancel); ++ pCtx = null; ++ } ++ } ++ ++ protected static native long nativeInit(String cipherType, boolean encrypt, byte[] key, byte[] iv, boolean padding) ++ throws RuntimeException; ++ ++ protected static native int nativeUpdate(long pContext, byte[] in, int inOfs, int inLen, byte[] out, ++ int outOfs, boolean gcm, byte[] aad) throws ArrayIndexOutOfBoundsException; ++ ++ protected static native int nativeFinal(long pContext, byte[] out, ++ int outOfs) throws ArrayIndexOutOfBoundsException, BadPaddingException; ++ ++ protected static native void nativeFree(long pContext); ++ ++ protected static native int nativeFinalGcm(long pContext, byte[] out, int outOfs, boolean gcm, ++ int tagLength, byte[] gcmTag, boolean encrypt) throws ArrayIndexOutOfBoundsException, BadPaddingException; ++ ++ protected void ensureInitialized() { ++ if (!initialized) { ++ reset(true); ++ long pCtxVal = nativeInit(cipherName, encrypt, keyValue, iv, padding == Padding.PKCS5PADDING); ++ initialized = (pCtxVal != 0L); ++ if (initialized) { ++ pCtx = new CipherContextRef(this, pCtxVal); ++ } else { ++ throw new RuntimeException("Cannot initialize Cipher"); ++ } ++ } ++ } ++ ++ // copied from sun.security.jca.JCAUtil ++ // will be changed to reference that method once that code has been ++ // integrated and promoted ++ static int getTempArraySize(int totalSize) { ++ return Math.min(4096, totalSize); ++ } ++ ++ /** ++ * Continues a multiple-part encryption or decryption operation ++ * (depending on how this cipher was initialized), processing another data ++ * part. ++ * ++ *

    All input.remaining() bytes starting at ++ * input.position() are processed. The result is stored ++ * in the output buffer. ++ * Upon return, the input buffer's position will be equal ++ * to its limit; its limit will not have changed. The output buffer's ++ * position will have advanced by n, where n is the value returned ++ * by this method; the output buffer's limit will not have changed. ++ * ++ *

    If output.remaining() bytes are insufficient to ++ * hold the result, a ShortBufferException is thrown. ++ * ++ *

    Subclasses should consider overriding this method if they can ++ * process ByteBuffers more efficiently than byte arrays. ++ * ++ * @param input the input ByteBuffer ++ * @param output the output ByteByffer ++ * ++ * @return the number of bytes stored in output ++ * ++ * @exception ShortBufferException if there is insufficient space in the ++ * output buffer ++ * ++ * @throws NullPointerException if either parameter is null ++ * @since 1.5 ++ */ ++ protected int engineUpdate(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException { ++ try { ++ return bufferCrypt(input, output, true); ++ } catch (IllegalBlockSizeException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } catch (BadPaddingException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } ++ } ++ ++ /** ++ * Finalize crypto operation with ByteBuffers ++ * ++ * @param input the input ByteBuffer ++ * @param output the output ByteBuffer ++ * ++ * @return output length ++ * @throws ShortBufferException ++ * @throws IllegalBlockSizeException ++ * @throws BadPaddingException ++ */ ++ @Override ++ protected int engineDoFinal(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException, IllegalBlockSizeException, ++ BadPaddingException { ++ return bufferCrypt(input, output, false); ++ } ++ ++ /** ++ * Implementation for encryption using ByteBuffers. Used for both ++ * engineUpdate() and engineDoFinal(). ++ */ ++ private int bufferCrypt(ByteBuffer input, ByteBuffer output, ++ boolean isUpdate) throws ShortBufferException, ++ IllegalBlockSizeException, BadPaddingException { ++ if ((input == null) || (output == null)) { ++ throw new NullPointerException ++ ("Input and output buffers must not be null"); ++ } ++ int inPos = input.position(); ++ int inLimit = input.limit(); ++ int inLen = inLimit - inPos; ++ if (isUpdate && (inLen == 0)) { ++ return 0; ++ } ++ int outLenNeeded = getOutputSizeByOperation(inLen, !isUpdate); ++ ++ if (output.remaining() < outLenNeeded) { ++ throw new ShortBufferException("Need at least " + outLenNeeded ++ + " bytes of space in output buffer"); ++ } ++ ++ // detecting input and output buffer overlap may be tricky ++ // we can only write directly into output buffer when we ++ // are 100% sure it's safe to do so ++ ++ boolean a1 = input.hasArray(); ++ boolean a2 = output.hasArray(); ++ int total = 0; ++ ++ if (a1) { // input has an accessible byte[] ++ byte[] inArray = input.array(); ++ int inOfs = input.arrayOffset() + inPos; ++ ++ if (a2) { // output has an accessible byte[] ++ byte[] outArray = output.array(); ++ int outPos = output.position(); ++ int outOfs = output.arrayOffset() + outPos; ++ ++ // check array address and offsets and use temp output buffer ++ // if output offset is larger than input offset and ++ // falls within the range of input data ++ boolean useTempOut = false; ++ if (inArray == outArray && ++ ((inOfs < outOfs) && (outOfs < inOfs + inLen))) { ++ useTempOut = true; ++ outArray = new byte[outLenNeeded]; ++ outOfs = 0; ++ } ++ if (isUpdate) { ++ total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs); ++ } else { ++ total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs); ++ } ++ if (useTempOut) { ++ output.put(outArray, outOfs, total); ++ } else { ++ // adjust output position manually ++ output.position(outPos + total); ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } else { // output does not have an accessible byte[] ++ byte[] outArray = null; ++ if (isUpdate) { ++ outArray = engineUpdate(inArray, inOfs, inLen); ++ } else { ++ outArray = engineDoFinal(inArray, inOfs, inLen); ++ } ++ if (outArray != null && outArray.length != 0) { ++ output.put(outArray); ++ total = outArray.length; ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } ++ } else { // input does not have an accessible byte[] ++ // have to assume the worst, since we have no way of determine ++ // if input and output overlaps or not ++ byte[] tempOut = new byte[outLenNeeded]; ++ int outOfs = 0; ++ ++ byte[] tempIn = new byte[getTempArraySize(inLen)]; ++ do { ++ int chunk = Math.min(inLen, tempIn.length); ++ if (chunk > 0) { ++ input.get(tempIn, 0, chunk); ++ } ++ int n; ++ if (isUpdate || (inLen > chunk)) { ++ n = engineUpdate(tempIn, 0, chunk, tempOut, outOfs); ++ } else { ++ n = engineDoFinal(tempIn, 0, chunk, tempOut, outOfs); ++ } ++ outOfs += n; ++ total += n; ++ inLen -= chunk; ++ } while (inLen > 0); ++ if (total > 0) { ++ output.put(tempOut, 0, total); ++ } ++ } ++ ++ return total; ++ } ++} ++ +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java +new file mode 100644 +index 000000000..a4a005285 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.Cipher; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.*; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.PKCS8EncodedKeySpec; ++import java.security.spec.X509EncodedKeySpec; ++import java.util.*; ++ ++class KAEUtils { ++ enum MessageDigestType { ++ MD2("MD2", "md2", 16), ++ MD5("MD5", "md5", 16), ++ SHA1("SHA-1", "sha1", 20, ++ new HashSet<>(Arrays.asList("SHA1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"))), ++ SHA224("SHA-224", "sha224", 28, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"))), ++ SHA256("SHA-256", "sha256", 32, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"))), ++ SHA384("SHA-384", "sha384", 48, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"))), ++ SHA512("SHA-512", "sha512", 64, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"))), ++ SHA512_224("SHA-512/224", "sha512-224", 28, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.5", "OID.2.16.840.1.101.3.4.2.5"))), ++ SHA_512_256("SHA-512/256", "sha512-256", 32, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.6", "OID.2.16.840.1.101.3.4.2.6"))); ++ ++ final String digestName; ++ final String kaeDigestName; ++ final int digestLen; ++ final Set aliasNames; ++ ++ public String getDigestName() { ++ return digestName; ++ } ++ ++ public String getKaeDigestName() { ++ return kaeDigestName; ++ } ++ ++ public int getDigestLen() { ++ return digestLen; ++ } ++ ++ public Set getAliasNames() { ++ return aliasNames; ++ } ++ ++ MessageDigestType(String digestName, String kaeDigestName, int digestLen, Set aliasNames) { ++ this.digestName = digestName; ++ this.kaeDigestName = kaeDigestName; ++ this.digestLen = digestLen; ++ this.aliasNames = aliasNames; ++ } ++ ++ MessageDigestType(String digestName, String kaeDigestName, int digestLen) { ++ this(digestName, kaeDigestName, digestLen, Collections.emptySet()); ++ } ++ } ++ ++ /** ++ * kae digest algorithm info map ++ */ ++ private static final Map DIGEST_ALGORITHM_NAME_MAP = new HashMap<>(); ++ private static final Map DIGEST_ALGORITHM_LENGTH_MAP = new HashMap<>(); ++ ++ private static final Map SIZE_TO_CURVE = new HashMap<>(); ++ private static final Map CURVE_ALIAS = new HashMap<>(); ++ ++ static { ++ initDigest(); ++ initECDH(); ++ } ++ ++ private static void initDigest() { ++ MessageDigestType[] messageDigestTypes = MessageDigestType.values(); ++ for (MessageDigestType messageDigestType : messageDigestTypes) { ++ DIGEST_ALGORITHM_NAME_MAP.put(messageDigestType.getDigestName(), messageDigestType.getKaeDigestName()); ++ DIGEST_ALGORITHM_LENGTH_MAP.put(messageDigestType.getDigestName(), messageDigestType.getDigestLen()); ++ for (String aliasName : messageDigestType.getAliasNames()) { ++ DIGEST_ALGORITHM_NAME_MAP.put(aliasName, messageDigestType.getKaeDigestName()); ++ DIGEST_ALGORITHM_LENGTH_MAP.put(aliasName, messageDigestType.getDigestLen()); ++ } ++ } ++ } ++ ++ // get the kae digest algorithm name ++ static String getKAEDigestName(String digestName) { ++ return digestName == null ? null : DIGEST_ALGORITHM_NAME_MAP.get(digestName.toUpperCase(Locale.ROOT)); ++ } ++ ++ static Integer getDigestLength(String digestName) { ++ return digestName == null ? null : DIGEST_ALGORITHM_LENGTH_MAP.get(digestName.toUpperCase(Locale.ROOT)); ++ } ++ ++ static class ConstructKeys { ++ /** ++ * Construct a public key from its encoding. ++ * ++ * @param encodedKey the encoding of a public key. ++ * @param encodedKeyAlgorithm the algorithm the encodedKey is for. ++ * @return a public key constructed from the encodedKey. ++ */ ++ private static PublicKey constructPublicKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) ++ throws InvalidKeyException, NoSuchAlgorithmException { ++ try { ++ KeyFactory keyFactory = ++ KeyFactory.getInstance(encodedKeyAlgorithm); ++ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); ++ return keyFactory.generatePublic(keySpec); ++ } catch (NoSuchAlgorithmException nsae) { ++ throw new NoSuchAlgorithmException("No installed providers " + ++ "can create keys for the " + ++ encodedKeyAlgorithm + ++ "algorithm", nsae); ++ } catch (InvalidKeySpecException ike) { ++ throw new InvalidKeyException("Cannot construct public key", ike); ++ } ++ } ++ ++ /** ++ * Construct a private key from its encoding. ++ * ++ * @param encodedKey the encoding of a private key. ++ * @param encodedKeyAlgorithm the algorithm the wrapped key is for. ++ * @return a private key constructed from the encodedKey. ++ */ ++ private static PrivateKey constructPrivateKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) throws InvalidKeyException, ++ NoSuchAlgorithmException { ++ try { ++ KeyFactory keyFactory = ++ KeyFactory.getInstance(encodedKeyAlgorithm); ++ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); ++ return keyFactory.generatePrivate(keySpec); ++ } catch (NoSuchAlgorithmException nsae) { ++ throw new NoSuchAlgorithmException("No installed providers " + ++ "can create keys for the " + ++ encodedKeyAlgorithm + ++ "algorithm", nsae); ++ } catch (InvalidKeySpecException ike) { ++ throw new InvalidKeyException("Cannot construct private key", ike); ++ } ++ } ++ ++ /** ++ * Construct a secret key from its encoding. ++ * ++ * @param encodedKey the encoding of a secret key. ++ * @param encodedKeyAlgorithm the algorithm the secret key is for. ++ * @return a secret key constructed from the encodedKey. ++ */ ++ private static SecretKey constructSecretKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) { ++ return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); ++ } ++ ++ static Key constructKey(byte[] encoding, String keyAlgorithm, ++ int keyType) throws InvalidKeyException, NoSuchAlgorithmException { ++ switch (keyType) { ++ case Cipher.SECRET_KEY: ++ return constructSecretKey(encoding, keyAlgorithm); ++ case Cipher.PRIVATE_KEY: ++ return constructPrivateKey(encoding, keyAlgorithm); ++ case Cipher.PUBLIC_KEY: ++ return constructPublicKey(encoding, keyAlgorithm); ++ default: ++ throw new InvalidKeyException("Unknown keytype " + keyType); ++ } ++ } ++ } ++ ++ private static void initECDH() { ++ SIZE_TO_CURVE.put(224, "secp224r1"); ++ SIZE_TO_CURVE.put(256, "prime256v1"); ++ SIZE_TO_CURVE.put(384, "secp384r1"); ++ SIZE_TO_CURVE.put(521, "secp521r1"); ++ CURVE_ALIAS.put("secp256r1", "prime256v1"); ++ CURVE_ALIAS.put("1.3.132.0.33", "secp224r1"); ++ CURVE_ALIAS.put("1.3.132.0.34", "secp384r1"); ++ CURVE_ALIAS.put("1.3.132.0.35", "secp521r1"); ++ CURVE_ALIAS.put("1.2.840.10045.3.1.7", "prime256v1"); ++ } ++ ++ static String getCurveBySize(int size) { ++ return SIZE_TO_CURVE.get(size); ++ } ++ ++ static String getCurveByAlias(String alias) { ++ return CURVE_ALIAS.get(alias); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf b/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf +new file mode 100644 +index 000000000..49ff98fd8 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf +@@ -0,0 +1,75 @@ ++# ++# This is the config file for KAEProvider. ++# These configuration properties support the use of jdk system properties, ++# and jdk system properties take precedence over file configuration properties. ++# For detailed usage, please refer to the user manual: ++# https://gitee.com/openeuler/bishengjdk-8/wikis/%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/KAE%20Provider%E7%94%A8%E6%88%B7%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C ++# ++ ++# Algorithms are enabled by default if KAEProvider is used. ++# Delete # if you want to disable certain algorithm. ++# kae.md5=false ++# kae.sha256=false ++# kae.sha384=false ++# kae.sm3=false ++# kae.aes=false ++# kae.sm4=false ++# kae.hmac=false ++# kae.rsa=false ++# kae.dh=false ++# kae.ec=false ++ ++# Configure engine id, the default value is kae. ++# kae.engine.id=kae ++ ++# Configure whether libcrypto.so uses GLOBAL mode, uses LOCAL mode by default. ++# If you use uadk_engine, you need to enable this option. ++# kae.libcrypto.useGlobalMode=false ++ ++# The following configuration will only take effect when using KAEProvider. ++# Configure whether to enable KAE hardware acceleration for each category of algorithm. ++# The configurable value are as follows: ++# true : enable KAE hardware acceleration by default ++# false: use openssl soft calculation by default ++# The digest/sm4/rsa/dh category algorithm enable KAE hardware acceleration by default. ++# The aes/hmac/ec category algorithm use openssl soft calculation by default. ++# The ec category algorithm configuration does not take effect temporarily. and it ++# currently does not support KAE hardware acceleration, temporarily use openssl soft calculation. ++# kae.digest.useKaeEngine=true ++# kae.aes.useKaeEngine=false ++# kae.sm4.useKaeEngine=true ++# kae.hmac.useKaeEngine=false ++# kae.rsa.useKaeEngine=true ++# kae.dh.useKaeEngine=true ++# kae.ec.useKaeEngine=false ++# ++# Some engines do not fully support certain categories of algorithms, for example, the digest ++# algorithm implemented by kae engine only supports md5 and sm3.For more information, please refer to: ++# KAE : https://github.com/kunpengcompute/KAE#:~:text=Digest%20algorithm%3A%20SM3/MD5 ++# UADK: https://gitee.com/openeuler/uadk/wikis/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/UADK%20quick%20start#11-uadk ++# ++# Users can disable unsupported algorithms through the following property configuration. ++# Disable algorithm to enable KAE hardware acceleration, use openssl soft algorithm instead. ++# The sha256, sha384 algorithms are disabled by default. ++# digest : md5,sha256,sha384,sm3 ++# aes : aes-128-ecb,aes-128-cbc,aes-128-ctr,aes-128-gcm, ++# aes-192-ecb,aes-192-cbc,aes-192-ctr,aes-192-gcm, ++# aes-256-ecb,aes-256-cbc,aes-256-ctr,aes-256-gcm ++# sm4 : sm4-ecb,sm4-cbc,sm4-ctr,sm4-ofb ++# hmac : hmac-md5,hmac-sha1,hmac-sha224,hmac-sha256,hmac-sha384,hmac-sha512 ++# rsa : rsa ++# dh : dh ++# ec : ec ++# kae.engine.disabledAlgorithms=sha256,sha384 ++ ++# SM4 max chunk size of each encryption or decryption. ++# when input data does not have an accessible byte[]. ++# The default value is 4096, when configuring a non-positive Integer type, use the default value of 4096. ++# kae.sm4.maxChunkSize=4096 ++ ++# Enable engine load log. ++# kae.log=true ++# ++# It only takes effect when the property kae.log value is true. ++# Configure log file path, default value is System.getProperty("user.dir") + "/ + "kae.log". ++# kae.log.file=/home/user/kae.log +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c +new file mode 100644 +index 000000000..557d3965b +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c +@@ -0,0 +1,471 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include "kae_log.h" ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSACipher.h" ++ ++typedef int RSACryptOperation(int, const unsigned char*, unsigned char*, RSA*, int); ++ ++typedef int EvpPkeyCryptOperation(EVP_PKEY_CTX*, unsigned char*, size_t*, const unsigned char*, size_t); ++ ++typedef int EvpPkeyCryptInitOperation(EVP_PKEY_CTX*); ++ ++/* ++ * RSA encrypt or decrypt for NoPadding or PKCS1Padding , follow the steps below ++ * ++ */ ++static int RSACryptNotOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, ++ jint paddingType, RSACryptOperation rsaCryptOperation, char* cryptName) { ++ jbyte* inBytes = NULL; ++ jbyte* outBytes = NULL; ++ int resultSize = 0; ++ ++ // get RSA ++ EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; ++ ++ // rsa = pkey->rsa ++ RSA* rsa = EVP_PKEY_get1_RSA(pkey); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_get1_RSA", KAE_ThrowRuntimeException); ++ return 0; ++ } ++ ++ // do encrypt or decrypt ++ inBytes = (*env)->GetByteArrayElements(env, in, NULL); ++ if (inBytes == NULL) { ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ outBytes = (*env)->GetByteArrayElements(env, out, NULL); ++ if (outBytes == NULL) { ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ resultSize = rsaCryptOperation(inLen, (unsigned char*)inBytes, (unsigned char*)outBytes, rsa, paddingType); ++ if (resultSize <= 0) { ++ KAE_ThrowFromOpenssl(env, cryptName, KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ jsize outLen = (*env)->GetArrayLength(env, out); ++ (*env)->SetByteArrayRegion(env, out, 0, outLen, outBytes); ++ ++cleanup: ++ if (outBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, out, outBytes, 0); ++ } ++ if (inBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, in, inBytes, 0); ++ } ++ if (rsa != NULL) { ++ RSA_free(rsa); ++ } ++ return resultSize; ++} ++ ++/* ++ * set rsa padding ++ */ ++static bool SetRSAPadding(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, int paddingType) { ++ if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * set rsa mgf1 md ++ */ ++static bool SetRSAMgf1Md(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, const char* mgf1MdAlgoUTF) { ++ EVP_MD* mgf1MD = (EVP_MD*)EVP_get_digestbyname(mgf1MdAlgoUTF); ++ if (mgf1MD == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_get_digestbyname", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, mgf1MD) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_mgf1_md", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * set rsa oaep md ++ */ ++static bool SetRSAOaepMd(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, const char* oaepMdAlgoUTF) { ++ EVP_MD* oaepMD = (EVP_MD*)EVP_get_digestbyname(oaepMdAlgoUTF); ++ if (oaepMD == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_get_digestbyname", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ if (EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, oaepMD) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_oaep_md", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * set rsa oaep label ++ */ ++static bool SetRSAOaepLabel(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jbyte* labelBytes, jsize labelSize) { ++ if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkeyCtx, labelBytes, labelSize) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set0_rsa_oaep_label", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * release rsa oaep temp resource ++ */ ++static void ReleaseRSACryptOAEPResource(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, ++ jstring mgf1MdAlgo, const char* mgf1MdAlgoUTF, jstring oaepMdAlgo, const char* oaepMdAlgoUTF, ++ jbyteArray in, jbyte* inBytes, jbyteArray out, jbyte* outBytes) { ++ if (mgf1MdAlgoUTF != NULL) { ++ (*env)->ReleaseStringUTFChars(env, mgf1MdAlgo, mgf1MdAlgoUTF); ++ } ++ if (oaepMdAlgoUTF != NULL) { ++ (*env)->ReleaseStringUTFChars(env, oaepMdAlgo, oaepMdAlgoUTF); ++ } ++ if (outBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, out, outBytes, 0); ++ } ++ if (inBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, in, inBytes, 0); ++ } ++ EVP_PKEY_CTX_free(pkeyCtx); ++} ++ ++static int RSACryptOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, ++ jint paddingType, jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label, ++ EvpPkeyCryptInitOperation cryptInitOperation, char* cryptInitName, ++ EvpPkeyCryptOperation cryptOperation, char* cryptName) { ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ const char* mgf1MdAlgoUTF = NULL; ++ const char* oaepMdAlgoUTF = NULL; ++ jbyte* labelBytes = NULL; ++ jbyte* outBytes = NULL; ++ jbyte* inBytes = NULL; ++ // outLen type should be size_t ++ // EVP_PKEY_encrypt takes the outLen address as a parameter, and the parameter type is size_t* ++ // You can refer to the issue #2774 to see more content ++ size_t outLen = 0; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("RSACryptOAEPPadding: kaeEngine => %p", kaeEngine); ++ ++ ++ EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; ++ ++ // new ctx ++ // rsa encrypt/decrypt init ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL || cryptInitOperation(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, pkeyCtx == NULL ? "EVP_PKEY_CTX_new" : cryptInitName, KAE_ThrowInvalidKeyException); ++ goto cleanup; ++ } ++ ++ if ((mgf1MdAlgoUTF = (*env)->GetStringUTFChars(env, mgf1MdAlgo, 0)) == NULL || ++ (oaepMdAlgoUTF = (*env)->GetStringUTFChars(env, oaepMdAlgo, 0)) == NULL) { ++ KAE_ThrowOOMException(env, "GetStringUTFChars failed"); ++ goto cleanup; ++ } ++ ++ /* ++ * set padding type ++ * set rsa mgf1 md ++ * set rsa oaep md ++ */ ++ if (!SetRSAPadding(env, pkeyCtx, paddingType) || !SetRSAMgf1Md(env, pkeyCtx, mgf1MdAlgoUTF) || ++ !SetRSAOaepMd(env, pkeyCtx, oaepMdAlgoUTF)) { ++ goto cleanup; ++ } ++ ++ // set rsa oaep label ++ jsize labelSize = (*env)->GetArrayLength(env, label); ++ if (labelSize > 0) { ++ // EVP_PKEY_CTX_free will free the labelBytes, so we can not free labelBytes when cleanup. ++ // Only SetRSAOaepLabel failed , free labelBytes. ++ if ((labelBytes = malloc(labelSize)) == NULL) { ++ KAE_ThrowNullPointerException(env, "malloc failed"); ++ goto cleanup; ++ } ++ (*env)->GetByteArrayRegion(env, label, 0, labelSize, labelBytes); ++ if (!SetRSAOaepLabel(env, pkeyCtx, labelBytes, labelSize)) { ++ free(labelBytes); ++ goto cleanup; ++ } ++ } ++ ++ // do encrypt/decrypt ++ outLen = (size_t)(*env)->GetArrayLength(env, out); ++ if ((outBytes = (*env)->GetByteArrayElements(env, out, NULL)) == NULL || ++ (inBytes = (*env)->GetByteArrayElements(env, in, NULL)) == NULL) { ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ if (cryptOperation(pkeyCtx, (unsigned char*)outBytes, &outLen, (unsigned char*)inBytes, inLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, cryptName, KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, out, 0, outLen, outBytes); ++ ++cleanup: ++ ReleaseRSACryptOAEPResource(env, pkeyCtx, mgf1MdAlgo, mgf1MdAlgoUTF, oaepMdAlgo, oaepMdAlgoUTF, ++ in, inBytes, out, outBytes); ++ return outLen; ++} ++ ++/* ++ * Release rsa param n,e,d,p,q,dmp1,dmq1,iqmp ++ */ ++void ReleaseRSAParams(BIGNUM* bnN, BIGNUM* bnE, BIGNUM* bnD, BIGNUM* bnP, BIGNUM* bnQ, ++ BIGNUM* bnDMP1, BIGNUM* bnDMQ1, BIGNUM* bnIQMP) { ++ KAE_ReleaseBigNumFromByteArray(bnN); ++ KAE_ReleaseBigNumFromByteArray(bnE); ++ KAE_ReleaseBigNumFromByteArray(bnD); ++ KAE_ReleaseBigNumFromByteArray(bnP); ++ KAE_ReleaseBigNumFromByteArray(bnQ); ++ KAE_ReleaseBigNumFromByteArray(bnDMP1); ++ KAE_ReleaseBigNumFromByteArray(bnDMQ1); ++ KAE_ReleaseBigNumFromByteArray(bnIQMP); ++} ++ ++/* ++ * Create rsa private crt key ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeCreateRSAPrivateCrtKey ++ * Signature: ([B[B[B[B[B[B[B[B)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateCrtKey(JNIEnv* env, ++ jclass cls, jbyteArray n, jbyteArray e, jbyteArray d, jbyteArray p, jbyteArray q, ++ jbyteArray dmp1, jbyteArray dmq1, jbyteArray iqmp) { ++ BIGNUM* bnN = NULL; ++ BIGNUM* bnE = NULL; ++ BIGNUM* bnD = NULL; ++ BIGNUM* bnP = NULL; ++ BIGNUM* bnQ = NULL; ++ BIGNUM* bnDMP1 = NULL; ++ BIGNUM* bnDMQ1 = NULL; ++ BIGNUM* bnIQMP = NULL; ++ RSA* rsa = NULL; ++ EVP_PKEY* pkey = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSACipher_nativeCreateRSAPrivateCrtKey: kaeEngine => %p", kaeEngine); ++ ++ // convert to big num ++ if ((bnN = KAE_GetBigNumFromByteArray(env, n)) == NULL || ++ (bnE = KAE_GetBigNumFromByteArray(env, e)) == NULL || ++ (bnD = KAE_GetBigNumFromByteArray(env, d)) == NULL || ++ (bnP = KAE_GetBigNumFromByteArray(env, p)) == NULL || ++ (bnQ = KAE_GetBigNumFromByteArray(env, q)) == NULL || ++ (bnDMP1 = KAE_GetBigNumFromByteArray(env, dmp1)) == NULL || ++ (bnDMQ1 = KAE_GetBigNumFromByteArray(env, dmq1)) == NULL || ++ (bnIQMP = KAE_GetBigNumFromByteArray(env, iqmp)) == NULL) { ++ goto cleanup; ++ } ++ ++ // new pkey ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // new rsa ++ rsa = RSA_new_method(kaeEngine); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new_method", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // set rsa private crt key params n,e,d,p,q,dmp1,dmp1,iqmp ++ if (RSA_set0_key(rsa, bnN, bnE, bnD) <= 0 || ++ RSA_set0_factors(rsa, bnP, bnQ) <= 0 || ++ RSA_set0_crt_params(rsa, bnDMP1, bnDMQ1, bnIQMP) <= 0) { ++ KAE_ThrowFromOpenssl(env, "RSA set param", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // assign rsa to pkey ++ int result = EVP_PKEY_assign_RSA(pkey, rsa); ++ if (result <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_assign_RSA", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ return (jlong)pkey; ++cleanup: ++ ReleaseRSAParams(bnN, bnE, bnD, bnP, bnQ, bnDMP1, bnDMQ1, bnIQMP); ++ RSA_free(rsa); ++ EVP_PKEY_free(pkey); ++ return 0; ++} ++ ++/* ++ * Create rsa public key ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeCreateRSAPublicKey ++ * Signature: ([B[B)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPublicKey( ++ JNIEnv* env, jclass cls, jbyteArray n, jbyteArray e) { ++ BIGNUM* bnN = NULL; ++ BIGNUM* bnE = NULL; ++ RSA* rsa = NULL; ++ EVP_PKEY* pkey = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSACipher_nativeCreateRSAPublicKey: kaeEngine => %p", kaeEngine); ++ ++ // get public key param n ++ bnN = KAE_GetBigNumFromByteArray(env, n); ++ if (bnN == NULL) { ++ goto cleanup; ++ } ++ ++ // get public key param e ++ bnE = KAE_GetBigNumFromByteArray(env, e); ++ if (bnE == NULL) { ++ goto cleanup; ++ } ++ ++ // new rsa ++ rsa = RSA_new_method(kaeEngine); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new_method", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // new EVP_PKEY ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // set rsa public key params n and e ++ if (RSA_set0_key(rsa, bnN, bnE, NULL) <= 0) { ++ KAE_ThrowFromOpenssl(env, "RSA_set0_key", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // assign rsa to pkey ++ int result = EVP_PKEY_assign_RSA(pkey, rsa); ++ if (result <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_assign_RSA", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ return (jlong)pkey; ++cleanup: ++ KAE_ReleaseBigNumFromByteArray(bnN); ++ KAE_ReleaseBigNumFromByteArray(bnE); ++ RSA_free(rsa); ++ EVP_PKEY_free(pkey); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPrivateEncrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateEncrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_private_encrypt, ++ "RSA_private_encrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPrivateDecrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateDecrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_private_decrypt, ++ "RSA_private_decrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPublicEncrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicEncrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_public_encrypt, ++ "RSA_public_encrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPublicDecrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicDecrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_public_decrypt, ++ "RSA_public_decrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAEncryptOAEPPading ++ * Signature: (JI[B[BI[B[B[B)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAEncryptOAEPPadding(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, ++ jint paddingType, jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label) { ++ return RSACryptOAEPPadding(env, keyAddress, inLen, in, out, paddingType, oaepMdAlgo, mgf1MdAlgo, label, ++ EVP_PKEY_encrypt_init, "EVP_PKEY_encrypt_init", ++ EVP_PKEY_encrypt, "EVP_PKEY_encrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSADecryptOAEPPadding ++ * Signature: (JI[B[BILjava/lang/String;Ljava/lang/String;[B)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSADecryptOAEPPadding(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType, ++ jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label) { ++ return RSACryptOAEPPadding(env, keyAddress, inLen, in, out, paddingType, oaepMdAlgo, mgf1MdAlgo, label, ++ EVP_PKEY_decrypt_init, "EVP_PKEY_decrypt_init", ++ EVP_PKEY_decrypt, "EVP_PKEY_decrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeFreeKey ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeFreeKey(JNIEnv* env, ++ jclass cls, jlong keyAddress) { ++ EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; ++ if (pkey != NULL) { ++ EVP_PKEY_free(pkey); ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c +new file mode 100644 +index 000000000..82bf477da +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c +@@ -0,0 +1,232 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAEDigest.h" ++ ++#define DIGEST_STACK_SIZE 1024 ++#define DIGEST_CHUNK_SIZE 64*1024 ++#define DIGEST_LENGTH_THRESHOLD 48 ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeInit ++ * Signature: (Ljava/lang/String;)J ++ */ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeInit(JNIEnv *env, jclass cls, jstring algorithmName) ++{ ++ EVP_MD_CTX* ctx = NULL; ++ ENGINE* kaeEngine = NULL; ++ ++ if (algorithmName == NULL) { ++ KAE_ThrowNullPointerException(env, "algorithm is null"); ++ return 0; ++ } ++ ++ // EVP_get_digestbyname ++ const char* algo_utf = (*env)->GetStringUTFChars(env, algorithmName, 0); ++ kaeEngine = GetDigestEngineByAlgorithmName(algo_utf); ++ KAE_TRACE("KAEDigest_nativeInit: kaeEngine => %p", kaeEngine); ++ EVP_MD* md = (EVP_MD*) EVP_get_digestbyname(algo_utf); ++ (*env)->ReleaseStringUTFChars(env, algorithmName, algo_utf); ++ if (md == NULL) { ++ KAE_TRACE("%s not supported", algo_utf); ++ return 0; ++ } ++ KAE_TRACE("KAEDigest_nativeInit: create md => %p", md); ++ ++ ctx = EVP_MD_CTX_create(); ++ if (ctx == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_MD_CTX fail"); ++ return 0; ++ } ++ KAE_TRACE("KAEDigest_nativeInit: create ctx => %p", ctx); ++ ++ // EVP_DigestInit_ex ++ int result_code = EVP_DigestInit_ex(ctx, md, kaeEngine); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestInit_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ KAE_TRACE("KAEDigest_nativeInit EVP_DigestInit_ex(ctx = %p, md = %p) success", ctx, md); ++ ++ KAE_TRACE("KAEDigest_nativeInit: finished"); ++ return (jlong) ctx; ++ ++cleanup: ++ EVP_MD_CTX_destroy(ctx); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeUpdate ++ * Signature: (Ljava/lang/String;J[BII)I ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeUpdate(JNIEnv *env, jclass cls, jlong ctxAddress, ++ jbyteArray input, jint offset, jint inLen) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d", ctx, input, offset, inLen); ++ if (ctx == NULL) { ++ return; ++ } ++ ++ jint in_offset = offset; ++ jint in_size = inLen; ++ int result_code = 0; ++ if (in_size <= DIGEST_STACK_SIZE) { // allocation on the stack ++ jbyte buffer[DIGEST_STACK_SIZE]; ++ (*env)->GetByteArrayRegion(env, input, offset, inLen, buffer); ++ result_code = EVP_DigestUpdate(ctx, buffer, inLen); ++ } else { // data chunk ++ jint remaining = in_size; ++ jint buf_size = (remaining >= DIGEST_CHUNK_SIZE) ? DIGEST_CHUNK_SIZE : remaining; ++ jbyte* buffer = malloc(buf_size); ++ if (buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ return; ++ } ++ while (remaining > 0) { ++ jint chunk_size = (remaining >= buf_size) ? buf_size : remaining; ++ (*env)->GetByteArrayRegion(env, input, in_offset, chunk_size, buffer); ++ result_code = EVP_DigestUpdate(ctx, buffer, chunk_size); ++ if (!result_code) { ++ break; ++ } ++ in_offset += chunk_size; ++ remaining -= chunk_size; ++ } ++ free(buffer); ++ } ++ if (!result_code) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestUpdate failed", KAE_ThrowRuntimeException); ++ return; ++ } ++ KAE_TRACE("KAEDigest_nativeUpdate EVP_DigestUpdate success"); ++ KAE_TRACE("KAEDigest_nativeUpdate: finished"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeDigest ++ * Signature: (Ljava/lang/String;J[BII)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeDigest(JNIEnv *env, jclass cls, ++ jlong ctxAddress, jbyteArray output, jint offset, jint len) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeDigest(ctx = %p, output = %p, offset = %d, len = %d", ctx, output, offset, len); ++ unsigned char* md = NULL; ++ unsigned int bytesWritten = 0; ++ ++ if (ctx == NULL) { ++ return 0; ++ } ++ ++ if (len <= 0 || len > DIGEST_LENGTH_THRESHOLD) { ++ KAE_ThrowRuntimeException(env, "len out of length"); ++ return 0; ++ } ++ md = malloc(len); ++ if (md == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ return 0; ++ } ++ ++ // EVP_DigestFinal_ex ++ int result_code = EVP_DigestFinal_ex(ctx, md, &bytesWritten); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestFinal_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ KAE_TRACE("KAEDigest_nativeFinal EVP_DigestFinal_ex success, bytesWritten = %d", bytesWritten); ++ ++ (*env)->SetByteArrayRegion(env, output, offset, bytesWritten, (jbyte*) md); ++ ++ KAE_TRACE("KAEDigest_nativeFinal: finished"); ++ ++cleanup: ++ free(md); ++ return bytesWritten; ++} ++ ++/* ++* Class: org_openeuler_security_openssl_KAEDigest ++* Method: nativeClone ++* Signature: (J)J ++*/ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeClone(JNIEnv *env, jclass cls, jlong ctxAddress) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeClone: ctx = %p", ctx); ++ if (ctx == NULL) { ++ return 0; ++ } ++ ++ EVP_MD_CTX* ctxCopy = EVP_MD_CTX_create(); ++ if (ctxCopy == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_MD_CTX fail"); ++ return 0; ++ } ++ KAE_TRACE("KAEDigest_nativeClone: create ctxCopy => %p", ctxCopy); ++ ++ int result_code = EVP_MD_CTX_copy_ex(ctxCopy, ctx); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_MD_CTX_copy_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ KAE_TRACE("KAEDigest_nativeClone EVP_MD_CTX_copy_ex(ctxCopy = %p, ctx = %p) success", ctxCopy, ctx); ++ KAE_TRACE("KAEDigest_nativeClone: finished"); ++ return (jlong) ctxCopy; ++ ++cleanup: ++ EVP_MD_CTX_destroy(ctxCopy); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeFree(JNIEnv *env, jclass cls, jlong ctxAddress) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeFree(ctx = %p)", ctx); ++ if (ctx != NULL) { ++ EVP_MD_CTX_destroy(ctx); ++ } ++ ++ KAE_TRACE("KAEDigest_nativeFree: finished"); ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c +new file mode 100644 +index 000000000..c0579ebf4 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++#include "openssl_ad.h" ++ ++void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg) { ++ jclass cls = (*env)->FindClass(env, name); ++ if (cls != 0) { ++ (*env)->ThrowNew(env, cls, msg); ++ (*env)->DeleteLocalRef(env, cls); ++ } ++} ++ ++void KAE_ThrowOOMException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/OutOfMemoryError", msg); ++} ++ ++void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/NullPointerException", msg); ++} ++ ++void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", msg); ++} ++ ++void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { ++ switch (reason) { ++ case EVP_R_UNSUPPORTED_ALGORITHM: ++ KAE_ThrowByName(env, "java/security/NoSuchAlgorithmException", msg); ++ break; ++ case EVP_R_MISSING_PARAMETERS: ++ KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); ++ break; ++ case EVP_R_BAD_DECRYPT: ++ case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: ++ case EVP_F_EVP_PKEY_DECRYPT: ++ case EVP_R_PUBLIC_KEY_NOT_RSA: ++ case EVP_R_CTRL_NOT_IMPLEMENTED: ++ KAE_ThrowByName(env, "javax/crypto/BadPaddingException", msg); ++ break; ++ default: ++ defaultException(env, msg); ++ break; ++ } ++} ++ ++void KAE_ThrowRuntimeException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/RuntimeException", msg); ++} ++ ++void KAE_ThrowBadPaddingException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "javax/crypto/BadPaddingException", msg); ++} ++ ++void KAE_ThrowInvalidKeyException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); ++} ++ ++void KAE_ThrowInvalidAlgorithmParameterException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/security/InvalidAlgorithmParameterException", msg); ++} ++ ++void KAE_ThrowFromOpenssl(JNIEnv* env, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { ++ const char* file = NULL; ++ const char* data = NULL; ++ int line = 0; ++ int flags = 0; ++ unsigned long err; ++ static const int ESTRING_SIZE = 256; ++ ++ err = ERR_get_error_line_data(&file, &line, &data, &flags); ++ if (err == 0) { ++ defaultException(env, msg); ++ return; ++ } ++ ++ if (!(*env)->ExceptionCheck(env)) { ++ char estring[ESTRING_SIZE]; ++ ERR_error_string_n(err, estring, ESTRING_SIZE); ++ int lib = ERR_GET_LIB(err); ++ int func = ERR_GET_FUNC(err); ++ int reason = ERR_GET_REASON(err); ++ KAE_TRACE("OpenSSL error in %s: err=%lx, lib=%x, func=%x, reason=%x, file=%s, line=%d, estring=%s, data=%s", msg, err, ++ lib, func, reason, file, line, estring, (flags & ERR_TXT_STRING) ? data : "(no data)"); ++ // Ignore exceptions in RSA_verify_PKCS1_PSS_mgf1 function ++ if (lib == ERR_LIB_RSA && func == RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1) { ++ return; ++ } ++ ++ if (lib == ERR_LIB_EVP || lib == ERR_LIB_RSA) { ++ KAE_ThrowEvpException(env, reason, estring, defaultException); ++ } else { ++ defaultException(env, estring); ++ } ++ } ++ ++ ERR_clear_error(); ++} ++ ++void KAE_ThrowAEADBadTagException(JNIEnv *env, const char *msg) { ++ KAE_ThrowByName(env, "javax/crypto/AEADBadTagException", msg); ++} ++ ++void KAE_ThrowSignatureException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/security/SignatureException", msg); ++} ++ ++void KAE_ThrowClassNotFoundException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/ClassNotFoundException", msg); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h +new file mode 100644 +index 000000000..f33f993e4 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 KAE_EXCEPTION_H ++#define KAE_EXCEPTION_H ++ ++#include ++ ++/* Throw a Java exception by name */ ++void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg); ++ ++void KAE_ThrowOOMException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowFromOpenssl(JNIEnv* env, const char* msg, void (* defaultException)(JNIEnv*, const char*)); ++ ++void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)); ++ ++void KAE_ThrowRuntimeException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowBadPaddingException(JNIEnv* env, const char* msg); ++ ++/* Throw InvalidKeyException */ ++void KAE_ThrowInvalidKeyException(JNIEnv* env, const char* msg); ++ ++/* Throw AlgorithmParameterException */ ++void KAE_ThrowInvalidAlgorithmParameterException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowAEADBadTagException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowSignatureException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowClassNotFoundException(JNIEnv* env, const char* msg); ++#endif +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c +new file mode 100644 +index 000000000..ad7b86ecd +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "kae_util.h" ++ ++static const EVP_MD* EVPGetDigestByName(JNIEnv* env, const char* algo) ++{ ++ static const EVP_MD* md5 = NULL; ++ static const EVP_MD* sha1 = NULL; ++ static const EVP_MD* sha224 = NULL; ++ static const EVP_MD* sha256 = NULL; ++ static const EVP_MD* sha384 = NULL; ++ static const EVP_MD* sha512 = NULL; ++ ++ if (strcasecmp(algo, "md5") == 0) { ++ return md5 == NULL ? md5 = EVP_get_digestbyname(algo) : md5; ++ } else if (strcasecmp(algo, "sha1") == 0) { ++ return sha1 == NULL ? sha1 = EVP_get_digestbyname(algo) : sha1; ++ } else if (strcasecmp(algo, "sha224") == 0) { ++ return sha224 == NULL ? sha224 = EVP_get_digestbyname(algo) : sha224; ++ } else if (strcasecmp(algo, "sha256") == 0) { ++ return sha256 == NULL ? sha256 = EVP_get_digestbyname(algo) : sha256; ++ } else if (strcasecmp(algo, "sha384") == 0) { ++ return sha384 == NULL ? sha384 = EVP_get_digestbyname(algo) : sha384; ++ } else if (strcasecmp(algo, "sha512") == 0) { ++ return sha512 == NULL ? sha512 = EVP_get_digestbyname(algo) : sha512; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetDigestByName error"); ++ return 0; ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEHMac ++ * Method: nativeInit ++ * Signature: ([BILjava/lang/String;)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeInit ++ (JNIEnv* env, jclass cls, jbyteArray key, jint key_len, jstring algoStr) { ++ if (key == NULL || algoStr == NULL) { ++ KAE_ThrowNullPointerException(env, "param key or algoStr is null"); ++ return 0; ++ } ++ if (key_len <= 0) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "key"); ++ return 0; ++ } ++ HMAC_CTX* ctx = NULL; ++ jbyte* key_buffer = NULL; ++ const EVP_MD* md = NULL; ++ ENGINE* kaeEngine = NULL; ++ ++ const char* algo = (*env)->GetStringUTFChars(env, algoStr, 0); ++ md = EVPGetDigestByName(env, algo); ++ ++ kaeEngine = GetHmacEngineByAlgorithmName(algo); ++ KAE_TRACE("KAEHMac_nativeInit: kaeEngine => %p", kaeEngine); ++ ++ (*env)->ReleaseStringUTFChars(env, algoStr, algo); ++ if (md == NULL) { ++ KAE_ThrowRuntimeException(env, "algorithm unsupport"); ++ return 0; ++ } ++ ++ // get secret-key ++ key_buffer = malloc(key_len); ++ if (key_buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return 0; ++ } ++ (*env)->GetByteArrayRegion(env, key, 0, key_len, key_buffer); ++ ++ // create a hmac context ++ ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ KAE_ThrowRuntimeException(env, "Hmac_CTX_new invoked failed"); ++ goto cleanup; ++ } ++ ++ // init hmac context with sc_key and evp_md ++ int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, kaeEngine); ++ if (result_code == 0) { ++ KAE_ThrowRuntimeException(env, "Hmac_Init_ex invoked failed"); ++ goto cleanup; ++ } ++ free(key_buffer); ++ return (jlong) ctx; ++ ++cleanup: ++ free(key_buffer); ++ HMAC_CTX_free(ctx); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEHMac ++ * Method: nativeUpdate ++ * Signature: (J[BII)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeUpdate ++ (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray input, jint in_offset, jint in_len) { ++ KAE_TRACE("KAEHMac_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d)", (void*) hmac_ctx, input, in_offset, in_len); ++ HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; ++ if (ctx == NULL || input == NULL) { ++ KAE_ThrowNullPointerException(env, "param ctx or input is null"); ++ return; ++ } ++ int input_size = (*env)->GetArrayLength(env, input); ++ if ((in_offset < 0) || (in_len < 0) || (in_offset > input_size - in_len)) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "input"); ++ return; ++ } ++ // do nothing while in_len is 0 ++ if (in_len == 0) { ++ return; ++ } ++ ++ jbyte* buffer = malloc(in_len); ++ if (buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return; ++ } ++ (*env)->GetByteArrayRegion(env, input, in_offset, in_len, buffer); ++ if (!HMAC_Update(ctx, (unsigned char*) buffer, in_len)) { ++ KAE_ThrowRuntimeException(env, "Hmac_Update invoked failed"); ++ } ++ free(buffer); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEHMac ++ * Method: nativeFinal ++ * Signature: (J[BII)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeFinal ++ (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray output, jint out_offset, jint in_len) { ++ HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; ++ if (ctx == NULL || output == NULL) { ++ KAE_ThrowNullPointerException(env, "param ctx or input is null"); ++ return 0; ++ } ++ int output_size = (*env)->GetArrayLength(env, output); ++ if ((out_offset < 0) || (in_len < 0) || (out_offset > output_size - in_len)) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "output"); ++ return 0; ++ } ++ ++ jbyte* temp_result = NULL; ++ ++ temp_result = malloc(in_len); ++ if (temp_result == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return 0; ++ } ++ // do final ++ unsigned int bytesWritten = 0; ++ int result_code = HMAC_Final(ctx, (unsigned char*) temp_result, &bytesWritten); ++ if (result_code == 0) { ++ KAE_ThrowRuntimeException(env, "Hmac_Final invoked failed"); ++ goto cleanup; ++ } ++ ++ // write back to output_array ++ (*env)->SetByteArrayRegion(env, output, out_offset, bytesWritten, (jbyte*) temp_result); ++ KAE_TRACE("KAEHMac_nativeFinal success, output_offset = %d, bytesWritten = %u", out_offset, bytesWritten); ++ ++cleanup: ++ free(temp_result); ++ return bytesWritten; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEHMac ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeFree ++ (JNIEnv* env, jclass cls, jlong hmac_ctx) { ++ HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; ++ if (ctx != NULL) { ++ HMAC_CTX_free(ctx); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c +new file mode 100644 +index 000000000..e9dfa4094 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include ++#include ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "org_openeuler_security_openssl_KAEDHKeyAgreement.h" ++ ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDHKeyAgreement ++ * Method: nativeComputeKey ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAEDHKeyAgreement_nativeComputeKey(JNIEnv* env, ++ jobject obj, jbyteArray y, jbyteArray x, jbyteArray p, jbyteArray g, jint pSize) { ++ ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyAgreement_nativeComputeKey start."); ++ ++ DH* dh = NULL; ++ BIGNUM* y_bn = NULL; ++ BIGNUM* x_bn = NULL; ++ BIGNUM* p_bn = NULL; ++ BIGNUM* g_bn = NULL; ++ BIGNUM* computeKeyRetBn = NULL; ++ int computekeyLength = 0; ++ unsigned char* secret = NULL; ++ jbyteArray retByteArray = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(DH_INDEX); ++ KAE_TRACE("KAEDHKeyAgreement_nativeComputeKey: kaeEngine => %p", kaeEngine); ++ ++ // bits to Bytes ++ int pSizeInByte = (pSize +7) >> 3; ++ ++ if ((secret = (unsigned char*)malloc(pSizeInByte)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc secret failed."); ++ goto cleanup; ++ } ++ memset(secret, 0, pSizeInByte); ++ ++ if ((dh = DH_new_method(kaeEngine)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate DH failed in nativeComputeKey."); ++ goto cleanup; ++ } ++ ++ if ((y_bn = KAE_GetBigNumFromByteArray(env, y)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert y to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((x_bn = KAE_GetBigNumFromByteArray(env, x)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert x to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((p_bn = KAE_GetBigNumFromByteArray(env, p)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert p to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((g_bn = KAE_GetBigNumFromByteArray(env, g)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert g to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((computeKeyRetBn = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate BN failed."); ++ goto cleanup; ++ } ++ ++ if (!DH_set0_pqg(dh, BN_dup(p_bn), NULL, BN_dup(g_bn))) { ++ KAE_ThrowRuntimeException(env, "DH_set0_pqg failed."); ++ goto cleanup; ++ } ++ ++ if (!DH_set0_key(dh, NULL, BN_dup(x_bn))) { ++ KAE_ThrowRuntimeException(env, "DH_set0_key failed."); ++ goto cleanup; ++ } ++ ++ computekeyLength = DH_compute_key(secret, y_bn, dh); ++ ++ if (computekeyLength <= 0 ) { ++ KAE_ThrowRuntimeException(env, "DH_compute_key failed."); ++ goto cleanup; ++ } ++ ++ BN_bin2bn(secret, computekeyLength, computeKeyRetBn); ++ ++ retByteArray = KAE_GetByteArrayFromBigNum(env, computeKeyRetBn); ++ if (retByteArray == NULL) { ++ KAE_ThrowRuntimeException(env, "GetByteArrayFromBigNum failed in nativeComputeKey."); ++ goto cleanup; ++ } ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyAgreement_nativeComputeKey finished!"); ++ ++cleanup: ++ if (dh != NULL) ++ DH_free(dh); ++ if (y_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(y_bn); ++ if (x_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(x_bn); ++ if (p_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(p_bn); ++ if (g_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(g_bn); ++ if (secret != NULL) { ++ memset(secret, 0, pSizeInByte); ++ free(secret); ++ } ++ if (computeKeyRetBn != NULL) ++ BN_free(computeKeyRetBn); ++ ++ return retByteArray; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c +new file mode 100644 +index 000000000..b0877a25e +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAEECDHKeyAgreement.h" ++ ++static void FreeGenerateSecretParam(BIGNUM* s, BIGNUM* wX, BIGNUM* wY, ++ EC_POINT* pub, EC_KEY* eckey, EC_GROUP* group, unsigned char* shareKey, int shareKeyLen) ++{ ++ KAE_ReleaseBigNumFromByteArray(s); ++ KAE_ReleaseBigNumFromByteArray(wX); ++ KAE_ReleaseBigNumFromByteArray(wY); ++ if (pub != NULL) { ++ EC_POINT_free(pub); ++ } ++ if (eckey != NULL) { ++ EC_KEY_free(eckey); ++ } ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (shareKey != NULL) { ++ memset(shareKey, 0, shareKeyLen); ++ free(shareKey); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEECDHKeyAgreement ++ * Method: nativeGenerateSecret ++ * Signature: (Ljava/lang/String;[B[B[B)[B ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAEECDHKeyAgreement_nativeGenerateSecret ++ (JNIEnv* env, jclass cls, jstring curveName, jbyteArray wXArr, jbyteArray wYArr, jbyteArray sArr) ++{ ++ EC_GROUP* group = NULL; ++ EC_KEY* eckey = NULL; ++ BIGNUM* wX = NULL; ++ BIGNUM* wY = NULL; ++ BIGNUM* s = NULL; ++ EC_POINT* pub = NULL; ++ jbyteArray javaBytes = NULL; ++ unsigned char* shareKey = NULL; ++ const char *curve = (*env)->GetStringUTFChars(env, curveName, 0); ++ int nid = OBJ_sn2nid(curve); ++ (*env)->ReleaseStringUTFChars(env, curveName, curve); ++ ++ // Initialization of secret key. ++ int expectSecretLen = 0; ++ ++ if ((nid == NID_undef) || (group = EC_GROUP_new_by_curve_name(nid)) == NULL) { ++ goto cleanup; ++ } ++ if ((s = KAE_GetBigNumFromByteArray(env, sArr)) == NULL || (wX = KAE_GetBigNumFromByteArray(env, wXArr)) == NULL ++ || (wY = KAE_GetBigNumFromByteArray(env, wYArr)) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate BN_new"); ++ goto cleanup; ++ } ++ if ((eckey = EC_KEY_new()) == NULL || !EC_KEY_set_group(eckey, group)) { ++ goto cleanup; ++ } ++ if ((pub = EC_POINT_new(group)) == NULL) { ++ goto cleanup; ++ } ++ if (!EC_POINT_set_affine_coordinates_GFp(group, pub, wX, wY, NULL)) { ++ goto cleanup; ++ } ++ if (!EC_KEY_set_public_key(eckey, pub) || !EC_KEY_set_private_key(eckey, s)) { ++ goto cleanup; ++ } ++ ++ // Get the length of secret key, in bytes. ++ expectSecretLen = (EC_GROUP_get_degree(group) + 7) / 8; ++ ++ if ((shareKey = malloc(expectSecretLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(shareKey, 0, expectSecretLen); ++ ++ // Perform ecdh keyagreement. ++ if (ECDH_compute_key(shareKey, expectSecretLen, pub, eckey, NULL) != expectSecretLen) { ++ goto cleanup; ++ } ++ ++ if ((javaBytes = (*env)->NewByteArray(env, expectSecretLen)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, javaBytes, 0, expectSecretLen, (jbyte*)shareKey); ++ FreeGenerateSecretParam(s, wX, wY, pub, eckey, group, shareKey, expectSecretLen); ++ return javaBytes; ++ ++cleanup: ++ FreeGenerateSecretParam(s, wX, wY, pub, eckey, group, shareKey, expectSecretLen); ++ return NULL; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +new file mode 100644 +index 000000000..6315cc6ee +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +@@ -0,0 +1,132 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include ++#include ++#include "kae_util.h" ++#include "kae_log.h" ++#include "org_openeuler_security_openssl_KAEDHKeyPairGenerator.h" ++#include "kae_exception.h" ++ ++ ++/* ++* Class: org_openeuler_security_openssl_KAEDHKeyPairGenerator ++* Method: nativeGenerateKeyPair ++* Signature: ([B[BI)[[B ++*/ ++ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair ++ (JNIEnv* env, jclass cls, jbyteArray p, jbyteArray g, jint lSize) ++{ ++ DH* dh = NULL; ++ BIGNUM* p_bn = NULL; ++ BIGNUM* g_bn = NULL; ++ const BIGNUM* pri_key_bn = NULL; ++ const BIGNUM* pub_key_bn = NULL; ++ jclass byteArrayClass = NULL; ++ jobjectArray keys = NULL; ++ jbyteArray pri_key = NULL; ++ jbyteArray pub_key = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(DH_INDEX); ++ KAE_TRACE("KAEDHKeyPairGenerator_nativeGenerateKeyPair: kaeEngine => %p", kaeEngine); ++ ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair start !"); ++ ++ if ((dh = DH_new_method(kaeEngine)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate DH failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ if ((p_bn = KAE_GetBigNumFromByteArray(env, p)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate p_bn failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ if ((g_bn = KAE_GetBigNumFromByteArray(env, g)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate g_bn failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ if (!DH_set0_pqg(dh, BN_dup(p_bn), NULL, BN_dup(g_bn))) { ++ KAE_ThrowRuntimeException(env, "DH_set0_pqg failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ // Return value is fixed to 1, nothing to check. ++ DH_set_length(dh, lSize); ++ ++ if (!DH_generate_key(dh)) { ++ KAE_ThrowInvalidAlgorithmParameterException(env, "DH generate key failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ if ((byteArrayClass = (*env)->FindClass(env, "[B")) == NULL) { ++ KAE_ThrowClassNotFoundException(env, "Class byte[] not found."); ++ goto cleanup; ++ } ++ ++ if ((keys = (*env)->NewObjectArray(env, 2, byteArrayClass, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate ByteArray failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ // Return the ptr of private key in dh. ++ pri_key_bn = DH_get0_priv_key(dh); ++ pub_key_bn = DH_get0_pub_key(dh); ++ ++ pub_key = KAE_GetByteArrayFromBigNum(env, pub_key_bn); ++ if (pub_key == NULL) { ++ KAE_ThrowOOMException(env, "PublicKey allocate failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ pri_key = KAE_GetByteArrayFromBigNum(env, pri_key_bn); ++ if (pri_key == NULL) { ++ KAE_ThrowRuntimeException(env, "GetByteArrayFromBigNum failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ (*env)->SetObjectArrayElement(env, keys, 0, pub_key); ++ (*env)->SetObjectArrayElement(env, keys, 1, pri_key); ++ ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair finished !"); ++ ++cleanup: ++ if (dh != NULL) ++ DH_free(dh); ++ if (p_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(p_bn); ++ if (g_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(g_bn); ++ if (byteArrayClass != NULL) ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ if (pub_key != NULL) ++ (*env)->DeleteLocalRef(env, pub_key); ++ if (pri_key != NULL) ++ (*env)->DeleteLocalRef(env, pri_key); ++ ++ return keys; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c +new file mode 100644 +index 000000000..0449f8a26 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c +@@ -0,0 +1,505 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "org_openeuler_security_openssl_KAEECKeyPairGenerator.h" ++ ++#define KAE_EC_PARAM_NUM_SIZE 7 ++#define KAE_EC_KEY_NUM_SIZE 3 ++ ++// ECDH param index. ++typedef enum ECDHParamIndex { ++ ecdhP = 0, ++ ecdhA, ++ ecdhB, ++ ecdhX, ++ ecdhY, ++ ecdhOrder, ++ ecdhCofactor ++} ECDHParamIndex; ++ ++// ECDH Key index. ++typedef enum ECDHKeyIndex { ++ ecdhWX = 0, ++ ecdhWY, ++ ecdhS ++} ECDHKeyIndex; ++ ++static void FreeECDHCurveParam(JNIEnv* env, BIGNUM* p, BIGNUM* a, BIGNUM* b, jbyteArray paramP, ++ jbyteArray paramA, jbyteArray paramB) ++{ ++ if (p != NULL) { ++ BN_free(p); ++ } ++ if (a != NULL) { ++ BN_free(a); ++ } ++ if (b != NULL) { ++ BN_free(b); ++ } ++ if (paramP != NULL) { ++ (*env)->DeleteLocalRef(env, paramP); ++ } ++ if (paramA != NULL) { ++ (*env)->DeleteLocalRef(env, paramA); ++ } ++ if (paramB != NULL) { ++ (*env)->DeleteLocalRef(env, paramB); ++ } ++} ++ ++// Set p, a, b in group to params. ++static bool SetECDHCurve(JNIEnv* env, EC_GROUP* group, jobjectArray params) ++{ ++ BIGNUM* p = NULL; ++ BIGNUM* a = NULL; ++ BIGNUM* b = NULL; ++ jbyteArray paramP = NULL; ++ jbyteArray paramA = NULL; ++ jbyteArray paramB = NULL; ++ if ((p = BN_new()) == NULL || (a = BN_new()) == NULL || (b = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate BN_new"); ++ goto cleanup; ++ } ++ if (!EC_GROUP_get_curve_GFp(group, p, a, b, NULL)) { ++ goto cleanup; ++ } ++ ++ // Set p. ++ if ((paramP = KAE_GetByteArrayFromBigNum(env, p)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhP, paramP); ++ ++ // Set a. ++ if ((paramA = KAE_GetByteArrayFromBigNum(env, a)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhA, paramA); ++ ++ // Set b. ++ if ((paramB = KAE_GetByteArrayFromBigNum(env, b)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhB, paramB); ++ FreeECDHCurveParam(env, p, a, b, paramP, paramA, paramB); ++ return true; ++ ++cleanup: ++ FreeECDHCurveParam(env, p, a, b, paramP, paramA, paramB); ++ return false; ++} ++ ++// Set generator(x, y) in group to params. ++static bool SetECDHPoint(JNIEnv* env, EC_GROUP* group, jobjectArray params) ++{ ++ BIGNUM* x = NULL; ++ BIGNUM* y = NULL; ++ const EC_POINT* generator = NULL; ++ jbyteArray paramX = NULL; ++ jbyteArray paramY = NULL; ++ if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate BN_new"); ++ goto cleanup; ++ } ++ if ((generator = EC_GROUP_get0_generator(group)) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate ec generator"); ++ goto cleanup; ++ } ++ if (!EC_POINT_get_affine_coordinates_GFp(group, generator, x, y, NULL)) { ++ KAE_ThrowFromOpenssl(env, "EC_POINT_set_affine_coordinates_GFp", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // Set x. ++ if ((paramX = KAE_GetByteArrayFromBigNum(env, x)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhX, paramX); ++ ++ // Set y. ++ if ((paramY = KAE_GetByteArrayFromBigNum(env, y)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhY, paramY); ++ BN_free(x); ++ BN_free(y); ++ (*env)->DeleteLocalRef(env, paramX); ++ (*env)->DeleteLocalRef(env, paramY); ++ return true; ++ ++cleanup: ++ if (x != NULL) { ++ BN_free(x); ++ } ++ if (y != NULL) { ++ BN_free(y); ++ } ++ if (paramX != NULL) { ++ (*env)->DeleteLocalRef(env, paramX); ++ } ++ if (paramY != NULL) { ++ (*env)->DeleteLocalRef(env, paramY); ++ } ++ return false; ++} ++ ++// Set order, cofactor in group to params. ++static bool SetECDHOrderAndCofactor(JNIEnv* env, EC_GROUP* group, jobjectArray params) ++{ ++ BIGNUM* order = NULL; ++ BIGNUM* cofactor = NULL; ++ jbyteArray paramOrder = NULL; ++ jbyteArray paramCofactor = NULL; ++ if ((order = BN_new()) == NULL || (cofactor = BN_new()) == NULL) { ++ goto cleanup; ++ } ++ if (!EC_GROUP_get_order(group, order, NULL)) { ++ goto cleanup; ++ } ++ ++ // Set order. ++ if ((paramOrder = KAE_GetByteArrayFromBigNum(env, order)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhOrder, paramOrder); ++ if (!EC_GROUP_get_cofactor(group, cofactor, NULL)) { ++ goto cleanup; ++ } ++ ++ // Set cofactor. ++ if ((paramCofactor = KAE_GetByteArrayFromBigNum(env, cofactor)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhCofactor, paramCofactor); ++ BN_free(order); ++ BN_free(cofactor); ++ (*env)->DeleteLocalRef(env, paramOrder); ++ (*env)->DeleteLocalRef(env, paramCofactor); ++ return true; ++ ++cleanup: ++ if (order != NULL) { ++ BN_free(order); ++ } ++ if (cofactor != NULL) { ++ BN_free(cofactor); ++ } ++ if (paramOrder != NULL) { ++ (*env)->DeleteLocalRef(env, paramOrder); ++ } ++ if (paramCofactor != NULL) { ++ (*env)->DeleteLocalRef(env, paramCofactor); ++ } ++ return false; ++} ++ ++static void FreeECDHKeyParam(JNIEnv* env, ++ BIGNUM* wX, BIGNUM* wY, jbyteArray keyWX, jbyteArray keyWY, jbyteArray keyS) ++{ ++ if (wX != NULL) { ++ BN_free(wX); ++ } ++ if (wY != NULL) { ++ BN_free(wY); ++ } ++ if (keyWX != NULL) { ++ (*env)->DeleteLocalRef(env, keyWX); ++ } ++ if (keyWY != NULL) { ++ (*env)->DeleteLocalRef(env, keyWY); ++ } ++ if (keyS != NULL) { ++ (*env)->DeleteLocalRef(env, keyS); ++ } ++} ++ ++// Set publicKey(wX, wY) and privateKey(s) in eckey to params. ++static bool SetECDHKey(JNIEnv* env, const EC_GROUP* group, jobjectArray params, ++ const EC_KEY* eckey) ++{ ++ BIGNUM* wX = NULL; ++ BIGNUM* wY = NULL; ++ const EC_POINT* pub = NULL; ++ const BIGNUM* s = NULL; ++ jbyteArray keyWX = NULL; ++ jbyteArray keyWY = NULL; ++ jbyteArray keyS = NULL; ++ if ((wX = BN_new()) == NULL || (wY = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ goto cleanup; ++ } ++ ++ if ((pub = EC_KEY_get0_public_key(eckey)) == NULL || ++ !EC_POINT_get_affine_coordinates_GFp(group, pub, wX, wY, NULL)) { ++ goto cleanup; ++ } ++ if ((s = EC_KEY_get0_private_key(eckey)) == NULL) { ++ goto cleanup; ++ } ++ ++ // Set wX. ++ if ((keyWX = KAE_GetByteArrayFromBigNum(env, wX)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhWX, keyWX); ++ ++ // Set wY. ++ if ((keyWY = KAE_GetByteArrayFromBigNum(env, wY)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhWY, keyWY); ++ ++ // Set s. ++ if ((keyS = KAE_GetByteArrayFromBigNum(env, s)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhS, keyS); ++ FreeECDHKeyParam(env, wX, wY, keyWX, keyWY, keyS); ++ return true; ++ ++cleanup: ++ FreeECDHKeyParam(env, wX, wY, keyWX, keyWY, keyS); ++ return false; ++} ++ ++// Convert EC_GROUP in openssl to byte[][] in java ++static jobjectArray NewECDHParam(JNIEnv* env, EC_GROUP* group) ++{ ++ jclass byteArrayClass = (*env)->FindClass(env, "[B"); ++ jobjectArray params = (*env)->NewObjectArray(env, KAE_EC_PARAM_NUM_SIZE, byteArrayClass, NULL); ++ if (params == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ goto cleanup; ++ } ++ ++ if (!SetECDHCurve(env, group, params)) { ++ goto cleanup; ++ } ++ if (!SetECDHPoint(env, group, params)) { ++ goto cleanup; ++ } ++ if (!SetECDHOrderAndCofactor(env, group, params)) { ++ goto cleanup; ++ } ++ ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ return params; ++ ++cleanup: ++ if (byteArrayClass != NULL) { ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ } ++ if (params != NULL) { ++ (*env)->DeleteLocalRef(env, params); ++ } ++ return NULL; ++} ++ ++// Convert EC_KEY in openssl to byte[][] in java ++static jobjectArray NewECDHKey(JNIEnv* env, const EC_GROUP* group, const EC_KEY* eckey) ++{ ++ jclass byteArrayClass = (*env)->FindClass(env, "[B"); ++ jobjectArray params = (*env)->NewObjectArray(env, KAE_EC_KEY_NUM_SIZE, byteArrayClass, NULL); ++ if (params == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ goto cleanup; ++ } ++ if (!SetECDHKey(env, group, params, eckey)) { ++ goto cleanup; ++ } ++ ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ return params; ++ ++cleanup: ++ if (byteArrayClass != NULL) { ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ } ++ if (params != NULL) { ++ (*env)->DeleteLocalRef(env, params); ++ } ++ return NULL; ++} ++ ++static void FreeECDHParam(BIGNUM* p, BIGNUM* a, BIGNUM* b, BIGNUM* x, BIGNUM* y, BIGNUM* order, BIGNUM* cofactor) ++{ ++ KAE_ReleaseBigNumFromByteArray(p); ++ KAE_ReleaseBigNumFromByteArray(a); ++ KAE_ReleaseBigNumFromByteArray(b); ++ KAE_ReleaseBigNumFromByteArray(x); ++ KAE_ReleaseBigNumFromByteArray(y); ++ KAE_ReleaseBigNumFromByteArray(order); ++ KAE_ReleaseBigNumFromByteArray(cofactor); ++} ++ ++// Convert params in java to EC_GROUP in openssl ++static EC_GROUP* GetGroupByParam(JNIEnv* env, jbyteArray pArr, jbyteArray aArr, jbyteArray bArr, ++ jbyteArray xArr, jbyteArray yArr, jbyteArray orderArr, jint cofactorInt) ++{ ++ BIGNUM* p = NULL; ++ BIGNUM* a = NULL; ++ BIGNUM* b = NULL; ++ BIGNUM* x = NULL; ++ BIGNUM* y = NULL; ++ BIGNUM* order = NULL; ++ BIGNUM* cofactor = NULL; ++ EC_GROUP* group = NULL; ++ BN_CTX* ctx = NULL; ++ EC_POINT* generator = NULL; ++ if ((p = KAE_GetBigNumFromByteArray(env, pArr)) == NULL || (a = KAE_GetBigNumFromByteArray(env, aArr)) == NULL || ++ (b = KAE_GetBigNumFromByteArray(env, bArr)) == NULL || (x = KAE_GetBigNumFromByteArray(env, xArr)) == NULL || ++ (y = KAE_GetBigNumFromByteArray(env, yArr)) == NULL || (cofactor = BN_new()) == NULL || ++ (order = KAE_GetBigNumFromByteArray(env, orderArr)) == NULL || !BN_set_word(cofactor, cofactorInt)) { ++ goto cleanup; ++ } ++ ++ // Create the curve. ++ if ((ctx = BN_CTX_new()) == NULL || (group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { ++ goto cleanup; ++ } ++ ++ // Create the generator and set x, y. ++ if ((generator = EC_POINT_new(group)) == NULL || ++ !EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx)) { ++ goto cleanup; ++ } ++ ++ // Set the generator, order and cofactor. ++ if (!EC_GROUP_set_generator(group, generator, order, cofactor)) { ++ goto cleanup; ++ } ++ ++ FreeECDHParam(p, a, b, x, y, order, cofactor); ++ EC_POINT_free(generator); ++ BN_CTX_free(ctx); ++ return group; ++ ++cleanup: ++ FreeECDHParam(p, a, b, x, y, order, cofactor); ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (generator != NULL) { ++ EC_POINT_free(generator); ++ } ++ if (ctx != NULL) { ++ BN_CTX_free(ctx); ++ } ++ return NULL; ++} ++ ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEECKeyPairGenerator ++ * Method: nativeGenerateParam ++ * Signature: (Ljava/lang/String;)[[B ++ */ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEECKeyPairGenerator_nativeGenerateParam( ++ JNIEnv* env, jclass cls, jstring curveName) ++{ ++ EC_GROUP* group = NULL; ++ jobjectArray ecdhParam = NULL; ++ ++ const char *curve = (*env)->GetStringUTFChars(env, curveName, 0); ++ KAE_TRACE("KAEECKeyPairGenerator_nativeGenerateParam(curveName = %s)", curve); ++ int nid = OBJ_sn2nid(curve); ++ (*env)->ReleaseStringUTFChars(env, curveName, curve); ++ if (nid == NID_undef) { ++ goto cleanup; ++ } ++ // Construct a builtin curve. ++ if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL) { ++ goto cleanup; ++ } ++ ecdhParam = NewECDHParam(env, group); ++ ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ KAE_TRACE("KAEECKeyPairGenerator_nativeGenerateParam success, ecdhParam = %p", ecdhParam); ++ return ecdhParam; ++ ++cleanup: ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (ecdhParam != NULL) { ++ (*env)->DeleteLocalRef(env, ecdhParam); ++ } ++ return NULL; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEECKeyPairGenerator ++ * Method: nativeGenerateKeyPair ++ * Signature: ([B[B[B[B[B[BI)[[B ++ */ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEECKeyPairGenerator_nativeGenerateKeyPair( ++ JNIEnv* env, jclass cls, jbyteArray pArr, jbyteArray aArr, jbyteArray bArr, ++ jbyteArray xArr, jbyteArray yArr, jbyteArray orderArr, jint cofactorInt) ++{ ++ EC_GROUP* group = NULL; ++ EC_KEY* eckey = NULL; ++ jobjectArray ecdhKey = NULL; ++ ++ if ((group = GetGroupByParam(env, pArr, aArr, bArr, xArr, yArr, orderArr, cofactorInt)) == NULL) { ++ goto cleanup; ++ } ++ if ((eckey = EC_KEY_new()) == NULL) { ++ goto cleanup; ++ } ++ if (!EC_KEY_set_group(eckey, group)) { ++ goto cleanup; ++ } ++ // Generates a new public and private key for the supplied eckey object. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EC_KEY_generate_key.html} for details. ++ if (!EC_KEY_generate_key(eckey)) { ++ goto cleanup; ++ } ++ ++ ecdhKey = NewECDHKey(env, group, eckey); ++ ++ EC_KEY_free(eckey); ++ EC_GROUP_free(group); ++ ++ KAE_TRACE("KAEECKeyPairGenerator_nativeGenerateKeyPair success, ecdhKey = %p", ecdhKey); ++ return ecdhKey; ++ ++cleanup: ++ if (eckey != NULL) { ++ EC_KEY_free(eckey); ++ } ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (ecdhKey != NULL) { ++ (*env)->DeleteLocalRef(env, ecdhKey); ++ } ++ return NULL; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +new file mode 100644 +index 000000000..84c2ed109 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include "kae_log.h" ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSAKeyPairGenerator.h" ++#define KAE_RSA_PARAM_SIZE 8 ++ ++// rsa param index ++typedef enum RSAParamIndex { ++ rsaN = 0, ++ rsaE, ++ rsaD, ++ rsaP, ++ rsaQ, ++ rsaDmp1, ++ rsaDmq1, ++ rsaIqmp ++} RSAParamIndex; ++ ++// rsa param name array ++static const char* rsaParamNames[] = {"n", "e", "d", "p", "q", "dmp1", "dmq1", "iqmp"}; ++ ++// rsa get rsa param function list ++static const BIGNUM* (* GetRSAParamFunctionList[])(const RSA*) = { ++ RSA_get0_n, ++ RSA_get0_e, ++ RSA_get0_d, ++ RSA_get0_p, ++ RSA_get0_q, ++ RSA_get0_dmp1, ++ RSA_get0_dmq1, ++ RSA_get0_iqmp ++}; ++ ++/* ++ * New RSA and generate rsa key, follow the steps below ++ * step 1.New RSA ++ * step 2.Convert publicExponent to BIGNUM ++ * step 3.Generate rsa key, and all key information is stored in RSA ++ */ ++static RSA* NewRSA(JNIEnv* env, jint keySize, jbyteArray publicExponent) { ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("NewRSA: kaeEngine => %p", kaeEngine); ++ ++ // new rsa ++ RSA* rsa = RSA_new_method(kaeEngine); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new_method", KAE_ThrowRuntimeException); ++ return NULL; ++ } ++ ++ // convert publicExponent to BIGNUM ++ BIGNUM* exponent = KAE_GetBigNumFromByteArray(env, publicExponent); ++ if (exponent == NULL) { ++ return NULL; ++ } ++ ++ // generate rsa key ++ int result_code = RSA_generate_key_ex(rsa, keySize, exponent, NULL); ++ KAE_ReleaseBigNumFromByteArray(exponent); ++ if (result_code <= 0) { ++ RSA_free(rsa); ++ KAE_ThrowFromOpenssl(env, "RSA_generate_key_ex", KAE_ThrowRuntimeException); ++ return NULL; ++ } ++ return rsa; ++} ++ ++/* ++ * release RSA ++ */ ++static void ReleaseRSA(RSA* rsa) { ++ if (rsa != NULL) { ++ RSA_free(rsa); ++ } ++} ++ ++/* ++ * Set rsa key param, follow the steps below ++ * step 1. Get rsa param value ++ * step 2. Convert paramValue (BIGNUM) to jbyteArray ++ * step 3. Set the rsa param to the param array ++ */ ++static bool SetRSAKeyParam(JNIEnv* env, RSA* rsa, jobjectArray params, RSAParamIndex rsaParamIndex) { ++ // get rsa param value ++ const BIGNUM* rsaParamValue = GetRSAParamFunctionList[rsaParamIndex](rsa); ++ if (rsaParamValue == NULL) { ++ return false; ++ } ++ ++ // Convert paramValue to jbyteArray ++ jbyteArray param = KAE_GetByteArrayFromBigNum(env, rsaParamValue); ++ if (param == NULL) { ++ return false; ++ } ++ ++ // Set the rsa param to the param array ++ (*env)->SetObjectArrayElement(env, params, rsaParamIndex, param); ++ return true; ++} ++ ++/* ++ * New rsa key params, follow the steps below ++ * step 1. New rsa key param array ++ * step 2. Set rsa key param ++ */ ++static jobjectArray NewRSAKeyParams(JNIEnv* env, RSA* rsa) { ++ // new param array ++ jclass byteArrayClass = (*env)->FindClass(env, "[B"); ++ jobjectArray params = (*env)->NewObjectArray(env, KAE_RSA_PARAM_SIZE, byteArrayClass, NULL); ++ if (params == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ return NULL; ++ } ++ ++ // set rsa key param ++ RSAParamIndex paramIndex; ++ for (paramIndex = rsaN; paramIndex <= rsaIqmp; paramIndex++) { ++ if (!SetRSAKeyParam(env, rsa, params, paramIndex)) { ++ return NULL; ++ } ++ } ++ return params; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSAKeyPairGenerator ++ * Method: nativeGenerateKeyPair ++ * Signature: (I[B)[[B ++ */ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAERSAKeyPairGenerator_nativeGenerateKeyPair ( ++ JNIEnv* env, jclass cls, jint keySize, jbyteArray publicExponent) { ++ if (publicExponent == NULL) { ++ return NULL; ++ } ++ ++ // new RSA ++ RSA* rsa = NewRSA(env, keySize, publicExponent); ++ if (rsa == NULL) { ++ return NULL; ++ } ++ ++ // new RSA Key Parameters ++ jobjectArray rsaParm = NewRSAKeyParams(env, rsa); ++ ++ // release rsa ++ ReleaseRSA(rsa); ++ return rsaParm; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h +new file mode 100644 +index 000000000..b618546c5 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 KAE_LOG_H ++#define KAE_LOG_H ++ ++#ifdef KAE_DEBUG ++#define KAE_TRACE(...) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); } ++#else ++#define KAE_TRACE(...) ++#endif ++ ++#endif +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c +new file mode 100644 +index 000000000..f4f71005a +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include ++#include "kae_exception.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAEProvider.h" ++ ++#define KAE_OPENSSL_LIBRARY "libcrypto.so" ++ ++/* ++ * Class: Java_org_openeuler_security_openssl_KAEProvider ++ * Method: initOpenssl ++ * Signature: ()V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEProvider_initOpenssl ++ (JNIEnv *env, jclass cls, jboolean useGlobalMode, jstring engineId, jbooleanArray algorithmKaeFlags) { ++ SSL_load_error_strings(); ++ ERR_load_BIO_strings(); ++ OpenSSL_add_all_algorithms(); ++ ++ /* ++ * If the same shared object is opened again with dlopen(), the same object handle is returned. ++ * The dynamic linker maintains reference counts for object handles. ++ * An object that was previously opened with RTLD_LOCAL can be promoted to RTLD_GLOBAL in a subsequent dlopen(). ++ * ++ * RTLD_GLOBAL ++ * The symbols defined by this shared object will be made ++ * available for symbol resolution of subsequently loaded ++ * shared objects. ++ * RTLD_LOCAL ++ * This is the converse of RTLD_GLOBAL, and the default if ++ * neither flag is specified. Symbols defined in this shared ++ * object are not made available to resolve references in ++ * subsequently loaded shared objects. ++ * For more information see https://man7.org/linux/man-pages/man3/dlopen.3.html. ++ */ ++ if (useGlobalMode) { ++ char msg[1024]; ++ void *handle = NULL; ++ // Promote the flags of the loaded libcrypto.so library from RTLD_LOCAL to RTLD_GLOBAL ++ handle = dlopen(KAE_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); ++ if (handle == NULL) { ++ snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", KAE_OPENSSL_LIBRARY, dlerror()); ++ KAE_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); ++ return; ++ } ++ dlclose(handle); ++ } ++ ++ // check if KaeEngine holder is already set ++ ENGINE* e = GetKaeEngine(); ++ if (e != NULL) { ++ ENGINE_free(e); ++ e = NULL; ++ } ++ ++ // determine whether KAE is loaded successfully ++ const char* id = (*env)->GetStringUTFChars(env, engineId, 0); ++ e = ENGINE_by_id(id); ++ (*env)->ReleaseStringUTFChars(env, engineId, id); ++ if (e == NULL) { ++ KAE_ThrowFromOpenssl(env, "ENGINE_by_id", KAE_ThrowRuntimeException); ++ return; ++ } ++ SetKaeEngine(e); ++ ++ // initialize the engine for each algorithm ++ initEngines(env, algorithmKaeFlags); ++} ++ ++/* ++ * Class: Java_org_openeuler_security_openssl_KAEProvider ++ * Method: getEngineFlags ++ * Signature: ()V ++ */ ++JNIEXPORT jbooleanArray JNICALL Java_org_openeuler_security_openssl_KAEProvider_getEngineFlags ++ (JNIEnv *env, jclass cls) { ++ return getEngineFlags(env); ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c +new file mode 100644 +index 000000000..496ebc775 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c +@@ -0,0 +1,366 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include ++#include "kae_log.h" ++#include "kae_util.h" ++#include "kae_exception.h" ++ ++// get EVP_MD by digestName ++static const EVP_MD* getEvpMd(JNIEnv* env, jstring digestName) { ++ const char* digestNameUtf = (*env)->GetStringUTFChars(env, digestName, 0); ++ const EVP_MD* md = (EVP_MD*)EVP_get_digestbyname(digestNameUtf); ++ (*env)->ReleaseStringUTFChars(env, digestName, digestNameUtf); ++ if (md == NULL) { ++ KAE_ThrowSignatureException(env, "Unsupported digest algorithm."); ++ } ++ return md; ++} ++ ++// sign release ++static void signRelease(JNIEnv* env, jbyteArray digestValue, jbyte* digestBytes, jbyte* sigBytes, ++ EVP_PKEY_CTX* pkeyCtx) { ++ if (digestBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, digestValue, digestBytes, 0); ++ } ++ if (sigBytes != NULL) { ++ free(sigBytes); ++ } ++ if (pkeyCtx != NULL) { ++ EVP_PKEY_CTX_free(pkeyCtx); ++ } ++} ++ ++// verify release ++static void verifyRelease(JNIEnv* env, jbyteArray digestValue, jbyte* digestBytes, jbyteArray sigValue, jbyte* sigBytes, ++ EVP_PKEY_CTX* pkeyCtx) { ++ if (digestBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, digestValue, digestBytes, 0); ++ } ++ if (sigBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, sigValue, sigBytes, 0); ++ } ++ if (pkeyCtx != NULL) { ++ EVP_PKEY_CTX_free(pkeyCtx); ++ } ++} ++ ++// set rsa PkeyCtx parameters ++static bool setRsaPkeyCtxParameters(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jint paddingType, jstring digestName) { ++ // set rsa padding ++ if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set signature md ++ const EVP_MD* md = getEvpMd(env, digestName); ++ if (md == NULL) { ++ return false; ++ } ++ ++ if (EVP_PKEY_CTX_set_signature_md(pkeyCtx, md) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_signature_md", KAE_ThrowSignatureException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: rsaSign ++ * Signature: (JLjava/lang/String;[BI)[B ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_rsaSign(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jbyteArray sigByteArray = NULL; ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // sign init ++ if (EVP_PKEY_sign_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set rsa PkeyCtx parameters ++ if (!setRsaPkeyCtxParameters(env, pkeyCtx, paddingType, digestName)) { ++ goto cleanup; ++ } ++ ++ // sign ++ size_t sigLen = (size_t)EVP_PKEY_size(pkey); ++ if (sigLen <= 0) { ++ KAE_ThrowSignatureException(env, "The sigLen size cannot be zero or negative"); ++ goto cleanup; ++ } ++ if ((sigBytes = malloc(sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ goto cleanup; ++ } ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_sign(pkeyCtx, (unsigned char*)sigBytes, &sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set signature byte to jbyteArray ++ if ((sigByteArray = (*env)->NewByteArray(env, (jsize)sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "NewByteArray failed"); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, sigByteArray, 0, (jsize)sigLen, sigBytes); ++ ++cleanup: ++ signRelease(env, digestValue, digestBytes, sigBytes, pkeyCtx); ++ return sigByteArray; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: rsaVerify ++ * Signature: (JLjava/lang/String;[BI[B)Z ++ */ ++JNIEXPORT jboolean JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_rsaVerify(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType, jbyteArray sigValue) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jboolean isSuccess = JNI_FALSE; ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // verify init ++ if (EVP_PKEY_verify_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set rsa PkeyCtx parameters ++ if (!setRsaPkeyCtxParameters(env, pkeyCtx, paddingType, digestName)) { ++ goto cleanup; ++ } ++ ++ // verify ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ if ((sigBytes = (*env)->GetByteArrayElements(env, sigValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t sigLen = (size_t)(*env)->GetArrayLength(env, sigValue); ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_verify(pkeyCtx, (const unsigned char*)sigBytes, sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_verify", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ isSuccess = JNI_TRUE; ++ ++cleanup: ++ verifyRelease(env, digestValue, digestBytes, sigValue, sigBytes, pkeyCtx); ++ return isSuccess; ++} ++ ++// set pss pkeyCtx parameters ++static bool setPssPkeyCtxParameters(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jint paddingType, jstring digestName, ++ jstring mgf1DigestName, jint saltLen) { ++ // set rsa padding ++ if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set signature md ++ const EVP_MD* md = getEvpMd(env, digestName); ++ if (md == NULL) { ++ return false; ++ } ++ if (EVP_PKEY_CTX_set_signature_md(pkeyCtx, md) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_signature_md", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set rsa mgf1 md ++ const EVP_MD* mgf1Md = getEvpMd(env, mgf1DigestName); ++ if (mgf1Md == NULL) { ++ return false; ++ } ++ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, mgf1Md) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_mgf1_md", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set salt len ++ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkeyCtx, saltLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_pss_saltlen", KAE_ThrowSignatureException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: pssSign ++ * Signature: (JLjava/lang/String;[BILjava/lang/String;I)[B ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_pssSign(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType, jstring mgf1DigestName, ++ jint saltLen) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jbyteArray sigByteArray = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_pssSign: kaeEngine => %p", kaeEngine); ++ ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // sign init ++ if (EVP_PKEY_sign_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set pss pkeyCtx parameters ++ if (!setPssPkeyCtxParameters(env, pkeyCtx, paddingType, digestName, mgf1DigestName, saltLen)) { ++ goto cleanup; ++ } ++ ++ // sign ++ size_t sigLen = (size_t)EVP_PKEY_size(pkey); ++ if (sigLen <= 0) { ++ KAE_ThrowSignatureException(env, "The sigLen size cannot be zero or negative"); ++ goto cleanup; ++ } ++ if ((sigBytes = malloc(sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ goto cleanup; ++ } ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_sign(pkeyCtx, (unsigned char*)sigBytes, &sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set signature byte to jbyteArray ++ if ((sigByteArray = (*env)->NewByteArray(env, (jsize)sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "NewByteArray failed"); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, sigByteArray, 0, (jsize)sigLen, sigBytes); ++ ++cleanup: ++ signRelease(env, digestValue, digestBytes, sigBytes, pkeyCtx); ++ return sigByteArray; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: pssVerify ++ * Signature: (JLjava/lang/String;[BILjava/lang/String;I[B)Z ++ */ ++JNIEXPORT jboolean JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_pssVerify(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType, jstring mgf1DigestName, ++ jint saltLen, jbyteArray sigValue) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jboolean isSuccess = JNI_FALSE; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_pssVerify: kaeEngine => %p", kaeEngine); ++ ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // verify init ++ if (EVP_PKEY_verify_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set pkeyCtx parameters ++ if (!setPssPkeyCtxParameters(env, pkeyCtx, paddingType, digestName, mgf1DigestName, saltLen)) { ++ goto cleanup; ++ } ++ ++ // verify ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ if ((sigBytes = (*env)->GetByteArrayElements(env, sigValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t sigLen = (size_t)(*env)->GetArrayLength(env, sigValue); ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_verify(pkeyCtx, (const unsigned char*)sigBytes, sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_verify", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ isSuccess = JNI_TRUE; ++ ++cleanup: ++ verifyRelease(env, digestValue, digestBytes, sigValue, sigBytes, pkeyCtx); ++ return isSuccess; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c +new file mode 100644 +index 000000000..67151f53a +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c +@@ -0,0 +1,415 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAESymmetricCipherBase.h" ++ ++bool StartsWith(const char* str1, const char* str2) ++{ ++ if (str1 == NULL || str2 == NULL) { ++ return 0; ++ } ++ int len1 = strlen(str1); ++ int len2 = strlen(str2); ++ if (len1 > len2 || (len1 == 0 || len2 == 0)) { ++ return false; ++ } ++ const char *cur = str1; ++ int i = 0; ++ while (*cur != '\0') { ++ if (*cur != str2[i]) { ++ return 0; ++ } ++ cur++; ++ i++; ++ } ++ return true; ++} ++ ++static const EVP_CIPHER* EVPGetSm4CipherByName(JNIEnv* env, const char* algo) ++{ ++ static const EVP_CIPHER* sm4Ecb = NULL; ++ static const EVP_CIPHER* sm4Cbc = NULL; ++ static const EVP_CIPHER* sm4Ctr = NULL; ++ static const EVP_CIPHER* sm4Ofb = NULL; ++ ++ if (strcasecmp(algo, "sm4-ecb") == 0) { ++ return sm4Ecb == NULL ? sm4Ecb = EVP_get_cipherbyname(algo) : sm4Ecb; ++ } else if (strcasecmp(algo, "sm4-cbc") == 0) { ++ return sm4Cbc == NULL ? sm4Cbc = EVP_get_cipherbyname(algo) : sm4Cbc; ++ } else if (strcasecmp(algo, "sm4-ctr") == 0) { ++ return sm4Ctr == NULL ? sm4Ctr = EVP_get_cipherbyname(algo) : sm4Ctr; ++ } else if (strcasecmp(algo, "sm4-ofb") == 0) { ++ return sm4Ofb == NULL ? sm4Ofb = EVP_get_cipherbyname(algo) : sm4Ofb; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetSm4CipherByName error"); ++ return 0; ++ } ++} ++ ++static const EVP_CIPHER* EVPGetAesCipherByName(JNIEnv* env, const char* algo) ++{ ++ static const EVP_CIPHER* aes128Ecb = NULL; ++ static const EVP_CIPHER* aes128Cbc = NULL; ++ static const EVP_CIPHER* aes128Ctr = NULL; ++ static const EVP_CIPHER* aes128Gcm = NULL; ++ static const EVP_CIPHER* aes192Ecb = NULL; ++ static const EVP_CIPHER* aes192Cbc = NULL; ++ static const EVP_CIPHER* aes192Ctr = NULL; ++ static const EVP_CIPHER* aes192Gcm = NULL; ++ static const EVP_CIPHER* aes256Ecb = NULL; ++ static const EVP_CIPHER* aes256Cbc = NULL; ++ static const EVP_CIPHER* aes256Ctr = NULL; ++ static const EVP_CIPHER* aes256Gcm = NULL; ++ ++ if (strcasecmp(algo, "aes-128-ecb") == 0) { ++ return aes128Ecb == NULL ? aes128Ecb = EVP_get_cipherbyname(algo) : aes128Ecb; ++ } else if (strcasecmp(algo, "aes-128-cbc") == 0) { ++ return aes128Cbc == NULL ? aes128Cbc = EVP_get_cipherbyname(algo) : aes128Cbc; ++ } else if (strcasecmp(algo, "aes-128-ctr") == 0) { ++ return aes128Ctr == NULL ? aes128Ctr = EVP_get_cipherbyname(algo) : aes128Ctr; ++ } else if (strcasecmp(algo, "aes-128-gcm") == 0) { ++ return aes128Gcm == NULL ? aes128Gcm = EVP_get_cipherbyname(algo) : aes128Gcm; ++ } else if (strcasecmp(algo, "aes-192-ecb") == 0) { ++ return aes192Ecb == NULL ? aes192Ecb = EVP_get_cipherbyname(algo) : aes192Ecb; ++ } else if (strcasecmp(algo, "aes-192-cbc") == 0) { ++ return aes192Cbc == NULL ? aes192Cbc = EVP_get_cipherbyname(algo) : aes192Cbc; ++ } else if (strcasecmp(algo, "aes-192-ctr") == 0) { ++ return aes192Ctr == NULL ? aes192Ctr = EVP_get_cipherbyname(algo) : aes192Ctr; ++ } else if (strcasecmp(algo, "aes-192-gcm") == 0) { ++ return aes192Gcm == NULL ? aes192Gcm = EVP_get_cipherbyname(algo) : aes192Gcm; ++ } else if (strcasecmp(algo, "aes-256-ecb") == 0) { ++ return aes256Ecb == NULL ? aes256Ecb = EVP_get_cipherbyname(algo) : aes256Ecb; ++ } else if (strcasecmp(algo, "aes-256-cbc") == 0) { ++ return aes256Cbc == NULL ? aes256Cbc = EVP_get_cipherbyname(algo) : aes256Cbc; ++ } else if (strcasecmp(algo, "aes-256-ctr") == 0) { ++ return aes256Ctr == NULL ? aes256Ctr = EVP_get_cipherbyname(algo) : aes256Ctr; ++ } else if (strcasecmp(algo, "aes-256-gcm") == 0) { ++ return aes256Gcm == NULL ? aes256Gcm = EVP_get_cipherbyname(algo) : aes256Gcm; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetAesCipherByName error"); ++ return 0; ++ } ++} ++ ++void FreeMemoryFromInit(JNIEnv* env, jbyteArray iv, jbyte* ivBytes, jbyteArray key, jbyte* keyBytes, ++ int keyLength) ++{ ++ if (ivBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); ++ } ++ if (keyBytes != NULL) { ++ memset(keyBytes, 0, keyLength); ++ (*env)->ReleaseByteArrayElements(env, key, keyBytes, JNI_ABORT); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeInit ++ * Signature: (Ljava/lang/String;Z[B[B)J ++ */ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeInit(JNIEnv* env, jclass cls, ++ jstring cipherType, jboolean encrypt, jbyteArray key, jbyteArray iv, jboolean padding) ++{ ++ EVP_CIPHER_CTX* ctx = NULL; ++ jbyte* keyBytes = NULL; ++ jbyte* ivBytes = NULL; ++ const EVP_CIPHER* cipher = NULL; ++ ENGINE* kaeEngine = NULL; ++ int keyLength = (*env)->GetArrayLength(env, key); ++ ++ const char* algo = (*env)->GetStringUTFChars(env, cipherType, 0); ++ if (StartsWith("aes", algo)) { ++ cipher = EVPGetAesCipherByName(env, algo); ++ kaeEngine = GetAesEngineByAlgorithmName(algo); ++ } else { ++ cipher = EVPGetSm4CipherByName(env, algo); ++ kaeEngine = GetSm4EngineByAlgorithmName(algo); ++ } ++ ++ KAE_TRACE("KAESymmetricCipherBase_nativeInit: kaeEngine => %p", kaeEngine); ++ ++ (*env)->ReleaseStringUTFChars(env, cipherType, algo); ++ if (cipher == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_CIPHER fail"); ++ goto cleanup; ++ } ++ if ((ctx = EVP_CIPHER_CTX_new()) == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_CIPHER_CTX fail"); ++ goto cleanup; ++ } ++ ++ if (iv != NULL) { ++ ivBytes = (*env)->GetByteArrayElements(env, iv, NULL); ++ } ++ if (key != NULL) { ++ keyBytes = (*env)->GetByteArrayElements(env, key, NULL); ++ } ++ ++ if (!EVP_CipherInit_ex(ctx, cipher, kaeEngine, (const unsigned char*)keyBytes, ++ (const unsigned char*)ivBytes, encrypt ? 1 : 0)) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherInit_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ EVP_CIPHER_CTX_set_padding(ctx, padding ? 1 : 0); ++ ++ FreeMemoryFromInit(env, iv, ivBytes, key, keyBytes, keyLength); ++ return (jlong)ctx; ++ ++cleanup: ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ } ++ FreeMemoryFromInit(env, iv, ivBytes, key, keyBytes, keyLength); ++ return 0; ++} ++ ++static void FreeMemoryFromUpdate(unsigned char* in, unsigned char* aad, unsigned char* out) ++{ ++ if (in != NULL) { ++ free(in); ++ } ++ if (out != NULL) { ++ free(out); ++ } ++ if (aad != NULL) { ++ free(aad); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeUpdate ++ * Signature: (J[BII[BIZ[B)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeUpdate(JNIEnv* env, jclass cls, jlong ctxAddress, ++ jbyteArray inArr, jint inOfs, jint inLen, jbyteArray outArr, jint outOfs, jboolean gcm, jbyteArray gcmAAD) ++{ ++ unsigned char* in = NULL; ++ unsigned char* aad = NULL; ++ unsigned char* out = NULL; ++ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ if (ctx == NULL || inArr == NULL || outArr == NULL) { ++ goto cleanup; ++ } ++ ++ in = (unsigned char*)malloc(inLen); ++ int outLen = (*env)->GetArrayLength(env, outArr) - outOfs; ++ out = (unsigned char*)malloc(outLen); ++ if (in == NULL || out == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(in, 0, inLen); ++ memset(out, 0, outLen); ++ (*env)->GetByteArrayRegion(env, inArr, inOfs, inLen, (jbyte*)in); ++ ++ int bytesWritten = 0; ++ if (gcm && (gcmAAD != NULL)) { ++ int aadLen = (*env)->GetArrayLength(env, gcmAAD); ++ if ((aad = (unsigned char*)malloc(aadLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(aad, 0, aadLen); ++ (*env)->GetByteArrayRegion(env, gcmAAD, 0, aadLen, (jbyte*)aad); ++ ++ // Specify aad. ++ if (EVP_CipherUpdate(ctx, NULL, &bytesWritten, aad, aadLen) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherUpdate failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ } ++ ++ if (EVP_CipherUpdate(ctx, out, &bytesWritten, in, inLen) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherUpdate failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*)out); ++ ++ FreeMemoryFromUpdate(in, aad, out); ++ return bytesWritten; ++ ++cleanup: ++ FreeMemoryFromUpdate(in, aad, out); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeFinal ++ * Signature: (JZ[BI)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeFinal(JNIEnv* env, jclass cls, ++ jlong ctxAddress, jbyteArray outArr, jint outOfs) ++{ ++ unsigned char* out = NULL; ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ KAE_TRACE("KAESymmetricCipherBase_nativeFinal(ctxAddress = %p, outArr = %p, outOfs = %d)", ++ ctx, outArr, outOfs); ++ if (ctx == NULL || outArr == NULL) { ++ goto cleanup; ++ } ++ int outLen = (*env)->GetArrayLength(env, outArr) - outOfs; ++ out = (unsigned char*)malloc(outLen); ++ if (out == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(out, 0, outLen); ++ int bytesWritten = 0; ++ int result_code = EVP_CipherFinal_ex(ctx, out, &bytesWritten); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ KAE_TRACE("KAESymmetricCipherBase_nativeFinal EVP_CipherFinal_ex success, bytesWritten = %d", bytesWritten); ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*)out); ++ free(out); ++ KAE_TRACE("KAESymmetricCipherBase_nativeFinal: finished"); ++ return bytesWritten; ++ ++cleanup: ++ if (out != NULL) { ++ free(out); ++ } ++ return 0; ++} ++ ++static void FreeMemoryFromFinalGcm(unsigned char* out, unsigned char* gcmTag, unsigned char* gcmOut) ++{ ++ if (out != NULL) { ++ free(out); ++ } ++ if (gcmTag != NULL) { ++ free(gcmTag); ++ } ++ if (gcmOut != NULL) { ++ free(gcmOut); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAECipherAES ++ * Method: nativeFinalGcm ++ * Signature: (J[BIZI[BZ)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeFinalGcm(JNIEnv* env, ++ jclass cls, jlong ctxAddress, jbyteArray outArr, jint outOfs, jboolean gcm, jint tagLength, ++ jbyteArray gcmTagArr, jboolean encrypt) ++{ ++ unsigned char* out = NULL; ++ unsigned char* gcmTag = NULL; ++ unsigned char* gcmOut = NULL; ++ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ if (ctx == NULL || outArr == NULL) { ++ goto cleanup; ++ } ++ ++ int bytesWritten = 0; ++ if (encrypt) { ++ int outLen = (*env)->GetArrayLength(env, outArr) - outOfs; ++ if ((out = malloc(outLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(out, 0, outLen); ++ if (EVP_CipherFinal_ex(ctx, out, &bytesWritten) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*)out); ++ ++ // Writes tagLength bytes of the tag value to the buffer. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CIPHER_CTX_ctrl.html} for details. ++ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tagLength, out + bytesWritten) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CIPHER_CTX_ctrl failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, outArr, outOfs + bytesWritten, tagLength, (jbyte*)(out + bytesWritten)); ++ bytesWritten += tagLength; ++ } else { ++ // gcmOut is the plaintext that has been decrypted in the EVP_CipherUpdate. ++ // outOfs is the length of the gcmOut, where it's always > 0. ++ if ((gcmTag = (unsigned char*)malloc(tagLength)) == NULL || (gcmOut = (unsigned char*)malloc(outOfs)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(gcmTag, 0, tagLength); ++ memset(gcmOut, 0, outOfs); ++ ++ (*env)->GetByteArrayRegion(env, gcmTagArr, 0, tagLength, (jbyte*)gcmTag); ++ // Sets the expected gcmTag to tagLength bytes from gcmTag. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CIPHER_CTX_ctrl.html} for details. ++ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tagLength, gcmTag) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CTRL_AEAD_SET_TAG failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ (*env)->GetByteArrayRegion(env, outArr, 0, outOfs, (jbyte*)gcmOut); ++ // Finalise: note get no output for GCM ++ if (EVP_CipherFinal_ex(ctx, gcmOut, &bytesWritten) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowAEADBadTagException); ++ goto cleanup; ++ } ++ } ++ FreeMemoryFromFinalGcm(out, gcmTag, gcmOut); ++ ++ return bytesWritten; ++ ++cleanup: ++ FreeMemoryFromFinalGcm(out, gcmTag, gcmOut); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeFree(JNIEnv* env, jclass cls, jlong ctxAddress) ++{ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ KAE_TRACE("KAESymmetricCipherBase_nativeFree(ctx = %p)", ctx); ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ ctx = NULL; ++ } ++ ++ KAE_TRACE("KAESymmetricCipherBase_nativeFree: finished"); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c +new file mode 100644 +index 000000000..471ae834b +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c +@@ -0,0 +1,246 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++ ++static ENGINE* kaeEngine = NULL; ++ ++void SetKaeEngine(ENGINE* engine) { ++ kaeEngine = engine; ++} ++ ++ENGINE* GetKaeEngine() { ++ return kaeEngine; ++} ++ ++BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray) { ++ if (byteArray == NULL) { ++ KAE_ThrowNullPointerException(env, "KAE_GetBigNumFromByteArray byteArray is null"); ++ return NULL; ++ } ++ ++ jsize len = (*env)->GetArrayLength(env, byteArray); ++ if (len == 0) { ++ KAE_ThrowRuntimeException(env, "KAE_GetBigNumFromByteArray byteArray is empty"); ++ return NULL; ++ } ++ ++ BIGNUM* bn = BN_new(); ++ if (bn == NULL) { ++ KAE_ThrowFromOpenssl(env, "BN_new", KAE_ThrowRuntimeException); ++ return NULL; ++ } ++ ++ jbyte* bytes = (*env)->GetByteArrayElements(env, byteArray, NULL); ++ if (bytes == NULL) { ++ KAE_ThrowNullPointerException(env,"GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ BIGNUM* result = BN_bin2bn((const unsigned char*) bytes, len, bn); ++ (*env)->ReleaseByteArrayElements(env, byteArray, bytes, 0); ++ if (result == NULL) { ++ KAE_ThrowFromOpenssl(env, "BN_bin2bn", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ return bn; ++ ++cleanup: ++ BN_free(bn); ++ return NULL; ++} ++ ++void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn) { ++ if (bn != NULL) { ++ BN_free(bn); ++ } ++} ++ ++jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn) { ++ if (bn == NULL) { ++ return NULL; ++ } ++ // bn size need plus 1, for example 65535 , BN_num_bytes return 2 ++ int bnSize = BN_num_bytes(bn); ++ if (bnSize <= 0) { ++ return NULL; ++ } ++ bnSize += 1; ++ jbyteArray javaBytes = (*env)->NewByteArray(env, bnSize); ++ if (javaBytes == NULL) { ++ KAE_ThrowOOMException(env, "New byte array failed."); ++ return NULL; ++ } ++ jbyte* bytes = (*env)->GetByteArrayElements(env, javaBytes, NULL); ++ if (bytes == NULL) { ++ KAE_ThrowNullPointerException(env,"GetByteArrayElements failed."); ++ return NULL; ++ } ++ unsigned char* tmp = (unsigned char*) bytes; ++ if (BN_bn2bin(bn, tmp + 1) <= 0) { ++ KAE_ThrowFromOpenssl(env, "BN_bn2bin", KAE_ThrowRuntimeException); ++ javaBytes = NULL; ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, javaBytes, 0, bnSize, bytes); ++ ++cleanup: ++ (*env)->ReleaseByteArrayElements(env, javaBytes, bytes, 0); ++ return javaBytes; ++} ++ ++#define ENGINE_LENGTH (EC_INDEX + 1) ++static ENGINE* engines[ENGINE_LENGTH] = {NULL}; ++static jboolean engineFlags[ENGINE_LENGTH] = {JNI_FALSE}; ++static KAEAlgorithm kaeAlgorithms[ENGINE_LENGTH] = { ++ {MD5_INDEX, "md5"}, ++ {SHA256_INDEX, "sha256"}, ++ {SHA384_INDEX, "sha384"}, ++ {SM3_INDEX, "sm3"}, ++ {AES_128_ECB_INDEX, "aes-128-ecb"}, ++ {AES_128_CBC_INDEX, "aes-128-cbc"}, ++ {AES_128_CTR_INDEX, "aes-128-ctr"}, ++ {AES_128_GCM_INDEX, "aes-128-gcm"}, ++ {AES_192_ECB_INDEX, "aes-192-ecb"}, ++ {AES_192_CBC_INDEX, "aes-192-cbc"}, ++ {AES_192_CTR_INDEX, "aes-192-ctr"}, ++ {AES_192_GCM_INDEX, "aes-192-gcm"}, ++ {AES_256_ECB_INDEX, "aes-256-ecb"}, ++ {AES_256_CBC_INDEX, "aes-256-cbc"}, ++ {AES_256_CTR_INDEX, "aes-256-ctr"}, ++ {AES_256_GCM_INDEX, "aes-256-gcm"}, ++ {SM4_ECB_INDEX, "sm4-ecb"}, ++ {SM4_CBC_INDEX, "sm4-cbc"}, ++ {SM4_CTR_INDEX, "sm4-ctr"}, ++ {SM4_OFB_INDEX, "sm4-ofb"}, ++ {HMAC_MD5_INDEX, "hmac-md5"}, ++ {HMAC_SHA1_INDEX, "hmac-sha1"}, ++ {HMAC_SHA224_INDEX, "hmac-sha224"}, ++ {HMAC_SHA256_INDEX, "hmac-sha256"}, ++ {HMAC_SHA384_INDEX, "hmac-sha384"}, ++ {HMAC_SHA512_INDEX, "hmac-sha512"}, ++ {RSA_INDEX, "rsa"}, ++ {DH_INDEX, "dh"}, ++ {EC_INDEX, "ec"} ++}; ++ ++void initEngines(JNIEnv* env, jbooleanArray algorithmKaeFlags) { ++ if (algorithmKaeFlags == NULL) { ++ return; ++ } ++ ++ // get jTemp ++ jboolean* jTemp = NULL; ++ int length = (*env)->GetArrayLength(env, algorithmKaeFlags); ++ jTemp = (jboolean*) malloc(length); ++ if (jTemp == NULL) { ++ KAE_ThrowOOMException(env, "initEngines GetArrayLength error"); ++ return; ++ } ++ (*env)->GetBooleanArrayRegion(env, algorithmKaeFlags, 0, length, jTemp); ++ ++ // assign engines ++ int minLen = length < ENGINE_LENGTH ? length : ENGINE_LENGTH; ++ int i; ++ for (i = 0; i < minLen; i++) { ++ if (jTemp[i]) { ++ engines[i] = kaeEngine; ++ engineFlags[i] = JNI_TRUE; ++ } ++ } ++ if (length < ENGINE_LENGTH) { ++ for (i = minLen; i < ENGINE_LENGTH; i++) { ++ engines[i] = kaeEngine; ++ engineFlags[i] = JNI_TRUE; ++ } ++ } ++ ++ // free jTemp ++ if (jTemp != NULL) { ++ free(jTemp); ++ } ++} ++ ++jbooleanArray getEngineFlags(JNIEnv* env) { ++ jbooleanArray array = (*env)->NewBooleanArray(env, ENGINE_LENGTH); ++ (*env)->SetBooleanArrayRegion(env, array, 0, ENGINE_LENGTH, engineFlags); ++ return array; ++} ++ ++ENGINE* GetEngineByAlgorithmIndex(AlgorithmIndex algorithmIndex) { ++ return engines[algorithmIndex]; ++} ++ ++/* ++ * Get the engine used by the specified algorithm. ++ * @param beginIndex the beginning index, inclusive. ++ * @param endIndex the ending index, exclusive. ++ * @param algorithmName algorithm name ++ * @return engine ++ */ ++ENGINE* GetEngineByBeginIndexAndEndIndex(int beginIndex, int endIndex, ++ const char* algorithmName) { ++ if (beginIndex < 0 || endIndex > ENGINE_LENGTH) { ++ return NULL; ++ } ++ ++ int i; ++ for (i = beginIndex; i < endIndex; i++) { ++ if (strcasecmp(kaeAlgorithms[i].algorithmName, algorithmName) == 0) { ++ return engines[kaeAlgorithms[i].algorithmIndex]; ++ } ++ } ++ return NULL; ++} ++ ++ENGINE* GetHmacEngineByAlgorithmName(const char* algorithmName) { ++ char prefix[] = {"hmac-"}; ++ int len = strlen(algorithmName); ++ int newLen = strlen(algorithmName) + strlen(prefix) + 1; ++ char* newAlgorithmName = NULL; ++ newAlgorithmName = malloc(newLen); ++ if (newAlgorithmName == NULL) { ++ return NULL; ++ } ++ strcpy(newAlgorithmName, prefix); ++ strcat(newAlgorithmName, algorithmName); ++ ENGINE* engine = GetEngineByBeginIndexAndEndIndex(HMAC_MD5_INDEX, HMAC_SHA512_INDEX + 1, newAlgorithmName); ++ if (newAlgorithmName != NULL) { ++ free(newAlgorithmName); ++ } ++ return engine; ++} ++ ++ENGINE* GetDigestEngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(MD5_INDEX, SM3_INDEX + 1, algorithmName); ++} ++ ++ENGINE* GetAesEngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(AES_128_ECB_INDEX, AES_256_GCM_INDEX + 1, algorithmName); ++} ++ ++ENGINE* GetSm4EngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(SM4_ECB_INDEX, SM4_OFB_INDEX + 1, algorithmName); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h +new file mode 100644 +index 000000000..6eb980d62 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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 KAE_UTIL_H ++#define KAE_UTIL_H ++ ++#include ++#include ++ ++typedef enum { ++ MD5_INDEX, ++ SHA256_INDEX, ++ SHA384_INDEX, ++ SM3_INDEX, ++ AES_128_ECB_INDEX, ++ AES_128_CBC_INDEX, ++ AES_128_CTR_INDEX, ++ AES_128_GCM_INDEX, ++ AES_192_ECB_INDEX, ++ AES_192_CBC_INDEX, ++ AES_192_CTR_INDEX, ++ AES_192_GCM_INDEX, ++ AES_256_ECB_INDEX, ++ AES_256_CBC_INDEX, ++ AES_256_CTR_INDEX, ++ AES_256_GCM_INDEX, ++ SM4_ECB_INDEX, ++ SM4_CBC_INDEX, ++ SM4_CTR_INDEX, ++ SM4_OFB_INDEX, ++ HMAC_MD5_INDEX, ++ HMAC_SHA1_INDEX, ++ HMAC_SHA224_INDEX, ++ HMAC_SHA256_INDEX, ++ HMAC_SHA384_INDEX, ++ HMAC_SHA512_INDEX, ++ RSA_INDEX, ++ DH_INDEX, ++ EC_INDEX ++} AlgorithmIndex; ++ ++typedef struct { ++ AlgorithmIndex algorithmIndex; ++ const char* algorithmName; ++} KAEAlgorithm; ++ ++/* jbyteArray convert to BIGNUM */ ++BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray); ++ ++/* release BIGNUM allocat from */ ++void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn); ++ ++/* BIGNUM convert to jbyteArray */ ++jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn); ++ ++void SetKaeEngine(ENGINE* engine); ++ ++ENGINE* GetKaeEngine(); ++ ++void initEngines(JNIEnv* env, jbooleanArray algorithmKaeFlags); ++ ++jbooleanArray getEngineFlags(JNIEnv* env); ++ ++ENGINE* GetEngineByAlgorithmIndex(AlgorithmIndex algorithmIndex); ++ ++ENGINE* GetHmacEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetDigestEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetAesEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetSm4EngineByAlgorithmName(const char* algorithmName); ++ ++#endif +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h +new file mode 100644 +index 000000000..f4b552137 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h +@@ -0,0 +1,10 @@ ++#include ++#include ++ ++#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 ++ ++// ERR_GET_FUNC() was removed since Openssl3 ++#ifndef ERR_GET_FUNC ++#define ERR_GET_FUNC(e) (int)(((e) >> 12L) & 0xFFFL) ++#endif ++#endif +diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups +index 386ea4160..338234faf 100644 +--- a/test/jdk/TEST.groups ++++ b/test/jdk/TEST.groups +@@ -255,6 +255,9 @@ jdk_security = \ + jdk_security_infra = \ + security/infra/java/security/cert/CertPathValidator/certification + ++jdk_kae_security = \ ++ org/openeuler/security/openssl ++ + jdk_text = \ + java/text \ + sun/text +diff --git a/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java b/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java +index 1e5eb9680..398e3ea2a 100644 +--- a/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java ++++ b/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java +@@ -39,6 +39,7 @@ import java.security.KeyPairGenerator; + import java.security.spec.NamedParameterSpec; + import java.security.spec.AlgorithmParameterSpec; + import java.security.spec.ECGenParameterSpec; ++import java.security.Security; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; +@@ -53,7 +54,13 @@ public class KeyAgreementTest { + String kpgAlgo = args[1]; + String provider = System.getProperty("test.provider.name", args[2]); + System.out.println("Testing " + kaAlgo); +- AlgoSpec aSpec = AlgoSpec.valueOf(AlgoSpec.class, kaAlgo); ++ AlgoSpec aSpec; ++ if (Security.getProperty("security.provider.1").equals("KAEProvider") && ++ kaAlgo.equals("ECDH")) { ++ aSpec = AlgoSpec.valueOf(AlgoSpec.class, "KAEECDH"); ++ } else { ++ aSpec = AlgoSpec.valueOf(AlgoSpec.class, kaAlgo); ++ } + List specs = aSpec.getAlgorithmParameterSpecs(); + for (AlgorithmParameterSpec spec : specs) { + testKeyAgreement(provider, kaAlgo, kpgAlgo, spec); +@@ -70,6 +77,7 @@ public class KeyAgreementTest { + // "java.base/share/classes/sun/security/util/CurveDB.java" + + ECDH("secp256r1", "secp384r1", "secp521r1"), ++ KAEECDH("secp224r1", "secp256r1", "secp384r1", "secp521r1"), + XDH("X25519", "X448", "x25519"), + // There is no curve for DiffieHellman + DiffieHellman(new String[]{}); +@@ -81,6 +89,7 @@ public class KeyAgreementTest { + for (String crv : curves) { + switch (this.name()) { + case "ECDH": ++ case "KAEECDH": + specs.add(new ECGenParameterSpec(crv)); + break; + case "XDH": +diff --git a/test/jdk/java/security/Signature/SignatureGetInstance.java b/test/jdk/java/security/Signature/SignatureGetInstance.java +index 821c20602..536c3ba67 100644 +--- a/test/jdk/java/security/Signature/SignatureGetInstance.java ++++ b/test/jdk/java/security/Signature/SignatureGetInstance.java +@@ -54,9 +54,13 @@ public class SignatureGetInstance { + MyPrivKey testPriv = new MyPrivKey(); + MyPubKey testPub = new MyPubKey(); + ++ Provider kaeProvider = Security.getProvider("KAEProvider"); ++ String expectedProvName = kaeProvider != null ? "KAEProvider" : "SunRsaSign"; ++ ++ + testDblInit(testPriv, testPub, true, "TestProvider"); + testDblInit(kp.getPrivate(), kp.getPublic(), true, +- System.getProperty("test.provider.name", "SunRsaSign")); ++ System.getProperty("test.provider.name", expectedProName)); + testDblInit(testPriv, kp.getPublic(), false, null); + testDblInit(kp.getPrivate(), testPub, false, null); + +diff --git a/test/jdk/org/openeuler/security/openssl/AESTest.java b/test/jdk/org/openeuler/security/openssl/AESTest.java +new file mode 100644 +index 000000000..aac14568d +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/AESTest.java +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.Security; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.Cipher; ++import javax.crypto.KeyGenerator; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.IvParameterSpec; ++ ++/** ++ * @test ++ * @summary Basic test for AES ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main AESTest ++ */ ++ ++public class AESTest { ++ private static final String[] ALGORITHM = {"AES", "AES_128", "AES_192", "AES_256"}; ++ private static final String[] MODES = {"ECB", "CBC", "CTR", "GCM"}; ++ private static final String[] PADDING = {"NoPadding", "PKCS5Padding"}; ++ private static final int AES_128_KEY_LENGTH = 128; ++ private static final int AES_192_KEY_LENGTH = 192; ++ private static final int AES_256_KEY_LENGTH = 256; ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String algo : ALGORITHM) { ++ for (String mode : MODES) { ++ int padKinds = 2; ++ if (mode.equalsIgnoreCase("CTR")) { ++ padKinds = 1; ++ } ++ for (int k = 0; k < padKinds; k++) { ++ test(algo, mode, PADDING[k]); ++ } ++ } ++ } ++ } ++ ++ public static void test(String algo, String mo, String pad) throws Exception { ++ AlgorithmParameterSpec aps = null; ++ ++ Cipher cipher = Cipher.getInstance(algo + "/" + mo + "/" + pad); ++ ++ KeyGenerator kg = KeyGenerator.getInstance("AES"); ++ if (algo.equalsIgnoreCase("AES_192")) { ++ kg.init(AES_192_KEY_LENGTH); ++ } else if (algo.equalsIgnoreCase("AES_256")) { ++ kg.init(AES_256_KEY_LENGTH); ++ } else { ++ kg.init(AES_128_KEY_LENGTH); ++ } ++ ++ SecretKey key = kg.generateKey(); ++ ++ // encrypt ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.ENCRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.ENCRYPT_MODE, key); ++ } ++ ++ String cipherString = null; ++ if (!pad.equalsIgnoreCase("NoPadding")) { ++ cipherString = shortPlainText; ++ } else { ++ cipherString = plainText; ++ } ++ byte[] cipherText = cipher.doFinal(cipherString.getBytes(StandardCharsets.UTF_8)); ++ if (!mo.equalsIgnoreCase("ECB")) { ++ aps = new IvParameterSpec(cipher.getIV()); ++ } else { ++ aps = null; ++ } ++ ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.DECRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.DECRYPT_MODE, key, cipher.getParameters()); ++ } ++ ++ String decryptPlainText = new String(cipher.doFinal(cipherText)); ++ ++ if (!cipherString.equals(decryptPlainText)) { ++ throw new RuntimeException("aes decryption failed, algo = " + algo + ", mo = " + mo + ", pad = " + pad); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/DHTest.java b/test/jdk/org/openeuler/security/openssl/DHTest.java +new file mode 100644 +index 000000000..51dab7664 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/DHTest.java +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++import java.io.Serializable; ++import java.math.BigInteger; ++import java.security.*; ++import java.util.Arrays; ++import javax.crypto.KeyAgreement; ++import javax.crypto.spec.*; ++import org.openeuler.security.openssl.KAEProvider; ++ ++/** ++ * This class implements the Diffie-Hellman key exchange algorithm. ++ * D-H means combining your private key with your partners public key to ++ * generate a number. The peer does the same with its private key and our ++ * public key. Through the magic of Diffie-Hellman we both come up with the ++ * same number. This number is secret (discounting MITM attacks) and hence ++ * called the shared secret. It has the same length as the modulus, e.g. 512 ++ * or 1024 bit. Man-in-the-middle attacks are typically countered by an ++ * independent authentication step using certificates (RSA, DSA, etc.). ++ * ++ * The thing to note is that the shared secret is constant for two partners ++ * with constant private keys. This is often not what we want, which is why ++ * it is generally a good idea to create a new private key for each session. ++ * Generating a private key involves one modular exponentiation assuming ++ * suitable D-H parameters are available. ++ * ++ * General usage of this class (TLS DHE case): ++ * . if we are server, call DHCrypt(keyLength,random). This generates ++ * an ephemeral keypair of the request length. ++ * . if we are client, call DHCrypt(modulus, base, random). This ++ * generates an ephemeral keypair using the parameters specified by ++ * the server. ++ * . send parameters and public value to remote peer ++ * . receive peers ephemeral public key ++ * . call getAgreedSecret() to calculate the shared secret ++ * ++ * In TLS the server chooses the parameter values itself, the client must use ++ * those sent to it by the server. ++ * ++ * The use of ephemeral keys as described above also achieves what is called ++ * "forward secrecy". This means that even if the authentication keys are ++ * broken at a later date, the shared secret remains secure. The session is ++ * compromised only if the authentication keys are already broken at the ++ * time the key exchange takes place and an active MITM attack is used. ++ * This is in contrast to straightforward encrypting RSA key exchanges. ++ * ++ */ ++ ++/** ++ * @test ++ * @summary Basic test for DH ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main DHTest ++ */ ++ ++public class DHTest implements Serializable { ++ private static BigInteger g512; ++ private static BigInteger p512; ++ ++ private static volatile Provider sunJceProvider; ++ private static volatile Provider kaeProvider; ++ ++ public static void main(String[] args) throws Exception { ++ Security.addProvider(new KAEProvider()); ++ sunJceProvider = Security.getProvider("SunJCE"); ++ kaeProvider = Security.getProvider("KAEProvider"); ++ ++ g512 = new BigInteger("30270326776012916323988175351831539351616124181011347910931933302640902603480679235129557617566480716138395926949700593986872757726720164601940036524221141391913433558162442022339559255078339658108149162251643458301671465579040759659507434340437396584664407572026953757806341363255195983514333141770938654900099033797866272818739547343977583089845850158637618703095710047154252655157633638171416516716598940884520592858762209135010804267830977334033327483815694794951984230264309784679409488441905236794443014066406150649287037909246107758452315504212879842042858577191624250834553614056794526338841821045329189780334"); ++ ++ p512 = new BigInteger("27672987386729926592037876826877634387173876890702920770064392919138769821035856568775311919542560094764667151024449425954917954337048895981297730855891532066350935045229294626339548842381843985759061682551900379979643117695834175891578650111093016914264824311693147701566019122696621248493126219217339690346346921463135605151471303957324058301097079967414639146647429422884520134312590056632178576758580657240245655739869017244657144448267757255018625514803292549109401806336918448001843022629625467069714240279603204909633404992842479161100500474744098408277938070656334892106100534117209709263785505019003765693651"); ++ ++ DHParameterSpec dhParams = new DHParameterSpec(p512, g512); ++ KeyPairGenerator SunJCEkeyGen = KeyPairGenerator.getInstance("DH", sunJceProvider); ++ KeyPairGenerator KAEkeyGen = KeyPairGenerator.getInstance("DH", kaeProvider); ++ SunJCEkeyGen.initialize(dhParams, new SecureRandom()); ++ KAEkeyGen.initialize(dhParams, new SecureRandom()); ++ KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", sunJceProvider); ++ KeyPair aPair = SunJCEkeyGen.generateKeyPair(); ++ KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", kaeProvider); ++ KeyPair bPair = KAEkeyGen.generateKeyPair(); ++ ++ aKeyAgree.init(aPair.getPrivate()); ++ bKeyAgree.init(bPair.getPrivate()); ++ ++ aKeyAgree.doPhase(bPair.getPublic(), true); ++ bKeyAgree.doPhase(aPair.getPublic(), true); ++ ++ MessageDigest hash = MessageDigest.getInstance("MD5"); ++ byte[] b1 = hash.digest(aKeyAgree.generateSecret()); ++ byte[] b2 = hash.digest(bKeyAgree.generateSecret()); ++ if(Arrays.equals(b1, b2)){ ++ System.out.println("SUCCESS!"); ++ }else{ ++ System.out.println("Failed!"); ++ throw new RuntimeException("Not Equal DH keyagreement ouput from SunJCE and KAE Provider!"); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/DigestTest.java b/test/jdk/org/openeuler/security/openssl/DigestTest.java +new file mode 100644 +index 000000000..120b6ac47 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/DigestTest.java +@@ -0,0 +1,61 @@ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.MessageDigest; ++import java.security.Security; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.Map; ++ ++/** ++ * @test ++ * @summary Basic test for MD5 SHA256 SHA384 ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm DigestTest ++ */ ++public class DigestTest { ++ private static String PLAIN_TEXT = "hello world"; ++ ++ private static Map alg = new HashMap(); ++ ++ static { ++ alg.put("MD5", new byte[] {94, -74, 59, -69, -32, 30, -18, -48, -109, -53, 34, -69, -113, 90, -51, -61}); ++ alg.put( ++ "SHA-256", ++ new byte[] { ++ -71, 77, 39, -71, -109, 77, 62, 8, -91, 46, 82, -41, -38, 125, -85, -6, ++ -60, -124, -17, -29, 122, 83, -128, -18, -112, -120, -9, -84, -30, -17, -51, -23 ++ }); ++ alg.put( ++ "SHA-384", ++ new byte[] { ++ -3, -67, -114, 117, -90, 127, 41, -9, 1, -92, -32, 64, 56, 94, 46, 35, ++ -104, 99, 3, -22, 16, 35, -110, 17, -81, -112, 127, -53, -72, 53, 120, -77, ++ -28, 23, -53, 113, -50, 100, 110, -3, 8, 25, -35, -116, 8, -115, -31, -67 ++ }); ++ alg.put( ++ "SM3", ++ new byte[] { ++ 68, -16, 6, 30, 105, -6, 111, -33, -62, -112, -60, -108, 101, 74, 5, ++ -36, 12, 5, 61, -89, -27, -59, 43, -124, -17, -109, -87, -42, 125, 63, ++ -1, -120 ++ }); ++ } ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String key : alg.keySet()) { ++ test(PLAIN_TEXT, key, alg.get(key)); ++ } ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ MessageDigest md = MessageDigest.getInstance(algo); ++ md.update(plainText.getBytes(StandardCharsets.UTF_8)); ++ byte[] res = md.digest(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException(algo + " failed"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/ECDHTest.java b/test/jdk/org/openeuler/security/openssl/ECDHTest.java +new file mode 100644 +index 000000000..791fec252 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/ECDHTest.java +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import sun.security.ec.ECPrivateKeyImpl; ++import sun.security.ec.ECPublicKeyImpl; ++ ++import javax.crypto.KeyAgreement; ++import java.math.BigInteger; ++import java.security.KeyPair; ++import java.security.KeyPairGenerator; ++import java.security.Provider; ++import java.security.Security; ++import java.security.spec.ECFieldFp; ++import java.security.spec.ECParameterSpec; ++import java.security.spec.ECPoint; ++import java.security.spec.EllipticCurve; ++import java.util.Arrays; ++import java.nio.charset.StandardCharsets; ++import java.security.spec.*; ++import java.security.KeyFactory; ++import java.security.interfaces.ECPrivateKey; ++import java.security.interfaces.ECPublicKey; ++ ++/** ++ * @test ++ * @summary Basic test for ECDH ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @modules jdk.crypto.ec/sun.security.ec ++ * @requires os.arch=="aarch64" ++ * @run main ECDHTest ++ */ ++ ++public class ECDHTest { ++ ++ private static KeyPairGenerator keyPairGenerator; ++ private static String algorithm = "EC"; ++ private static int[] keyArr = {224, 256, 384, 521}; ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ ++ BigInteger a = new BigInteger("26959946667150639794667015087019630673557916260026308143510066298878"); ++ BigInteger b = new BigInteger("18958286285566608000408668544493926415504680968679321075787234672564"); ++ BigInteger p = new BigInteger("26959946667150639794667015087019630673557916260026308143510066298881"); ++ BigInteger x = new BigInteger("19277929113566293071110308034699488026831934219452440156649784352033"); ++ BigInteger y = new BigInteger("19926808758034470970197974370888749184205991990603949537637343198772"); ++ EllipticCurve CURVE = new EllipticCurve(new ECFieldFp(p), a, b); ++ ECPoint POINT = new ECPoint(x, y); ++ BigInteger ORDER = new BigInteger("26959946667150639794667015087019625940457807714424391721682722368061"); ++ int COFACTOR = 1; ++ ECParameterSpec PARAMS = new ECParameterSpec(CURVE, POINT, ORDER, COFACTOR); ++ ++ testKeyPairByParam(PARAMS); ++ for (int keySize : keyArr) { ++ testKeyPairByKeySize(keySize); ++ } ++ ++ KeyFactory keyFactory = KeyFactory.getInstance("EC"); ++ ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger("20135071615800221517902437867016717688420688735490569283842831828983"), PARAMS); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl)keyFactory.generatePrivate(privateKeySpec); ++ ++ ECPoint ecPoint = new ECPoint(new BigInteger("9490267631555585552004372465967099662885480699902812460349461311384"), new BigInteger("1974573604976093871117393045089050409882519645527397292712281520811")); ++ ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(ecPoint,PARAMS); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl)keyFactory.generatePublic(publicKeySpec); ++ testKeyAgreement(ecPrivKey, ecPublicKey, new byte[]{-88, -65, 43, -84, 26, 43, 46, 106, 20, 39, -76, 30, -71, 72, -102, 120, 108, -92, -86, -14, -96, -42, 93, -40, -43, -25, 15, -62}); ++ } ++ ++ public static void testKeyPairByParam(ECParameterSpec PARAMS) throws Exception { ++ keyPairGenerator = KeyPairGenerator.getInstance(algorithm); ++ keyPairGenerator.initialize(PARAMS); ++ KeyPair keyPair = keyPairGenerator.generateKeyPair(); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl) keyPair.getPrivate(); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl) keyPair.getPublic(); ++ } ++ ++ public static void testKeyPairByKeySize(int keySize) throws Exception { ++ keyPairGenerator = KeyPairGenerator.getInstance(algorithm); ++ keyPairGenerator.initialize(keySize); ++ KeyPair keyPair = keyPairGenerator.generateKeyPair(); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl) keyPair.getPrivate(); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl) keyPair.getPublic(); ++ } ++ ++ public static void testKeyAgreement(ECPrivateKeyImpl ecPrivKey, ECPublicKeyImpl ecPublicKey, byte[] expectRes) throws Exception { ++ KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH"); ++ keyAgreement.init(ecPrivKey); ++ keyAgreement.doPhase(ecPublicKey, true); ++ byte[] res = keyAgreement.generateSecret(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException("keyagreement failed"); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/HmacTest.java b/test/jdk/org/openeuler/security/openssl/HmacTest.java +new file mode 100644 +index 000000000..bddc37b4c +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/HmacTest.java +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Mac; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.Key; ++import java.security.Security; ++import java.util.Arrays; ++ ++/** ++ * @test ++ * @summary test for Hmac ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm HmacTest ++ */ ++public class HmacTest { ++ private static final byte[] PLAIN_BYTES = "hello world".getBytes(); ++ private static final String[] ALGORITHMS = new String[]{ ++ "HmacMD5", ++ "HmacSHA1", ++ "HmacSHA224", ++ "HmacSHA256", ++ "HmacSHA384", ++ "HmacSHA512", ++ }; ++ private static final byte[][] EXPECTED_BYTES = { ++ {-40, 63, -96, 13, 107, -33, -1, -53, -116, 117, 75, -6, 85, -88, -112, -90}, ++ {-68, 104, 112, -36, 123, 123, -92, 104, 89, -90, 63, 56, 84, 45, 12, -7, 41, 103, -105, -27}, ++ {-31, 0, 103, 51, -119, -61, 2, -76, -83, -113, 95, 86, 8, 46, 91, 20, ++ -15, -23, -71, 62, -50, 86, -54, 71, -94, -47, -103, 43}, ++ {-69, -83, -3, 7, 61, 38, -122, -59, 7, -53, 106, 114, 58, 102, 65, -118, ++ 54, -50, 116, -56, 110, 54, -71, 36, 60, 84, 14, 97, 78, 18, -119, -24}, ++ {100, -58, 106, 64, -96, 91, 99, -33, 36, -78, -53, -50, -78, 116, -110, 85, ++ 84, -5, -63, 17, 51, -69, -39, -122, 65, 8, -122, -43, 39, 13, -41, -52, ++ 45, -38, -59, 70, 17, -87, -63, -126, 4, 120, -77, 71, 119, 96, -2, -68}, ++ {-89, 47, -98, -12, 110, -88, 23, 2, 28, 26, -71, 53, -108, 54, -52, 1, ++ -121, -121, 87, 6, -78, 123, -14, -86, 127, 114, 124, -73, -98, 79, -122, 69, ++ -32, 50, 48, -79, -110, 66, 38, 70, -3, -76, 95, 55, 74, 48, 57, -121, ++ 22, 60, -83, -109, 59, 79, 0, -49, 107, 88, -82, -35, 87, -36, 49, -54} ++ }; ++ private static final Key key = new SecretKeySpec("mac".getBytes(), ""); ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (int i = 0; i < ALGORITHMS.length; i++) { ++ test(ALGORITHMS[i], key, PLAIN_BYTES, EXPECTED_BYTES[i]); ++ } ++ } ++ ++ private static void test(String algorithm, Key key, byte[] inputBytes, byte[] expectedBytes) throws Exception { ++ Mac mac = Mac.getInstance(algorithm); ++ mac.init(key); ++ mac.update(inputBytes); ++ byte[] bytes = mac.doFinal(); ++ if (!(mac.getProvider() instanceof KAEProvider)) { ++ throw new RuntimeException(algorithm + " failed," + ++ "provider=" + mac.getProvider().getClass() + "," + ++ "expectedProvider=" + KAEProvider.class); ++ } ++ if (!Arrays.equals(bytes, expectedBytes)) { ++ throw new RuntimeException(algorithm + " failed," + ++ "bytes=" + Arrays.toString(bytes) + "," + ++ "expectedBytes=" + Arrays.toString(expectedBytes)); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEConfTest.java b/test/jdk/org/openeuler/security/openssl/KAEConfTest.java +new file mode 100644 +index 000000000..4076aa2fc +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEConfTest.java +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEConfig; ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.io.FileWriter; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE Conf ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm KAEConfTest DEFAULT ++ * @run main/othervm KAEConfTest SPECIFY ++ */ ++public class KAEConfTest { ++ private static final String DEFAULT_CONF = System.getProperty("java.home") + ++ File.separator + "conf" + File.separator + "kaeprovider.conf"; ++ ++ private static final String SPECIFY_CONF = System.getProperty("user.dir") + ++ File.separator + "kaeprovider.conf"; ++ ++ private static final String SPECIFY_LOG_PATH = System.getProperty("user.dir") + File.separator + "kae.log"; ++ private static final List files = new ArrayList<>(); ++ ++ enum Mode { ++ DEFAULT, ++ SPECIFY ++ } ++ ++ public static void main(String[] args) throws IOException { ++ Mode mode = getMode(args); ++ try { ++ init(mode); ++ new KAEProvider(); ++ test(mode); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode(String[] args) { ++ if (args.length <= 0) { ++ return Mode.DEFAULT; ++ } ++ return Mode.valueOf(args[0]); ++ } ++ ++ private static void init(Mode mode) throws IOException { ++ if (Mode.SPECIFY.equals(mode)) { ++ System.setProperty("kae.conf", SPECIFY_CONF); ++ File file = new File(SPECIFY_CONF); ++ if (!file.exists()) { ++ Files.createFile(file.toPath()); ++ } ++ files.add(file); ++ try (FileWriter fileWriter = new FileWriter(file)) { ++ fileWriter.write("kae.log=true"); ++ fileWriter.flush(); ++ } ++ } ++ } ++ ++ private static void testDefault() { ++ File file = new File(DEFAULT_CONF); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ ++ private static void testSpecify() { ++ String value = KAEConfig.privilegedGetOverridable("kae.log"); ++ if (!"true".equals(value)) { ++ throw new RuntimeException("test failed : kae.log=" + value); ++ } ++ File file = new File(SPECIFY_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException(SPECIFY_LOG_PATH + "does not exist"); ++ } ++ // kae log file ++ files.add(file); ++ } ++ ++ private static void test(Mode mode) { ++ switch (mode) { ++ case DEFAULT: ++ testDefault(); ++ break; ++ case SPECIFY: ++ testSpecify(); ++ break; ++ default: ++ throw new IllegalArgumentException("invalid mode"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java b/test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java +new file mode 100644 +index 000000000..e8d767f0c +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java +@@ -0,0 +1,165 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEConfig; ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++/* ++ * @test ++ * @summary Test property kae.engine.disableAlgorithms ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm3 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ofb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha1 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha224 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha512 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=rsa KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=dh KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-gcm,aes-192-gcm,aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=md5,aes-128-ecb,sm4-ecb,hmac-sha1,rsa,dh,ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm3 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ofb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha1 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha224 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha512 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=rsa KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=dh KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-gcm,aes-192-gcm,aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=md5,aes-128-ecb,sm4-ecb,hmac-sha1,rsa,dh,ec KAEDisabledAlgorithmsTest ++ */ ++public class KAEDisabledAlgorithmsTest { ++ ++ public static void main(String[] args) { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ String[] disabledAlgorithms = getDisabledAlgorithms(); ++ init(); ++ new KAEProvider(); ++ test(disabledAlgorithms); ++ } ++ ++ private static final String[] PROPERTY_NAMES = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ private static String[] getDisabledAlgorithms() { ++ String value = System.getProperty("kae.engine.disabledAlgorithms"); ++ if (value == null) { ++ return new String[0]; ++ } ++ return value.split(","); ++ } ++ ++ private static void init() { ++ for (String propertyName : PROPERTY_NAMES) { ++ System.setProperty(propertyName, "true"); ++ } ++ } ++ ++ private static void test(String[] disabledAlgorithms) { ++ boolean[] useKaeEngineFlags = KAEConfig.getUseKaeEngineFlags(); ++ Set disabledAlgorithmIndexSet = new HashSet<>(); ++ ++ // test disabled algorithms ++ for (String disabledAlgorithm : disabledAlgorithms) { ++ Integer index = KAETestHelper.getAlgorithmIndex(disabledAlgorithm); ++ if (index == null || index < 0 || index >= useKaeEngineFlags.length) { ++ continue; ++ } ++ if (useKaeEngineFlags[index]) { ++ throw new RuntimeException("test failed"); ++ } ++ disabledAlgorithmIndexSet.add(index); ++ } ++ ++ // test other algorithms that are not disabled (except ec) ++ for (int i = 0; i < useKaeEngineFlags.length - 1; i++) { ++ if (!disabledAlgorithmIndexSet.contains(i) && !useKaeEngineFlags[i]) { ++ throw new RuntimeException(KAETestHelper.getAlgorithmName(i) + " algorithm is not disabled"); ++ } ++ } ++ ++ // test whether the ec algorithm is disabled by default ++ if (useKaeEngineFlags[useKaeEngineFlags.length - 1]) { ++ throw new RuntimeException(KAETestHelper.getAlgorithmName(useKaeEngineFlags.length - 1) ++ + " algorithm is disabled by default"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java b/test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java +new file mode 100644 +index 000000000..75248a432 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE property kae.engine.id and kae.libcrypto.useGlobalMode ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.log=true KAEEngineIdTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=kae KAEEngineIdTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true KAEEngineIdTest ++ */ ++public class KAEEngineIdTest { ++ ++ private static final String LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final List files = new ArrayList<>(); ++ ++ public static void main(String[] args) throws IOException { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ ++ try { ++ new KAEProvider(); ++ test(engine); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static void test(KAETestHelper.Engine engine) throws IOException { ++ File file = new File(LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException(LOG_PATH + " does not exist"); ++ } ++ files.add(file); ++ try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { ++ String s = bufferedReader.readLine(); ++ if (!s.contains(engine.getEngineId() + " engine was found")) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAELogTest.java b/test/jdk/org/openeuler/security/openssl/KAELogTest.java +new file mode 100644 +index 000000000..f635d96f3 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAELogTest.java +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE log ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm KAELogTest ++ * @run main/othervm -Dkae.log=false KAELogTest ++ * @run main/othervm -Dkae.log=true KAELogTest ++ * @run main/othervm -Dkae.log=true -Dkae.log.file=./KAELogTest/kae.log KAELogTest ++ */ ++public class KAELogTest { ++ private static final String DEFAULT_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final String SPECIFY_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "KAELogTest" + File.separator + "kae.log"; ++ ++ private static final List files = new ArrayList<>(); ++ ++ enum Mode { ++ DEFAULT, ++ DISABLE, ++ ENABLE, ++ SPECIFY ++ } ++ ++ public static void main(String[] args) { ++ Mode mode = getMode(); ++ try { ++ new KAEProvider(); ++ test(mode); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode() { ++ String enableKaeLog = System.getProperty("kae.log"); ++ if (enableKaeLog == null) { ++ return Mode.DEFAULT; ++ } else if ("false".equals(enableKaeLog)) { ++ return Mode.DISABLE; ++ } else { ++ String logPath = System.getProperty("kae.log.file"); ++ if (logPath == null) { ++ return Mode.ENABLE; ++ } ++ return Mode.SPECIFY; ++ } ++ } ++ ++ private static void testDefault() { ++ testDisable(); ++ } ++ ++ private static void testDisable() { ++ File file = new File(DEFAULT_LOG_PATH); ++ if (file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ ++ private static void testEnable() { ++ File file = new File(DEFAULT_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ files.add(file); ++ } ++ ++ private static void testSpecify() { ++ File file = new File(KAELogTest.SPECIFY_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ files.add(file); ++ files.add(file.getParentFile()); ++ } ++ ++ private static void test(Mode mode) { ++ switch (mode) { ++ case DEFAULT: ++ testDefault(); ++ break; ++ case DISABLE: ++ testDisable(); ++ break; ++ case ENABLE: ++ testEnable(); ++ break; ++ case SPECIFY: ++ testSpecify(); ++ break; ++ default: ++ throw new IllegalArgumentException("invalid mode"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAETestHelper.java b/test/jdk/org/openeuler/security/openssl/KAETestHelper.java +new file mode 100644 +index 000000000..59ad91ddc +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAETestHelper.java +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++class KAETestHelper { ++ private static final String KAE_ENGINE_ID = "kae"; ++ private static final String UADK_ENGINE_ID = "uadk_engine"; ++ private static boolean hasKaeEngine; ++ private static boolean hasUadkEngine; ++ ++ private static String engineRootPath; ++ ++ // algorithm names ++ private static final String[] ALGORITHM_NAMES = new String[]{ ++ "md5", ++ "sha256", ++ "sha384", ++ "sm3", ++ "aes-128-ecb", ++ "aes-128-cbc", ++ "aes-128-ctr", ++ "aes-128-gcm", ++ "aes-192-ecb", ++ "aes-192-cbc", ++ "aes-192-ctr", ++ "aes-192-gcm", ++ "aes-256-ecb", ++ "aes-256-cbc", ++ "aes-256-ctr", ++ "aes-256-gcm", ++ "sm4-ecb", ++ "sm4-cbc", ++ "sm4-ctr", ++ "sm4-ofb", ++ "hmac-md5", ++ "hmac-sha1", ++ "hmac-sha224", ++ "hmac-sha256", ++ "hmac-sha384", ++ "hmac-sha512", ++ "rsa", ++ "dh", ++ "ec" ++ }; ++ private static final Map ALGORITHM_NAME_MAP = new HashMap<>(); ++ ++ private static final String PROVIDER_NAME = "KAEProvider"; ++ private static final String USE_OPENSSL_MSG = "Use openssl soft calculation"; ++ private static final String USE_KAE_HARDWARE_MSG = "enable KAE hardware acceleration"; ++ private static final Map ALGORITHM_MSG_MAP = new HashMap<>(); ++ ++ static { ++ init(); ++ } ++ ++ enum Engine { ++ default_engine(hasKaeEngine, KAE_ENGINE_ID), ++ kae(hasKaeEngine, KAE_ENGINE_ID), ++ uadk_engine(hasUadkEngine, UADK_ENGINE_ID); ++ private final boolean isValid; ++ private final String engineId; ++ ++ Engine(boolean isValid, String engineId) { ++ this.isValid = isValid; ++ this.engineId = engineId; ++ } ++ ++ public boolean isValid() { ++ return isValid; ++ } ++ ++ public String getEngineId() { ++ return engineId; ++ } ++ } ++ ++ private static void init() { ++ engineRootPath = System.getenv("OPENSSL_ENGINES"); ++ if (engineRootPath == null || engineRootPath.equals("")) { ++ System.out.println("Environment variable OPENSSL_ENGINES is not configured"); ++ } ++ hasKaeEngine = hasEngine(KAE_ENGINE_ID); ++ hasUadkEngine = hasEngine(UADK_ENGINE_ID); ++ ++ for (int i = 0; i < ALGORITHM_NAMES.length; i++) { ++ ALGORITHM_NAME_MAP.put(ALGORITHM_NAMES[i], i); ++ } ++ ++ ALGORITHM_MSG_MAP.put(USE_OPENSSL_MSG, false); ++ ALGORITHM_MSG_MAP.put(USE_KAE_HARDWARE_MSG, true); ++ } ++ ++ static Integer getAlgorithmIndex(String algorithmName) { ++ return ALGORITHM_NAME_MAP.get(algorithmName); ++ } ++ ++ static String getAlgorithmName(Integer algorithmIndex) { ++ return ALGORITHM_NAMES[algorithmIndex]; ++ } ++ ++ private static boolean hasEngine(String engineId) { ++ String filePath = engineRootPath + File.separator + engineId + ".so"; ++ File file = new File(filePath); ++ return file.exists(); ++ } ++ ++ static boolean hasKaeEngine() { ++ return hasKaeEngine; ++ } ++ ++ static boolean hasUadkEngine() { ++ return hasUadkEngine; ++ } ++ ++ static void cleanUp(List files) { ++ for (File file : files) { ++ System.out.println("delete file : " + file); ++ file.delete(); ++ } ++ } ++ ++ static boolean[] parseLog(Engine engine, File file) throws IOException { ++ boolean[] kaeUseEngineFlags; ++ String expectedEngineMsg = engine.getEngineId() + " engine was found"; ++ try (BufferedReader reader = new BufferedReader(new FileReader(file))) { ++ // load engine message ++ String engineMsg = reader.readLine(); ++ if (engineMsg == null || !engineMsg.contains(expectedEngineMsg)) { ++ throw new RuntimeException("test failed : actual message :" + engineMsg); ++ } ++ ++ // summary message ++ String summaryMessage = reader.readLine(); ++ if (summaryMessage == null) { ++ throw new RuntimeException("test failed : summary message is null"); ++ } ++ ++ kaeUseEngineFlags = new boolean[ALGORITHM_NAMES.length]; ++ // strategy of each algorithm ++ String strategy; ++ while ((strategy = reader.readLine()) != null) { ++ String[] splitArray = strategy.split("=>"); ++ if (splitArray.length < 2) { ++ throw new RuntimeException("test failed : strategy = " + strategy); ++ } ++ ++ // algorithm Index ++ String algorithm = splitArray[0].replace(" ", ""); ++ Integer algorithmIndex = ALGORITHM_NAME_MAP.get(algorithm); ++ if (algorithmIndex == null) { ++ throw new RuntimeException("test failed : illegal algorithm " + algorithm); ++ } ++ ++ // provider and algorithm value ++ String detail = splitArray[1]; ++ String[] detailArray = detail.split(":"); ++ if (detailArray.length < 2) { ++ throw new RuntimeException("test failed : detail=" + strategy); ++ } ++ String provider = detailArray[0].replace(" ", ""); ++ if (!PROVIDER_NAME.equals(provider)) { ++ throw new RuntimeException("test failed : provider= " + provider); ++ } ++ String algorithmMsg = detailArray[1].trim(); ++ Boolean algorithmValue = ALGORITHM_MSG_MAP.get(algorithmMsg); ++ if (algorithmValue == null) { ++ throw new RuntimeException("test failed : algorithmMsg= " + algorithmMsg); ++ } ++ kaeUseEngineFlags[algorithmIndex] = algorithmValue; ++ } ++ } ++ return kaeUseEngineFlags; ++ } ++ ++ static KAETestHelper.Engine getEngine() { ++ String engineId = System.getProperty("kae.engine.id"); ++ if (engineId == null) { ++ return KAETestHelper.Engine.default_engine; ++ } ++ return KAETestHelper.Engine.valueOf(engineId); ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java b/test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java +new file mode 100644 +index 000000000..a5b9b5386 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java +@@ -0,0 +1,263 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++/* ++ * @test ++ * @summary Test KAE property kae..useKaeEngine ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.log=true -Dall.test=default KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.digest.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=enable -Dkae.digest.useKaeEngine=true -Dkae.aes.useKaeEngine=true -Dkae.sm4.useKaeEngine=true -Dkae.hmac.useKaeEngine=true -Dkae.rsa.useKaeEngine=true -Dkae.dh.useKaeEngine=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.digest.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=disable -Dkae.digest.useKaeEngine=false -Dkae.aes.useKaeEngine=false -Dkae.sm4.useKaeEngine=false -Dkae.hmac.useKaeEngine=false -Dkae.rsa.useKaeEngine=false -Dkae.dh.useKaeEngine=false -Dkae.ec.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=default -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=enable -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=true -Dkae.aes.useKaeEngine=true -Dkae.sm4.useKaeEngine=true -Dkae.hmac.useKaeEngine=true -Dkae.rsa.useKaeEngine=true -Dkae.dh.useKaeEngine=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=disable -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=false -Dkae.aes.useKaeEngine=false -Dkae.sm4.useKaeEngine=false -Dkae.hmac.useKaeEngine=false -Dkae.rsa.useKaeEngine=false -Dkae.dh.useKaeEngine=false -Dkae.ec.useKaeEngine=false KAEUseEngineTest ++ */ ++public class KAEUseEngineTest { ++ enum Mode { ++ DEFAULT(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }), ++ DIGEST_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 0, true), ++ AES_ENABLE(new boolean[]{ ++ true, false, false, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 1, true), ++ SM4_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 2, true), ++ HMAC_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ true, true, true, true, true, true, true, true, false ++ }, 3, true), ++ RSA_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 4, true), ++ DH_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 5, true), ++ EC_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 6, true), ++ ALL_ENABLE(new boolean[]{ ++ true, false, false, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, false ++ }, true), ++ DIGEST_DISABLE(new boolean[]{ ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 0, false), ++ AES_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 1, false), ++ SM4_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, false ++ }, 2, false), ++ HMAC_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 3, false), ++ RSA_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, false, true, false ++ }, 4, false), ++ DH_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, false, false ++ }, 5, false), ++ EC_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 6, false), ++ ALL_DISABLE(new boolean[]{ ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false ++ }, false); ++ private final boolean[] expectedResult; ++ private final Integer propertyNameIndex; ++ private final boolean enable; ++ private static final Map modeMap = new HashMap<>(); ++ ++ static { ++ Mode[] modes = Mode.values(); ++ for (Mode mode : modes) { ++ if (mode.propertyNameIndex != null) { ++ modeMap.put(PROPERTY_NAMES[mode.propertyNameIndex] + ":" + mode.enable, mode); ++ } ++ } ++ modeMap.put("default", DEFAULT); ++ modeMap.put("disable", ALL_DISABLE); ++ modeMap.put("enable", ALL_ENABLE); ++ } ++ ++ Mode(boolean[] expectedResult) { ++ this(expectedResult, false); ++ } ++ ++ Mode(boolean[] expectedResult, boolean enable) { ++ this(expectedResult, null, enable); ++ } ++ ++ Mode(boolean[] expectedResult, Integer propertyNameIndex, boolean enable) { ++ this.expectedResult = expectedResult; ++ this.propertyNameIndex = propertyNameIndex; ++ this.enable = enable; ++ } ++ ++ static Mode getMode(String name, Boolean enable) { ++ return modeMap.get(name + ":" + enable); ++ } ++ ++ static Mode getMode(String key) { ++ return modeMap.get(key); ++ } ++ } ++ ++ private static final String KAE_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final String[] PROPERTY_NAMES = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ private static final List files = new ArrayList<>(); ++ ++ public static void main(String[] args) throws IOException { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ Mode mode = getMode(); ++ if (mode == null) { ++ throw new RuntimeException("test failed: mode is null"); ++ } ++ ++ try { ++ new KAEProvider(); ++ test(mode, engine); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode() { ++ String value = System.getProperty("all.test"); ++ if (value != null) { ++ return Mode.getMode(value); ++ } ++ for (String propertyName : PROPERTY_NAMES) { ++ String property = System.getProperty(propertyName); ++ Boolean enable = null; ++ if (property != null) { ++ enable = Boolean.valueOf(property); ++ } ++ Mode mode = Mode.getMode(propertyName, enable); ++ if (mode != null) { ++ return mode; ++ } ++ } ++ return null; ++ } ++ ++ private static void test(Mode mode, KAETestHelper.Engine engine) throws IOException { ++ File file = new File(KAE_LOG_PATH); ++ files.add(file); ++ boolean[] kaeUseEngineFlags = KAETestHelper.parseLog(engine, file); ++ if (!Arrays.equals(mode.expectedResult, kaeUseEngineFlags)) { ++ throw new RuntimeException("test failed : expected : " + Arrays.toString(mode.expectedResult) + "," + ++ "actual:" + Arrays.toString(kaeUseEngineFlags)); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java b/test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java +new file mode 100644 +index 000000000..7bffbd6ec +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Cipher; ++import javax.crypto.spec.SecretKeySpec; ++import java.io.PrintStream; ++import java.nio.charset.StandardCharsets; ++import java.nio.file.Files; ++import java.nio.file.Paths; ++import java.security.Security; ++import java.util.Objects; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++ ++/** ++ * @test ++ * @summary test for KaeDebugLogTest ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Djava.security.debug=kae -Dkae.sm4.maxChunkSize=65536 KaeDebugLogTest ++ * @run main/othervm -Djava.security.debug=kae KaeDebugLogTest ++ * @run main/othervm -Djava.security.auth.debug=kae KaeDebugLogTest ++ * @run main/othervm KaeDebugLogTest ++ */ ++ ++public class KaeDebugLogTest { ++ ++ private static final PrintStream err = System.err; ++ ++ public static void main(String[] args) throws Exception { ++ PrintStream printStream = new PrintStream("kaetest.out"); ++ System.setErr(printStream); ++ testDebugLog(); ++ System.setErr(printStream); ++ testSm4ChunkSize(); ++ } ++ ++ public static void testDebugLog() throws Exception { ++ new KAEProvider(); ++ Stream lines = Files.lines(Paths.get("kaetest.out")); ++ System.setErr(err); ++ String content = lines.collect(Collectors.joining(System.lineSeparator())); ++ if(("kae".equals(System.getProperty("java.security.debug")) ++ || "kae".equals(System.getProperty("java.security..auth.debug"))) ++ && !content.contains("reading kae properties file:")){ ++ throw new RuntimeException("KaeDebugLogTest Failed! Failed to set the debug log."); ++ } ++ lines.close(); ++ } ++ ++ public static void testSm4ChunkSize() throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ Cipher cipher = Cipher.getInstance("SM4"); ++ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("sm4EncryptionKey".getBytes(StandardCharsets.UTF_8), "SM4")); ++ Stream lines = Files.lines(Paths.get("kaetest.out")); ++ System.setErr(err); ++ String content = lines.collect(Collectors.joining(System.lineSeparator())); ++ String log = "The configured chunk size is " + System.getProperty("kae.sm4.maxChunkSize"); ++ if(("kae".equals(System.getProperty("java.security.debug")) ++ || "kae".equals(System.getProperty("java.security..auth.debug"))) ++ && Objects.nonNull(System.getProperty("kae.sm4.maxChunkSize")) &&!content.contains(log)){ ++ throw new RuntimeException("KaeDebugLogTest Failed! Failed to set the kae.sm4.maxChunkSize = " + System.getProperty("kae.sm4.maxChunkSize")); ++ } ++ lines.close(); ++ } ++ ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KaeProviderTest.java b/test/jdk/org/openeuler/security/openssl/KaeProviderTest.java +new file mode 100644 +index 000000000..0f4425b6d +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KaeProviderTest.java +@@ -0,0 +1,171 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Cipher; ++import javax.crypto.Mac; ++import javax.crypto.NoSuchPaddingException; ++import java.security.KeyPairGenerator; ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.Security; ++ ++/** ++ * @test ++ * @requires os.arch=="aarch64" ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @summary test for KaeProviderTest ++ * @run main/othervm KaeProviderTest ++ * @run main/othervm KaeProviderTest true ++ * @run main/othervm KaeProviderTest false ++ * @run main/othervm KaeProviderTest wrong ++ */ ++ ++public class KaeProviderTest { ++ ++ private static final String[] algorithmKaeProviderPropertyNames = new String[]{ ++ "kae.md5", ++ "kae.sha256", ++ "kae.sha384", ++ "kae.sm3", ++ "kae.aes", ++ "kae.sm4", ++ "kae.hmac", ++ "kae.rsa", ++ "kae.dh", ++ "kae.ec" ++ }; ++ ++ private static final String KAE = "KAEProvider"; ++ ++ public static void main(String[] args) throws Exception { ++ initProperty(args); ++ Security.insertProviderAt(new KAEProvider(), 1); ++ testALL(); ++ } ++ ++ private static void initProperty(String[] args) { ++ if (args.length <= 0) { ++ return; ++ } ++ String value = args[0]; ++ for (String name : algorithmKaeProviderPropertyNames){ ++ System.setProperty(name,value); ++ } ++ } ++ ++ public static void testALL() throws Exception { ++ testMd5(); ++ testSha256(); ++ testSha384(); ++ testSm3(); ++ testAes(); ++ testSm4(); ++ testHmac(); ++ testRsa(); ++ testDh(); ++ testEc(); ++ } ++ ++ public static void testMd5() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("MD5"); ++ judge("kae.md5",messageDigest.getProvider().getName()); ++ ++ } ++ ++ public static void testSha256() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); ++ judge("kae.sha256",messageDigest.getProvider().getName()); ++ } ++ ++ public static void testSha384() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("SHA-384"); ++ judge("kae.sha384",messageDigest.getProvider().getName()); ++ } ++ ++ public static void testSm3() throws NoSuchAlgorithmException { ++ try{ ++ MessageDigest messageDigest = MessageDigest.getInstance("SM3"); ++ judge("kae.sm3",messageDigest.getProvider().getName()); ++ }catch (NoSuchAlgorithmException e){ ++ if(Boolean.parseBoolean(System.getProperty("kae.sm3"))){ ++ throw e; ++ } ++ } ++ } ++ ++ public static void testAes() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ Cipher cipher = Cipher.getInstance("AES"); ++ judge("kae.aes",cipher.getProvider().getName()); ++ } ++ ++ public static void testSm4() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ try{ ++ Cipher cipher = Cipher.getInstance("SM4"); ++ judge("kae.sm4",cipher.getProvider().getName()); ++ }catch (NoSuchAlgorithmException e){ ++ if(Boolean.parseBoolean(System.getProperty("kae.sm4"))){ ++ throw e; ++ } ++ } ++ } ++ ++ public static void testHmac() throws NoSuchAlgorithmException { ++ Mac mac = Mac.getInstance("HmacMD5"); ++ judge("kae.hmac",mac.getProvider().getName()); ++ } ++ ++ public static void testRsa() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ Cipher cipher = Cipher.getInstance("RSA"); ++ judge("kae.rsa",cipher.getProvider().getName()); ++ } ++ ++ public static void testDh() throws NoSuchAlgorithmException { ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); ++ judge("kae.dh",keyPairGenerator.getProvider().getName()); ++ } ++ ++ public static void testEc() throws NoSuchAlgorithmException { ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); ++ judge("kae.ec",keyPairGenerator.getProvider().getName()); ++ } ++ ++ private static void judge(String algorithm , String providerName){ ++ String value = System.getProperty(algorithm); ++ if (value == null) { ++ if (!KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! default Provider.name is not right!"); ++ } ++ } else { ++ if (Boolean.parseBoolean(value) && !KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! " + algorithm + " is " + value + "," + ++ " Provider.name is not right!"); ++ } ++ if (!Boolean.parseBoolean(value) && KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! " + algorithm + " is " + value + ", " + ++ " Provider.name is not right!"); ++ } ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/RSATest.java b/test/jdk/org/openeuler/security/openssl/RSATest.java +new file mode 100644 +index 000000000..8a787e1f7 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/RSATest.java +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.Security; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.Cipher; ++import javax.crypto.KeyGenerator; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.IvParameterSpec; ++ ++/** ++ * @test ++ * @summary Basic test for AES ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main AESTest ++ */ ++ ++public class AESTest { ++ private static final String[] ALGORITHM = {"AES", "AES_128", "AES_192", "AES_256"}; ++ private static final String[] MODES = {"ECB", "CBC", "CTR", "GCM"}; ++ private static final String[] PADDING = {"NoPadding", "PKCS5Padding"}; ++ private static final int AES_128_KEY_LENGTH = 128; ++ private static final int AES_192_KEY_LENGTH = 192; ++ private static final int AES_256_KEY_LENGTH = 256; ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String algo : ALGORITHM) { ++ for (String mode : MODES) { ++ int padKinds = 2; ++ if (mode.equalsIgnoreCase("CTR")) { ++ padKinds = 1; ++ } ++ for (int k = 0; k < padKinds; k++) { ++ test(algo, mode, PADDING[k]); ++ } ++ } ++ } ++ } ++ ++ public static void test(String algo, String mo, String pad) throws Exception { ++ AlgorithmParameterSpec aps = null; ++ ++ Cipher cipher = Cipher.getInstance(algo + "/" + mo + "/" + pad); ++ ++ KeyGenerator kg = KeyGenerator.getInstance("AES"); ++ if (algo.equalsIgnoreCase("AES_192")) { ++ kg.init(AES_192_KEY_LENGTH); ++ } else if (algo.equalsIgnoreCase("AES_256")) { ++ kg.init(AES_256_KEY_LENGTH); ++ } else { ++ kg.init(AES_128_KEY_LENGTH); ++ } ++ ++ SecretKey key = kg.generateKey(); ++ ++ // encrypt ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.ENCRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.ENCRYPT_MODE, key); ++ } ++ ++ String cipherString = null; ++ if (!pad.equalsIgnoreCase("NoPadding")) { ++ cipherString = shortPlainText; ++ } else { ++ cipherString = plainText; ++ } ++ byte[] cipherText = cipher.doFinal(cipherString.getBytes(StandardCharsets.UTF_8)); ++ if (!mo.equalsIgnoreCase("ECB")) { ++ aps = new IvParameterSpec(cipher.getIV()); ++ } else { ++ aps = null; ++ } ++ ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.DECRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.DECRYPT_MODE, key, cipher.getParameters()); ++ } ++ ++ String decryptPlainText = new String(cipher.doFinal(cipherText)); ++ ++ if (!cipherString.equals(decryptPlainText)) { ++ throw new RuntimeException("aes decryption failed, algo = " + algo + ", mo = " + mo + ", pad = " + pad); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/SM3Test.java b/test/jdk/org/openeuler/security/openssl/SM3Test.java +new file mode 100644 +index 000000000..e1c5346c9 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/SM3Test.java +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import java.nio.charset.StandardCharsets; ++import java.util.Arrays; ++import java.security.MessageDigest; ++import java.security.Security; ++ ++/** ++ * @test ++ * @summary Basic test for sm3 ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @run main SM3Test ++ */ ++ ++public class SM3Test { ++ ++ private static String plainText = "helloworldhellow"; ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ test(plainText, "SM3", new byte[]{40, -103, -71, 4, -80, -49, 94, 112, 11, -75, -66, 121, 63, 80, 62, -14, -45, -75, -34, 66, -77, -34, -26, 26, 33, -23, 45, 52, -74, 67, -18, 118}); ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ MessageDigest md = MessageDigest.getInstance(algo); ++ md.update(plainText.getBytes(StandardCharsets.UTF_8)); ++ byte[] res = md.digest(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException("sm3 failed"); ++ } ++ } ++ ++} +diff --git a/test/jdk/org/openeuler/security/openssl/SM4Test.java b/test/jdk/org/openeuler/security/openssl/SM4Test.java +new file mode 100644 +index 000000000..ac81831ba +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/SM4Test.java +@@ -0,0 +1,153 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import java.nio.ByteBuffer; ++import java.nio.charset.StandardCharsets; ++import java.util.Arrays; ++import java.security.Security; ++import javax.crypto.Cipher; ++import javax.crypto.spec.IvParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/** ++ * @test ++ * @summary Basic test for sm4 ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @run main SM4Test ++ */ ++ ++public class SM4Test { ++ ++ private static SecretKeySpec ks = new SecretKeySpec("sm4EncryptionKey".getBytes(StandardCharsets.UTF_8), "SM4"); // key has 16 bytes ++ private static IvParameterSpec iv = new IvParameterSpec("abcdefghabcdefgh".getBytes(StandardCharsets.UTF_8)); // iv has 16 bytes ++ private static IvParameterSpec shortIv = new IvParameterSpec("abcdefgh".getBytes(StandardCharsets.UTF_8)); // CTR support >= 8bytes iv ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ test(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ test(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ test(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ test(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ test(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ test(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ test(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ ++ testCtrShortIv(plainText, "SM4/CTR/NOPADDING", new byte[]{-13, 73, 40, -36, -64, -67, 75, -72, 90, 58, 73, -4, -36, 115, 126, -48}); ++ ++ testByteBuffer(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ testByteBuffer(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ testByteBuffer(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ testByteBuffer(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ testByteBuffer(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ ++ System.setProperty("kae.sm4.maxChunkSize", "65536"); ++ testByteBuffer(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ testByteBuffer(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ testByteBuffer(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ testByteBuffer(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ testByteBuffer(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ if (algo.contains("ECB")) { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ } else { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, iv); ++ } ++ byte[] cipherText = encryptCipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); ++ if (!Arrays.equals(cipherText, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ String decryptPlainText = new String(decryptCipher.doFinal(cipherText)); ++ if (!plainText.equals(decryptPlainText)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ } ++ ++ public static void testCtrShortIv(String plainText, String algo, byte[] expectRes) throws Exception { ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, shortIv); ++ byte[] cipherText = encryptCipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); ++ if (!Arrays.equals(cipherText, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ String decryptPlainText = new String(decryptCipher.doFinal(cipherText)); ++ if (!plainText.equals(decryptPlainText)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ } ++ ++ public static void testByteBuffer(String plainText, String algo, byte[] expectRes) throws Exception { ++ // encrypt ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ if (algo.contains("ECB")) { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ } else { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, iv); ++ } ++ int inputLen = plainText.length(); ++ ByteBuffer sourceByteBuffer = ByteBuffer.allocateDirect(inputLen); ++ sourceByteBuffer.put(plainText.getBytes()); ++ sourceByteBuffer.flip(); ++ int outputLen = encryptCipher.getOutputSize(inputLen); ++ ByteBuffer encryptedByteBuffer = ByteBuffer.allocate(outputLen); ++ encryptCipher.doFinal(sourceByteBuffer,encryptedByteBuffer); ++ encryptedByteBuffer.flip(); ++ byte[] encryptedBytes = new byte[encryptedByteBuffer.limit()]; ++ encryptedByteBuffer.get(encryptedBytes); ++ if (!Arrays.equals(encryptedBytes, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ sourceByteBuffer.clear(); ++ encryptedByteBuffer.flip(); ++ ++ // decrypt ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ outputLen = decryptCipher.getOutputSize(encryptedBytes.length); ++ ByteBuffer decryptedByteBuffer = ByteBuffer.allocate(outputLen); ++ decryptCipher.doFinal(encryptedByteBuffer, decryptedByteBuffer); ++ decryptedByteBuffer.flip(); ++ byte[] decryptedBytes = new byte[decryptedByteBuffer.limit()]; ++ decryptedByteBuffer.get(decryptedBytes); ++ if (!Arrays.equals(plainText.getBytes(), decryptedBytes)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ encryptedByteBuffer.clear(); ++ decryptedByteBuffer.clear(); ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +index cd74b5164..52cfbab4e 100644 +--- a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java ++++ b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +@@ -107,7 +107,12 @@ public class PreferredProviderNegativeTest { + + String expected; + String value = args[1]; +- expected = System.getProperty("test.provider.name", "SunJCE"); ++ ++ if (Security.getProperty("security.provider.1").equals("KAEProvider")) { ++ expected = "KAEProvider"; ++ } else { ++ expected = "SunJCE"; ++ } + + if (args.length >= 2) { + switch (args[0]) { +diff --git a/test/jdk/sun/security/krb5/auto/BasicProc.java b/test/jdk/sun/security/krb5/auto/BasicProc.java +index 0ba0b907b..c67efa446 100644 +--- a/test/jdk/sun/security/krb5/auto/BasicProc.java ++++ b/test/jdk/sun/security/krb5/auto/BasicProc.java +@@ -298,7 +298,9 @@ public class BasicProc { + Proc p = Proc.create("BasicProc") + .inheritProp("jdk.net.hosts.file") + .prop("java.security.manager", "") +- .perm(new javax.security.auth.AuthPermission("doAs")); ++ .perm(new javax.security.auth.AuthPermission("doAs")) ++ .perm(new java.util.PropertyPermission( ++ "kae.disableKaeDispose", "read")); + if (lib != null) { + p.env("KRB5_CONFIG", CONF) + .env("KRB5_TRACE", Platform.isWindows() ? "CON" : "/dev/stderr") +diff --git a/test/jdk/sun/security/pkcs11/Secmod/policy b/test/jdk/sun/security/pkcs11/Secmod/policy +index e4c95ca6d..60488fd06 100644 +--- a/test/jdk/sun/security/pkcs11/Secmod/policy ++++ b/test/jdk/sun/security/pkcs11/Secmod/policy +@@ -3,4 +3,5 @@ grant { + permission java.io.FilePermission "${test.src}/-", "read"; + permission java.io.FilePermission "${pkcs11test.nss.db}/-", "read"; + permission java.io.FilePermission "${pkcs11test.nss.libdir}/-", "read"; ++ permission java.util.PropertyPermission "kae.disableKaeDispose", "read"; + }; +\ No newline at end of file +diff --git a/test/jdk/sun/security/pkcs11/policy b/test/jdk/sun/security/pkcs11/policy +index d5a78b6ba..42d22643e 100644 +--- a/test/jdk/sun/security/pkcs11/policy ++++ b/test/jdk/sun/security/pkcs11/policy +@@ -1,4 +1,5 @@ + grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.util.PropertyPermission "test.provider.name", "read"; ++ permission java.util.PropertyPermission "kae.disableKaeDispose", "read"; + }; +diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +index 26304c5df..ca618ccfe 100644 +--- a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java ++++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +@@ -91,6 +91,10 @@ public class DisabledCurve extends SSLSocketTemplate { + } + + public static void main(String[] args) throws Exception { ++ // KAEProvider does not support sect283r1 ++ if (Security.getProperty("security.provider.1").equals("KAEProvider")) { ++ return; ++ } + String expected = args[1]; + String disabledName = ("DISABLE_NONE".equals(args[0]) ? "" : args[0]); + boolean disabled = false; +diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy b/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy +index b426b173f..6f65e48a3 100644 +--- a/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy ++++ b/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy +@@ -33,5 +33,7 @@ grant codeBase "file:com.jar" { + "javax.net.ssl.trustStore", "write"; + permission java.util.PropertyPermission + "javax.net.ssl.trustStorePassword", "write"; ++ permission java.util.PropertyPermission ++ "kae.disableKaeDispose", "read"; + }; + +diff --git a/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java b/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java +new file mode 100644 +index 000000000..8a6e5658d +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.InvalidKeyException; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.concurrent.TimeUnit; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.spec.SecretKeySpec; ++ ++@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) ++public class AESBenchmark extends BenchmarkBase { ++ ++ @Param({"AES/ECB/PKCS5Padding", "AES/ECB/NoPadding", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding", "AES/CTR/NoPadding"}) ++ private String algorithm; ++ ++ @Param({"128", "192", "256"}) ++ private int keyLength; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ private byte[][] encryptedData; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, ++ InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { ++ setupProvider(); ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ SecretKeySpec ks = new SecretKeySpec(keystring, "AES"); ++ ++ encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ encryptedData = fillEncrypted(data, encryptCipher); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] encryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ public byte[] decrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] decryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++} ++ +diff --git a/test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java b/test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java +new file mode 100644 +index 000000000..222405235 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java +@@ -0,0 +1,133 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.Fork; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.spec.GCMParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidKeyException; ++import java.security.NoSuchAlgorithmException; ++import java.security.spec.InvalidParameterSpecException; ++ ++import java.security.Provider; ++ ++ ++public class AESGCMBenchmark extends BenchmarkBase{ ++ ++ @Param({"AES/GCM/NoPadding","AES/GCM/PKCS5Padding"}) ++ private String algorithm; ++ ++ @Param({"128", "192", "256"}) ++ private int keyLength; ++ ++ @Param({""+1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ byte[] data; ++ byte[] encryptedData; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ SecretKeySpec ks; ++ GCMParameterSpec gcm_spec; ++ byte[] aad; ++ byte[] iv; ++ ++ public static final int IV_BUFFER_SIZE = 32; ++ public static final int IV_MODULO = IV_BUFFER_SIZE - 16; ++ int iv_index = 0; ++ ++ private int next_iv_index() { ++ int r = iv_index; ++ iv_index = (iv_index + 1) % IV_MODULO; ++ return r; ++ } ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidParameterSpecException { ++ setupProvider(); ++ assert algorithm.split("/")[1].compareToIgnoreCase("GCM") == 0; ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ ks = new SecretKeySpec(keystring, "AES"); ++ iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]); ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ aad = fillSecureRandom(new byte[5]); ++ encryptCipher = makeCipher(prov, algorithm); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.updateAAD(aad); ++ decryptCipher = makeCipher(prov, algorithm); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters().getParameterSpec(GCMParameterSpec.class)); ++ decryptCipher.updateAAD(aad); ++ data = fillRandom(new byte[dataSize]); ++ encryptedData = encryptCipher.doFinal(data); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.updateAAD(aad); ++ return encryptCipher.doFinal(data); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] encrypt_arg() throws BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.updateAAD(aad); ++ return encryptCipher.doFinal(data); ++ } ++ ++ @Benchmark ++ public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, gcm_spec); ++ decryptCipher.updateAAD(aad); ++ return decryptCipher.doFinal(encryptedData); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] decrypt_arg() throws BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, gcm_spec); ++ decryptCipher.updateAAD(aad); ++ return decryptCipher.doFinal(encryptedData); ++ } ++ ++ public static Cipher makeCipher(Provider prov, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException { ++ return (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ } ++} ++ +diff --git a/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java b/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java +new file mode 100644 +index 000000000..4e3e7f817 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java +@@ -0,0 +1,106 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Measurement; ++import org.openjdk.jmh.annotations.Mode; ++import org.openjdk.jmh.annotations.OutputTimeUnit; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Scope; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.State; ++import org.openjdk.jmh.annotations.Threads; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import java.security.Provider; ++import java.security.SecureRandom; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++@BenchmarkMode(Mode.Throughput) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 5) ++@Threads(1) ++@State(Scope.Thread) ++public class BenchmarkBase { ++ public static final int SET_SIZE = 128; ++ ++ byte[][] data; ++ int index = 0; ++ ++ @Param({"", "KAEProvider"}) ++ private String provider; ++ ++ public Provider prov = null; ++ ++ @Setup ++ public void setupProvider() { ++ Security.addProvider(new KAEProvider()); ++ if (provider != null && !provider.isEmpty()) { ++ prov = Security.getProvider(provider); ++ if (prov == null) { ++ throw new RuntimeException("Can't find provider \"" + provider + "\""); ++ } ++ } ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++ ++ public static byte[] fillRandom(byte[] data) { ++ Random rnd = new Random(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[] fillSecureRandom(byte[] data) { ++ SecureRandom rnd = new SecureRandom(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[][] fillEncrypted(byte[][] data, Cipher encryptCipher) ++ throws IllegalBlockSizeException, BadPaddingException { ++ byte[][] encryptedData = new byte[data.length][]; ++ for (int i = 0; i < encryptedData.length; i++) { ++ encryptedData[i] = encryptCipher.doFinal(data[i]); ++ } ++ return encryptedData; ++ } ++ ++} +diff --git a/test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java b/test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java +new file mode 100644 +index 000000000..eb5ece804 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java +@@ -0,0 +1,139 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++ ++package org.openeuler.bench.security.openssl; ++ ++import java.math.BigInteger; ++import java.security.*; ++import javax.crypto.*; ++import javax.crypto.spec.*; ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import java.util.concurrent.TimeUnit; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.KeyPairGenerator; ++ ++public class DHKeyAgreementBenchMark extends BenchmarkBase { ++ @Param({"DH"}) ++ private String algorithm; ++ ++ @Param({"512", "1024", "2048", "3072", "4096"}) ++ private int keySize; ++ ++ private KeyPairGenerator aliceKpairGen; ++ private KeyPairGenerator bobKpairGen; ++ private KeyPairGenerator carolKpairGen; ++ ++ private KeyPair aliceKpair; ++ private KeyPair bobKpair; ++ private KeyPair carolKpair; ++ ++ private DHParameterSpec dhSkipParamSpec; ++ ++ @Setup ++ public void setUp() throws Exception { ++ setupProvider(); ++ aliceKpairGen = createKeyPairGenerator(); ++ bobKpairGen = createKeyPairGenerator(); ++ carolKpairGen = createKeyPairGenerator(); ++ ++ // Alice creates her own DH key pair ++ aliceKpairGen.initialize(keySize); ++ aliceKpair = aliceKpairGen.generateKeyPair(); ++ // Bob creates his own DH key pair ++ bobKpairGen.initialize(keySize); ++ bobKpair = bobKpairGen.generateKeyPair(); ++ // Carol creates her own DH key pair ++ carolKpairGen.initialize(keySize); ++ carolKpair = carolKpairGen.generateKeyPair(); ++ } ++ ++ @Benchmark ++ public void KeyAgreement() throws Exception { ++ ++ // Alice initialize ++ KeyAgreement aliceKeyAgree = (prov == null ? KeyAgreement.getInstance("DH") : KeyAgreement.getInstance("DH", prov)); ++ aliceKeyAgree.init(aliceKpair.getPrivate()); ++ // Bob initialize ++ KeyAgreement bobKeyAgree = (prov == null ? KeyAgreement.getInstance("DH") : KeyAgreement.getInstance("DH", prov)); ++ bobKeyAgree.init(bobKpair.getPrivate()); ++ // Carol initialize ++ KeyAgreement carolKeyAgree = (prov == null ? KeyAgreement.getInstance("DH") : KeyAgreement.getInstance("DH", prov)); ++ carolKeyAgree.init(carolKpair.getPrivate()); ++ // Alice uses Carol's public key ++ Key ac = aliceKeyAgree.doPhase(carolKpair.getPublic(), false); ++ // Bob uses Alice's public key ++ Key ba = bobKeyAgree.doPhase(aliceKpair.getPublic(), false); ++ // Carol uses Bob's public key ++ Key cb = carolKeyAgree.doPhase(bobKpair.getPublic(), false); ++ // Alice uses Carol's result from above ++ aliceKeyAgree.doPhase(cb, true); ++ // Bob uses Alice's result from above ++ bobKeyAgree.doPhase(ac, true); ++ // Carol uses Bob's result from above ++ carolKeyAgree.doPhase(ba, true); ++ ++ // Alice, Bob and Carol compute their secrets ++ byte[] aliceSharedSecret = aliceKeyAgree.generateSecret(); ++ int aliceLen = aliceSharedSecret.length; ++ ++ byte[] bobSharedSecret = bobKeyAgree.generateSecret(); ++ int bobLen = bobSharedSecret.length; ++ ++ byte[] carolSharedSecret = carolKeyAgree.generateSecret(); ++ int carolLen = carolSharedSecret.length; ++ ++ // Compare Alice and Bob ++ if (aliceLen != bobLen) { ++ throw new Exception("Alice and Bob have different lengths"); ++ } ++ for (int i=0; i pssParameterSpecMap; ++ ++ static { ++ initPSSParameterSpecMap(); ++ } ++ ++ @Param({"SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"}) ++ private String algorithm; ++ ++ @Param({"2048", "3072", "4096"}) ++ private int keySize; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 256 * 1024, "" + 1024 * 1024, "" + 10 * 1024 * 1024}) ++ private int dataSize; ++ ++ private KeyPair keyPair; ++ ++ private byte[][] sigData; ++ ++ ++ private static void initPSSParameterSpecMap() { ++ pssParameterSpecMap = new HashMap<>(); ++ pssParameterSpecMap.put("SHA-1", new PSSParameterSpec("SHA-1", ++ "MGF1", MGF1ParameterSpec.SHA1, 20, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-224", new PSSParameterSpec("SHA-224", ++ "MGF1", MGF1ParameterSpec.SHA224, 28, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-256", new PSSParameterSpec("SHA-256", ++ "MGF1", MGF1ParameterSpec.SHA256, 32, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-384", new PSSParameterSpec("SHA-384", ++ "MGF1", MGF1ParameterSpec.SHA384, 48, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-512", new PSSParameterSpec("SHA-512", ++ "MGF1", MGF1ParameterSpec.SHA512, 64, PSSParameterSpec.TRAILER_FIELD_BC)); ++ } ++ ++ @Setup ++ public void setup() throws Exception { ++ setupProvider(); ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); ++ keyPairGenerator.initialize(keySize); ++ keyPair = keyPairGenerator.generateKeyPair(); ++ data = new byte[SET_SIZE][dataSize]; ++ sigData = getSigBytes(data); ++ } ++ ++ private byte[][] getSigBytes(byte[][] data) throws Exception { ++ byte[][] sigBytes = new byte[data.length][]; ++ Signature signature = prov != null ? Signature.getInstance("RSASSA-PSS", prov) : ++ Signature.getInstance("RSASSA-PSS"); ++ signature.setParameter(pssParameterSpecMap.get(algorithm)); ++ signature.initSign(keyPair.getPrivate()); ++ for (int i = 0; i < sigBytes.length; i++) { ++ signature.update(data[i]); ++ sigBytes[i] = signature.sign(); ++ } ++ return sigBytes; ++ } ++ ++ @Benchmark ++ public void sign() throws Exception { ++ Signature signature = prov != null ? Signature.getInstance("RSASSA-PSS", prov) : ++ Signature.getInstance("RSASSA-PSS"); ++ signature.setParameter(pssParameterSpecMap.get(algorithm)); ++ signature.initSign(keyPair.getPrivate()); ++ signature.update(data[index]); ++ signature.sign(); ++ index = (index + 1) % SET_SIZE; ++ } ++ ++ @Benchmark ++ public void verify() throws Exception { ++ Signature signature = prov != null ? Signature.getInstance("RSASSA-PSS", prov) : ++ Signature.getInstance("RSASSA-PSS"); ++ signature.setParameter(pssParameterSpecMap.get(algorithm)); ++ signature.initVerify(keyPair.getPublic()); ++ signature.update(data[index]); ++ signature.verify(sigData[index]); ++ index = (index + 1) % SET_SIZE; ++ } ++} +diff --git a/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java b/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java +new file mode 100644 +index 000000000..31112ea57 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. All rights reserved. ++ * Copyright (c) 2015, 2018, 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. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++ ++import java.security.*; ++ ++/** ++ * RSA Signature Benchmark ++ */ ++public class RSASignatureBenchmark extends BenchmarkBase { ++ @Param({"MD5withRSA", "SHA1withRSA", "SHA224withRSA", "SHA384withRSA", "SHA256withRSA", "SHA512withRSA"}) ++ private String algorithm; ++ ++ @Param({"2048", "3072", "4096"}) ++ private int keySize; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 256 * 1024, "" + 1024 * 1024, "" + 10 * 1024 * 1024}) ++ private int dataSize; ++ ++ private KeyPair keyPair; ++ ++ private byte[][] sigData; ++ ++ @Setup ++ public void setup() throws Exception { ++ setupProvider(); ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); ++ keyPairGenerator.initialize(keySize); ++ keyPair = keyPairGenerator.generateKeyPair(); ++ data = new byte[SET_SIZE][dataSize]; ++ sigData = getSigBytes(data); ++ } ++ ++ private byte[][] getSigBytes(byte[][] data) throws Exception { ++ byte[][] sigBytes = new byte[data.length][]; ++ Signature signature = prov != null ? Signature.getInstance(algorithm, prov) : ++ Signature.getInstance(algorithm); ++ signature.initSign(keyPair.getPrivate()); ++ for (int i = 0; i < sigBytes.length; i++) { ++ signature.update(data[i]); ++ sigBytes[i] = signature.sign(); ++ } ++ return sigBytes; ++ } ++ ++ @Benchmark ++ public void sign() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { ++ Signature signature = prov != null ? Signature.getInstance(algorithm, prov) : ++ Signature.getInstance(algorithm); ++ signature.initSign(keyPair.getPrivate()); ++ signature.update(data[index]); ++ signature.sign(); ++ index = (index + 1) % SET_SIZE; ++ } ++ ++ @Benchmark ++ public void verify() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { ++ Signature signature = prov != null ? Signature.getInstance(algorithm, prov) : ++ Signature.getInstance(algorithm); ++ signature.initVerify(keyPair.getPublic()); ++ signature.update(data[index]); ++ signature.verify(sigData[index]); ++ index = (index + 1) % SET_SIZE; ++ } ++} +diff --git a/test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java b/test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java +new file mode 100644 +index 000000000..eea830dbe +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Measurement; ++import org.openjdk.jmh.annotations.Mode; ++import org.openjdk.jmh.annotations.OutputTimeUnit; ++import org.openjdk.jmh.annotations.Scope; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.State; ++import org.openjdk.jmh.annotations.Threads; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++@BenchmarkMode(Mode.Throughput) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 5) ++@Threads(1) ++@State(Scope.Thread) ++public class SM3Benchmark { ++ public static final int SET_SIZE = 128; ++ byte[][] data; ++ int index = 0; ++ ++ @Param({"SM3"}) ++ private String algorithm; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ int dataSize; ++ ++ MessageDigest md; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException { ++ Security.addProvider(new KAEProvider()); ++ Provider prov = Security.getProvider("KAEProvider"); ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ md = (prov == null) ? MessageDigest.getInstance(algorithm) : MessageDigest.getInstance(algorithm, prov); ++ } ++ ++ @Benchmark ++ public byte[] digest() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return md.digest(d); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] digestDispose() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return md.digest(d); ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++} ++ +diff --git a/test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java b/test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java +new file mode 100644 +index 000000000..32de2b235 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java +@@ -0,0 +1,157 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Measurement; ++import org.openjdk.jmh.annotations.Mode; ++import org.openjdk.jmh.annotations.OutputTimeUnit; ++import org.openjdk.jmh.annotations.Scope; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.State; ++import org.openjdk.jmh.annotations.Threads; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.InvalidKeyException; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.SecureRandom; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.spec.SecretKeySpec; ++ ++@BenchmarkMode(Mode.Throughput) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 5) ++@Threads(1) ++@State(Scope.Thread) ++public class SM4Benchmark { ++ public static final int SET_SIZE = 128; ++ byte[][] data; ++ int index = 0; ++ ++ @Param({"SM4/ECB/NoPadding", "SM4/ECB/PKCS5Padding", "SM4/CBC/NoPadding", "SM4/CBC/PKCS5Padding", "SM4/CTR/NoPadding", "SM4/OFB/NoPadding", "SM4/OFB/PKCS5Padding"}) ++ private String algorithm; ++ ++ @Param({"128"}) ++ private int keyLength; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ private byte[][] encryptedData; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, ++ InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { ++ Security.addProvider(new KAEProvider()); ++ Provider prov = Security.getProvider("KAEProvider"); ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ SecretKeySpec ks = new SecretKeySpec(keystring, "SM4"); ++ ++ encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ encryptedData = fillEncrypted(data, encryptCipher); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] encryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ public byte[] decrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] decryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++ ++ public static byte[] fillRandom(byte[] data) { ++ Random rnd = new Random(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[] fillSecureRandom(byte[] data) { ++ SecureRandom rnd = new SecureRandom(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[][] fillEncrypted(byte[][] data, Cipher encryptCipher) ++ throws IllegalBlockSizeException, BadPaddingException { ++ byte[][] encryptedData = new byte[data.length][]; ++ for (int i = 0; i < encryptedData.length; i++) { ++ encryptedData[i] = encryptCipher.doFinal(data[i]); ++ } ++ return encryptedData; ++ } ++} ++ +-- +2.47.0.windows.2 + diff --git a/huawei-Add-KAE-zip-feature.patch b/huawei-Add-KAE-zip-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..49d556c68da1dd766e7b0bb3ef81935ad4b65582 --- /dev/null +++ b/huawei-Add-KAE-zip-feature.patch @@ -0,0 +1,569 @@ +Date: Thu, 13 Mar 2025 11:52:43 +0800 +Subject: Add KAE zip feature + +--- + make/autoconf/libraries.m4 | 4 ++ + make/autoconf/spec.gmk.in | 1 + + make/modules/java.base/lib/CoreLibraries.gmk | 39 ++++++++++-- + src/hotspot/share/runtime/arguments.cpp | 9 +++ + .../share/classes/java/util/zip/Deflater.java | 27 ++++++++ + .../java/util/zip/GZIPInputStream.java | 62 ++++++++++++++++++- + .../java/util/zip/GZIPOutputStream.java | 35 ++++++++++- + .../share/classes/java/util/zip/Inflater.java | 23 +++++++ + .../java/util/zip/InflaterInputStream.java | 21 +++++++ + src/java.base/share/conf/security/java.policy | 4 ++ + src/java.base/share/native/libzip/Deflater.c | 38 ++++++++++++ + src/java.base/share/native/libzip/Inflater.c | 37 ++++++++++- + .../zip/GZIP/GZIPOutputStreamHeaderTest.java | 4 ++ + 13 files changed, 296 insertions(+), 8 deletions(-) + +diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 +index 51d4f724c..b4f62ca19 100644 +--- a/make/autoconf/libraries.m4 ++++ b/make/autoconf/libraries.m4 +@@ -210,4 +210,8 @@ AC_DEFUN_ONCE([LIB_SETUP_MISC_LIBS], + # Control if libzip can use mmap. Available for purposes of overriding. + LIBZIP_CAN_USE_MMAP=true + AC_SUBST(LIBZIP_CAN_USE_MMAP) ++ ++ # Control if libz can use mmap. Available for purposes of overriding. ++ LIBZ_CAN_USE_MMAP=true ++ AC_SUBST(LIBZ_CAN_USE_MMAP) + ]) +diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in +index 8336b287a..53642529a 100644 +--- a/make/autoconf/spec.gmk.in ++++ b/make/autoconf/spec.gmk.in +@@ -811,6 +811,7 @@ USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ + LIBZ_CFLAGS:=@LIBZ_CFLAGS@ + LIBZ_LIBS:=@LIBZ_LIBS@ + LIBZIP_CAN_USE_MMAP:=@LIBZIP_CAN_USE_MMAP@ ++LIBZ_CAN_USE_MMAP:=@LIBZ_CAN_USE_MMAP@ + MSVCR_DLL:=@MSVCR_DLL@ + VCRUNTIME_1_DLL:=@VCRUNTIME_1_DLL@ + MSVCP_DLL:=@MSVCP_DLL@ +diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk +index 6aa9fd658..67d1192e1 100644 +--- a/make/modules/java.base/lib/CoreLibraries.gmk ++++ b/make/modules/java.base/lib/CoreLibraries.gmk +@@ -84,9 +84,39 @@ $(BUILD_LIBJAVA): $(BUILD_LIBVERIFY) + + ########################################################################################## + +-BUILD_LIBZIP_EXCLUDES := +-ifeq ($(USE_EXTERNAL_LIBZ), true) +- LIBZIP_EXCLUDES += zlib ++ifeq ($(USE_EXTERNAL_LIBZ), false) ++ ifeq ($(OPENJDK_TARGET_OS), linux) ++ ifeq ($(LIBZ_CAN_USE_MMAP), true) ++ BUILD_LIBZ_MMAP := -DUSE_MMAP ++ endif ++ ++ $(eval $(call SetupJdkLibrary, BUILD_LIBZ, \ ++ NAME := z, \ ++ SRC := $(TOPDIR)/src/java.base/share/native/libzip/zlib, \ ++ OPTIMIZATION := LOW, \ ++ CFLAGS := $(filter-out -fvisibility=hidden,$(CFLAGS_JDKLIB) $(LIBZ_CFLAGS)), \ ++ CFLAGS_unix := $(BUILD_LIBZ_MMAP) -UDEBUG, \ ++ DISABLED_WARNINGS_gcc := unused-function implicit-fallthrough, \ ++ DISABLED_WARNINGS_gcc_gzlib.c := implicit-function-declaration, \ ++ DISABLED_WARNINGS_gcc_gzwrite.c := implicit-function-declaration, \ ++ DISABLED_WARNINGS_gcc_gzread.c := implicit-function-declaration, \ ++ DISABLED_WARNINGS_clang := format-nonliteral, \ ++ LDFLAGS := $(LDFLAGS_JDKLIB) \ ++ $(call SET_SHARED_LIBRARY_ORIGIN), \ ++ LIBS_unix := , \ ++ LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \ ++ )) ++ ++ $(BUILD_LIBZ): $(BUILD_LIBJAVA) ++ ++ TARGETS += $(BUILD_LIBZ) ++ endif ++endif ++ ++########################################################################################## ++ ++ifeq ($(OPENJDK_TARGET_OS), linux) ++ LIBZIP_EXCLUDES := zlib + endif + + ifeq ($(LIBZIP_CAN_USE_MMAP), true) +@@ -105,10 +135,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBZIP, \ + DISABLED_WARNINGS_clang_gzwrite.c := format-nonliteral, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN), \ +- LIBS_unix := -ljvm -ljava $(LIBZ_LIBS), \ ++ LIBS_unix := -ljvm -ljava -lz, \ + LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \ + )) + ++$(BUILD_LIBZIP): $(BUILD_LIBZ) + $(BUILD_LIBZIP): $(BUILD_LIBJAVA) + + TARGETS += $(BUILD_LIBZIP) +diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp +index 9b8e5aa87..2e2a9a0f2 100644 +--- a/src/hotspot/share/runtime/arguments.cpp ++++ b/src/hotspot/share/runtime/arguments.cpp +@@ -2551,6 +2551,15 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m + // -D + } else if (match_option(option, "-D", &tail)) { + const char* value; ++#ifndef AARCH64 ++ if (match_option(option, "-DGZIP_USE_KAE=", &value)) { ++ if (strcmp(value, "true") == 0) { ++ jio_fprintf(defaultStream::output_stream(), ++ "-DGZIP_USE_KAE is not supported. This system propertiy is valid only on aarch64 architecture machines.\n" ++ "The compression action is performed using the native compression capability of the JDK.\n"); ++ } ++ } ++#endif + if (match_option(option, "-Djava.endorsed.dirs=", &value) && + *value!= '\0' && strcmp(value, "\"\"") != 0) { + // abort if -Djava.endorsed.dirs is set +diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java +index 5b57112bf..84688ad1a 100644 +--- a/src/java.base/share/classes/java/util/zip/Deflater.java ++++ b/src/java.base/share/classes/java/util/zip/Deflater.java +@@ -203,6 +203,20 @@ public class Deflater { + init(level, DEFAULT_STRATEGY, nowrap)); + } + ++ /** ++ * Creates a new compressor using the specified compression level ++ * and windowBits. ++ * This method is mainly used to support the KAE-zip feature. ++ * @param level the compression level (0-9) ++ * @param windowBits compression format (-15~31) ++ */ ++ public Deflater(int level, int windowBits) { ++ this.level = level; ++ this.strategy = DEFAULT_STRATEGY; ++ this.zsRef = new DeflaterZStreamRef(this, ++ initKAE(level, DEFAULT_STRATEGY, windowBits)); ++ } ++ + /** + * Creates a new compressor using the specified compression level. + * Compressed data will be generated in ZLIB format. +@@ -882,6 +896,18 @@ public class Deflater { + } + } + ++ /** ++ * Resets deflater so that a new set of input data can be processed. ++ * Java fields are not initialized. ++ * This method is mainly used to support the KAE-zip feature. ++ */ ++ public void resetKAE() { ++ synchronized (zsRef) { ++ ensureOpen(); ++ reset(zsRef.address()); ++ } ++ } ++ + /** + * Closes the compressor and discards any unprocessed input. + * +@@ -913,6 +939,7 @@ public class Deflater { + } + + private static native long init(int level, int strategy, boolean nowrap); ++ private static native long initKAE(int level, int strategy, int windowBits); + private static native void setDictionary(long addr, byte[] b, int off, + int len); + private static native void setDictionaryBuffer(long addr, long bufAddress, int len); +diff --git a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java +index d704fd3c9..850691e02 100644 +--- a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java ++++ b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java +@@ -54,6 +54,23 @@ public class GZIPInputStream extends InflaterInputStream { + + private boolean closed = false; + ++ /** ++ * The field is mainly used to support the KAE-zip feature. ++ */ ++ private static boolean GZIP_USE_KAE = false; ++ ++ private static int WINDOWBITS = 31; ++ ++ private static int FLUSHKAE = 2; ++ ++ static { ++ if ("aarch64".equals(System.getProperty("os.arch"))) { ++ GZIP_USE_KAE = Boolean.parseBoolean(System.getProperty("GZIP_USE_KAE", "false")); ++ WINDOWBITS = Integer.parseInt(System.getProperty("WINDOWBITS", "31")); ++ FLUSHKAE = Integer.parseInt(System.getProperty("FLUSHKAE", "2")); ++ } ++ } ++ + /** + * Check to make sure that this stream has not been closed + */ +@@ -74,8 +91,13 @@ public class GZIPInputStream extends InflaterInputStream { + * @throws IllegalArgumentException if {@code size <= 0} + */ + public GZIPInputStream(InputStream in, int size) throws IOException { +- super(in, in != null ? new Inflater(true) : null, size); ++ super(in, in != null ? (GZIP_USE_KAE ? new Inflater(WINDOWBITS, FLUSHKAE) : new Inflater(true)) : null, size); + usesDefaultInflater = true; ++ ++ // When GZIP_USE_KAE is true, the header of the file is readed ++ // through the native zlib library, not in java code. ++ if (GZIP_USE_KAE) return; ++ + readHeader(in); + } + +@@ -127,13 +149,16 @@ public class GZIPInputStream extends InflaterInputStream { + } + int n = super.read(buf, off, len); + if (n == -1) { +- if (readTrailer()) ++ if (GZIP_USE_KAE ? readTrailerKAE() : readTrailer()) + eos = true; + else + return this.read(buf, off, len); + } else { + crc.update(buf, off, n); + } ++ if (GZIP_USE_KAE && inf.finished()) { ++ if (readTrailerKAE()) eos = true; ++ } + return n; + } + +@@ -254,6 +279,39 @@ public class GZIPInputStream extends InflaterInputStream { + return true; + } + ++ /* ++ * Reads GZIP member trailer and returns true if the eos ++ * reached, false if there are more (concatenated gzip ++ * data set) ++ * ++ * This method is mainly used to support the KAE-zip feature. ++ */ ++ private boolean readTrailerKAE() throws IOException { ++ InputStream in = this.in; ++ int n = inf.getRemaining(); ++ if (n > 0) { ++ in = new SequenceInputStream( ++ new ByteArrayInputStream(buf, len - n, n), ++ new FilterInputStream(in) { ++ public void close() throws IOException {} ++ }); ++ } ++ // If there are more bytes available in "in" or the leftover in the "inf" is > 18 bytes: ++ // next.header.min(10) + next.trailer(8), try concatenated case ++ ++ if (n > 18) { ++ inf.reset(); ++ inf.setInput(buf, len - n, n); ++ } else { ++ try { ++ fillKAE(n); ++ } catch (IOException e) { ++ return true; ++ } ++ } ++ return false; ++ } ++ + /* + * Reads unsigned integer in Intel byte order. + */ +diff --git a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java +index cdfac329c..f9570265e 100644 +--- a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java ++++ b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java +@@ -55,6 +55,20 @@ public class GZIPOutputStream extends DeflaterOutputStream { + // Represents the default "unknown" value for OS header, per RFC-1952 + private static final byte OS_UNKNOWN = (byte) 255; + ++ /** ++ * The field is mainly used to support the KAE-zip feature. ++ */ ++ private static boolean GZIP_USE_KAE = false; ++ ++ private static int WINDOWBITS = 31; ++ ++ static { ++ if ("aarch64".equals(System.getProperty("os.arch"))) { ++ GZIP_USE_KAE = Boolean.parseBoolean(System.getProperty("GZIP_USE_KAE", "false")); ++ WINDOWBITS = Integer.parseInt(System.getProperty("WINDOWBITS", "31")); ++ } ++ } ++ + /** + * Creates a new output stream with the specified buffer size. + * +@@ -90,10 +104,16 @@ public class GZIPOutputStream extends DeflaterOutputStream { + public GZIPOutputStream(OutputStream out, int size, boolean syncFlush) + throws IOException + { +- super(out, out != null ? new Deflater(Deflater.DEFAULT_COMPRESSION, true) : null, ++ super(out, out != null ? ++ (GZIP_USE_KAE ? new Deflater(Deflater.DEFAULT_COMPRESSION, WINDOWBITS) : ++ new Deflater(Deflater.DEFAULT_COMPRESSION, true)) : null, + size, + syncFlush); + usesDefaultDeflater = true; ++ ++ // When GZIP_USE_KAE is true, the header of the file is written ++ // through the native zlib library, not in java code. ++ if (GZIP_USE_KAE) return; + writeHeader(); + crc.reset(); + } +@@ -163,6 +183,13 @@ public class GZIPOutputStream extends DeflaterOutputStream { + int len = def.deflate(buf, 0, buf.length); + if (def.finished() && len <= buf.length - TRAILER_SIZE) { + // last deflater buffer. Fit trailer at the end ++ // When GZIP_USE_KAE is true, the trailer of the file is written ++ // through the native zlib library, not in java code. ++ if (GZIP_USE_KAE) { ++ out.write(buf, 0, len); ++ def.resetKAE(); ++ return; ++ } + writeTrailer(buf, len); + len = len + TRAILER_SIZE; + out.write(buf, 0, len); +@@ -173,6 +200,12 @@ public class GZIPOutputStream extends DeflaterOutputStream { + } + // if we can't fit the trailer at the end of the last + // deflater buffer, we write it separately ++ // When GZIP_USE_KAE is true, the trailer of the file is written ++ // through the native zlib library, not in java code. ++ if (GZIP_USE_KAE) { ++ def.resetKAE(); ++ return; ++ } + byte[] trailer = new byte[TRAILER_SIZE]; + writeTrailer(trailer, 0); + out.write(trailer); +diff --git a/src/java.base/share/classes/java/util/zip/Inflater.java b/src/java.base/share/classes/java/util/zip/Inflater.java +index 1b9152531..ae4740482 100644 +--- a/src/java.base/share/classes/java/util/zip/Inflater.java ++++ b/src/java.base/share/classes/java/util/zip/Inflater.java +@@ -134,6 +134,17 @@ public class Inflater { + this.zsRef = new InflaterZStreamRef(this, init(nowrap)); + } + ++ /** ++ * Creates a new decompressor. ++ * This method is mainly used to support the KAE-zip feature. ++ * ++ * @param windowBits compression format (-15~31) ++ * @param flushKAE inflate flush type (0~6) ++ */ ++ public Inflater(int windowBits, int flushKAE) { ++ this.zsRef = new InflaterZStreamRef(this, initKAE(windowBits, flushKAE)); ++ } ++ + /** + * Creates a new decompressor. + */ +@@ -702,6 +713,17 @@ public class Inflater { + } + } + ++ /** ++ * Resets inflater so that a new set of input data can be processed. ++ * This method is mainly used to support the KAE-zip feature. ++ */ ++ public void resetKAE() { ++ synchronized (zsRef) { ++ ensureOpen(); ++ reset(zsRef.address()); ++ } ++ } ++ + /** + * Closes the decompressor and discards any unprocessed input. + * +@@ -730,6 +752,7 @@ public class Inflater { + + private static native void initIDs(); + private static native long init(boolean nowrap); ++ private static native long initKAE(int windowBits, int flushKAE); + private static native void setDictionary(long addr, byte[] b, int off, + int len); + private static native void setDictionaryBuffer(long addr, long bufAddress, int len); +diff --git a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java +index d60b04470..2a6ffabe8 100644 +--- a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java ++++ b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java +@@ -268,6 +268,27 @@ public class InflaterInputStream extends FilterInputStream { + inf.setInput(buf, 0, len); + } + ++ /** ++ * Fills input buffer with more data to decompress. ++ * This method is mainly used to support the KAE-zip feature. ++ * @param n Maximum Read Bytes ++ * @throws IOException if an I/O error has occurred ++ */ ++ protected void fillKAE(int n) throws IOException { ++ ensureOpen(); ++ byte[] buftmp = new byte[buf.length]; ++ if (n != 0) { ++ System.arraycopy(buf, buf.length - n, buftmp, 0, n); ++ } ++ int kaelen = in.read(buftmp, n, buf.length - n); ++ if (kaelen == -1) { ++ throw new EOFException("Unexpected end of ZLIB input stream"); ++ } ++ System.arraycopy(buftmp, 0, buf, buf.length - n - kaelen, n + kaelen); ++ inf.reset(); ++ inf.setInput(buf, buf.length - n - kaelen, n + kaelen); ++ } ++ + /** + * Tests if this input stream supports the {@code mark} and + * {@code reset} methods. The {@code markSupported} +diff --git a/src/java.base/share/conf/security/java.policy b/src/java.base/share/conf/security/java.policy +index 88e8753de..99e8de1b4 100644 +--- a/src/java.base/share/conf/security/java.policy ++++ b/src/java.base/share/conf/security/java.policy +@@ -43,4 +43,8 @@ grant { + permission java.util.PropertyPermission "java.vm.version", "read"; + permission java.util.PropertyPermission "java.vm.vendor", "read"; + permission java.util.PropertyPermission "java.vm.name", "read"; ++ ++ permission java.util.PropertyPermission "GZIP_USE_KAE", "read"; ++ permission java.util.PropertyPermission "WINDOWBITS", "read"; ++ permission java.util.PropertyPermission "FLUSHKAE", "read"; + }; +diff --git a/src/java.base/share/native/libzip/Deflater.c b/src/java.base/share/native/libzip/Deflater.c +index 1ed1994d4..c04d5c42a 100644 +--- a/src/java.base/share/native/libzip/Deflater.c ++++ b/src/java.base/share/native/libzip/Deflater.c +@@ -76,6 +76,44 @@ Java_java_util_zip_Deflater_init(JNIEnv *env, jclass cls, jint level, + } + } + ++JNIEXPORT jlong JNICALL ++Java_java_util_zip_Deflater_initKAE(JNIEnv *env, jclass cls, jint level, ++ jint strategy, jint windowBits) ++{ ++ z_stream *strm = calloc(1, sizeof(z_stream)); ++ ++ if (strm == 0) { ++ JNU_ThrowOutOfMemoryError(env, 0); ++ return jlong_zero; ++ } else { ++ const char *msg; ++ int ret = deflateInit2(strm, level, Z_DEFLATED, ++ windowBits, ++ DEF_MEM_LEVEL, strategy); ++ switch (ret) { ++ case Z_OK: ++ return ptr_to_jlong(strm); ++ case Z_MEM_ERROR: ++ free(strm); ++ JNU_ThrowOutOfMemoryError(env, 0); ++ return jlong_zero; ++ case Z_STREAM_ERROR: ++ free(strm); ++ JNU_ThrowIllegalArgumentException(env, 0); ++ return jlong_zero; ++ default: ++ msg = ((strm->msg != NULL) ? strm->msg : ++ (ret == Z_VERSION_ERROR) ? ++ "zlib returned Z_VERSION_ERROR: " ++ "compile time and runtime zlib implementations differ" : ++ "unknown error initializing zlib library"); ++ free(strm); ++ JNU_ThrowInternalError(env, msg); ++ return jlong_zero; ++ } ++ } ++} ++ + static void throwInternalErrorHelper(JNIEnv *env, z_stream *strm, const char *fixmsg) { + const char *msg = NULL; + msg = (strm->msg != NULL) ? strm->msg : fixmsg; +diff --git a/src/java.base/share/native/libzip/Inflater.c b/src/java.base/share/native/libzip/Inflater.c +index a41e9775b..4835bfac2 100644 +--- a/src/java.base/share/native/libzip/Inflater.c ++++ b/src/java.base/share/native/libzip/Inflater.c +@@ -44,6 +44,7 @@ + + static jfieldID inputConsumedID; + static jfieldID outputConsumedID; ++static jint inflaterFlushType = Z_PARTIAL_FLUSH; + + JNIEXPORT void JNICALL + Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls) +@@ -87,6 +88,40 @@ Java_java_util_zip_Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap) + } + } + ++JNIEXPORT jlong JNICALL ++Java_java_util_zip_Inflater_initKAE(JNIEnv *env, jclass cls, jint windowBits, jint flushKAE) ++{ ++ z_stream *strm = calloc(1, sizeof(z_stream)); ++ inflaterFlushType = flushKAE; ++ ++ if (strm == NULL) { ++ JNU_ThrowOutOfMemoryError(env, 0); ++ return jlong_zero; ++ } else { ++ const char *msg; ++ int ret = inflateInit2(strm, windowBits); ++ switch (ret) { ++ case Z_OK: ++ return ptr_to_jlong(strm); ++ case Z_MEM_ERROR: ++ free(strm); ++ JNU_ThrowOutOfMemoryError(env, 0); ++ return jlong_zero; ++ default: ++ msg = ((strm->msg != NULL) ? strm->msg : ++ (ret == Z_VERSION_ERROR) ? ++ "zlib returned Z_VERSION_ERROR: " ++ "compile time and runtime zlib implementations differ" : ++ (ret == Z_STREAM_ERROR) ? ++ "inflateInit2 returned Z_STREAM_ERROR" : ++ "unknown error initializing zlib library"); ++ free(strm); ++ JNU_ThrowInternalError(env, msg); ++ return jlong_zero; ++ } ++ } ++} ++ + static void checkSetDictionaryResult(JNIEnv *env, jlong addr, int res) + { + switch (res) { +@@ -137,7 +172,7 @@ static jint doInflate(jlong addr, + strm->avail_in = inputLen; + strm->avail_out = outputLen; + +- ret = inflate(strm, Z_PARTIAL_FLUSH); ++ ret = inflate(strm, inflaterFlushType); + return ret; + } + +diff --git a/test/jdk/java/util/zip/GZIP/GZIPOutputStreamHeaderTest.java b/test/jdk/java/util/zip/GZIP/GZIPOutputStreamHeaderTest.java +index 93c2e91fe..4038ad9a7 100644 +--- a/test/jdk/java/util/zip/GZIP/GZIPOutputStreamHeaderTest.java ++++ b/test/jdk/java/util/zip/GZIP/GZIPOutputStreamHeaderTest.java +@@ -35,6 +35,10 @@ import java.util.zip.GZIPOutputStream; + * @bug 8244706 + * @summary Verify that the OS header flag in the stream written out by java.util.zip.GZIPOutputStream + * has the correct expected value ++ * @comment This test case is not suitable for GZIP-zip feature testing, the ninth byte in the header ++ * of the gzip file identifies the operating system that generated the file. By default, the byte of ++ * the compressed package generated by JDK is 0xff (OS_UNKNOWN). KAE-zip relies on the underlying ++ * zlib library to write header files, this field is set to 0x03 (OS_UNIX). Therefore, this case will fail + * @run testng GZIPOutputStreamHeaderTest + */ + public class GZIPOutputStreamHeaderTest { +-- +2.47.0.windows.2 + diff --git a/huawei-Fix-arm32-build-failed-undefined-reference.patch b/huawei-Fix-arm32-build-failed-undefined-reference.patch new file mode 100644 index 0000000000000000000000000000000000000000..403d7969cb72266a37db6a9f0a5dc724f05c0c79 --- /dev/null +++ b/huawei-Fix-arm32-build-failed-undefined-reference.patch @@ -0,0 +1,23 @@ +Date: Thu, 13 Mar 2025 11:54:22 +0800 +Subject: Fix arm32 build failed undefined reference + +--- + src/hotspot/os_cpu/linux_arm/linux_arm_32.S | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S +index eb560d8f0..cfac173b1 100644 +--- a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S ++++ b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S +@@ -28,8 +28,6 @@ + # point or use it in the same manner as does the server + # compiler. + +- .globl _Copy_conjoint_bytes +- .type _Copy_conjoint_bytes, %function + .globl _Copy_arrayof_conjoint_bytes + .type _Copy_arrayof_conjoint_bytes, %function + .globl _Copy_disjoint_words +-- +2.47.0.windows.2 + diff --git a/huawei-fix-build-fail-realpath.patch b/huawei-fix-build-fail-realpath.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2ccc4e1e2466c081f3aaaacd83dc7b575966ba6 --- /dev/null +++ b/huawei-fix-build-fail-realpath.patch @@ -0,0 +1,57 @@ +--- + src/hotspot/cpu/s390/vm_version_s390.cpp | 9 --------- + src/hotspot/share/jbolt/jBoltDcmds.cpp | 9 ++++++++- + 2 files changed, 8 insertions(+), 10 deletions(-) + +diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp +index 32b6a07ff..5ee2b66d3 100644 +--- a/src/hotspot/cpu/s390/vm_version_s390.cpp ++++ b/src/hotspot/cpu/s390/vm_version_s390.cpp +@@ -301,16 +301,6 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UsePopCountInstruction, true); + } + +- if (UnlockExperimentalVMOptions && UseHashMapIntegerCache && !FLAG_IS_DEFAULT(UseHashMapIntegerCache)) { +- FLAG_SET_DEFAULT(UseHashMapIntegerCache, false); +- warning("HashMap optimization is not supported in this VM."); +- } +- +- if (UnlockExperimentalVMOptions && UseFastSerializer && !FLAG_IS_DEFAULT(UseFastSerializer)) { +- FLAG_SET_DEFAULT(UseFastSerializer, false); +- warning("Serializer optimization is not supported in this VM."); +- } +- + // z/Architecture supports 8-byte compare-exchange operations + // (see Atomic::cmpxchg) + // and 'atomic long memory ops' (see Unsafe_GetLongVolatile). +diff --git a/src/hotspot/share/jbolt/jBoltDcmds.cpp b/src/hotspot/share/jbolt/jBoltDcmds.cpp +index 0cf1c75b4..7e9ba52a8 100644 +--- a/src/hotspot/share/jbolt/jBoltDcmds.cpp ++++ b/src/hotspot/share/jbolt/jBoltDcmds.cpp +@@ -24,6 +24,9 @@ + #include "jbolt/jBoltDcmds.hpp" + #include "jbolt/jBoltControlThread.hpp" + #include "jbolt/jBoltManager.hpp" ++#ifdef __linux__ ++#include "os_posix.hpp" ++#endif + + bool register_jbolt_dcmds() { + uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; +@@ -198,8 +201,12 @@ void JBoltDumpDCmd::execute(DCmdSource source, TRAPS) { + output()->print_cr("Failed: File open error or NULL: %s", path); + break; + case JBoltOK: +- rp = realpath(path, buffer); ++#ifdef __linux__ ++ rp = os::Posix::realpath(path, buffer, sizeof(buffer)); + output()->print_cr("Successful: Dump to %s", buffer); ++#else ++ output()->print_cr("Successful: Dump to %s", path); ++#endif + break; + default: + ShouldNotReachHere(); +-- +2.31.1 + diff --git a/huawei-heap-dump-redact-support.patch b/huawei-heap-dump-redact-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..d2666fa8c5bacce0481b51647f447ad4f3318ad1 --- /dev/null +++ b/huawei-heap-dump-redact-support.patch @@ -0,0 +1,4084 @@ +Date: Fri, 14 Mar 2025 22:08:38 +0800 +Subject: heap-dump-redact-support + +--- + src/hotspot/os/linux/os_linux.cpp | 37 +- + src/hotspot/os/linux/os_linux.hpp | 54 ++ + src/hotspot/share/oops/annotations.hpp | 1 + + src/hotspot/share/runtime/arguments.cpp | 24 + + src/hotspot/share/runtime/globals.hpp | 18 + + src/hotspot/share/runtime/vmStructs.cpp | 12 +- + src/hotspot/share/services/heapDumper.cpp | 693 +++++++++++++++++- + src/hotspot/share/services/heapRedactor.cpp | 676 +++++++++++++++++ + src/hotspot/share/services/heapRedactor.hpp | 225 ++++++ + src/hotspot/share/services/writeableFlags.cpp | 7 + + .../share/classes/sun/jvm/hotspot/HSDB.java | 19 +- + .../classes/sun/jvm/hotspot/SALauncher.java | 46 +- + .../sun/jvm/hotspot/oops/Annotation.java | 70 ++ + .../classes/sun/jvm/hotspot/oops/Field.java | 10 + + .../sun/jvm/hotspot/oops/InstanceKlass.java | 6 + + .../classes/sun/jvm/hotspot/tools/JMap.java | 63 +- + .../hotspot/utilities/AnnotationArray2D.java | 62 ++ + .../hotspot/utilities/HeapHprofBinWriter.java | 419 ++++++++++- + .../jvm/hotspot/utilities/HeapRedactor.java | 454 ++++++++++++ + .../share/classes/sun/tools/jmap/JMap.java | 258 ++++++- + 20 files changed, 3088 insertions(+), 66 deletions(-) + create mode 100644 src/hotspot/share/services/heapRedactor.cpp + create mode 100644 src/hotspot/share/services/heapRedactor.hpp + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java + create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java + +diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp +index 3cb529bc8..43ee4b7db 100644 +--- a/src/hotspot/os/linux/os_linux.cpp ++++ b/src/hotspot/os/linux/os_linux.cpp +@@ -4587,6 +4587,12 @@ os::Linux::jboltLog_precalc_t os::Linux::_jboltLog_precalc; + os::Linux::jboltLog_do_t os::Linux::_jboltLog_do; + os::Linux::jboltMerge_judge_t os::Linux::_jboltMerge_judge; + #endif // INCLUDE_JBOLT ++os::Linux::heap_dict_add_t os::Linux::_heap_dict_add; ++os::Linux::heap_dict_lookup_t os::Linux::_heap_dict_lookup; ++os::Linux::heap_dict_free_t os::Linux::_heap_dict_free; ++os::Linux::heap_vector_add_t os::Linux::_heap_vector_add; ++os::Linux::heap_vector_get_next_t os::Linux::_heap_vector_get_next; ++os::Linux::heap_vector_free_t os::Linux::_heap_vector_free; + + void os::Linux::load_plugin_library() { + +@@ -4595,6 +4601,12 @@ void os::Linux::load_plugin_library() { + _jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(RTLD_DEFAULT, "JBoltLog_DO")); + _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(RTLD_DEFAULT, "JBoltMerge_Judge")); + #endif // INCLUDE_JBOLT ++ _heap_dict_add = CAST_TO_FN_PTR(heap_dict_add_t, dlsym(RTLD_DEFAULT, "HeapDict_Add")); ++ _heap_dict_lookup = CAST_TO_FN_PTR(heap_dict_lookup_t, dlsym(RTLD_DEFAULT, "HeapDict_Lookup")); ++ _heap_dict_free = CAST_TO_FN_PTR(heap_dict_free_t, dlsym(RTLD_DEFAULT, "HeapDict_Free")); ++ _heap_vector_add = CAST_TO_FN_PTR(heap_vector_add_t, dlsym(RTLD_DEFAULT, "HeapVector_Add")); ++ _heap_vector_get_next = CAST_TO_FN_PTR(heap_vector_get_next_t, dlsym(RTLD_DEFAULT, "HeapVector_GetNext")); ++ _heap_vector_free= CAST_TO_FN_PTR(heap_vector_free_t, dlsym(RTLD_DEFAULT, "HeapVector_Free")); + + char path[JVM_MAXPATHLEN]; + char ebuf[1024]; +@@ -4612,12 +4624,31 @@ void os::Linux::load_plugin_library() { + _jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(handle, "JBoltLog_DO")); + } + if (_jboltMerge_judge == NULL) { +- _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge")); ++ _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge")); + } + #endif // INCLUDE_JBOLT ++ ++ if(_heap_dict_add == NULL) { ++ _heap_dict_add = CAST_TO_FN_PTR(heap_dict_add_t, dlsym(handle, "HeapDict_Add")); ++ } ++ if(_heap_dict_lookup == NULL) { ++ _heap_dict_lookup = CAST_TO_FN_PTR(heap_dict_lookup_t, dlsym(handle, "HeapDict_Lookup")); ++ } ++ if(_heap_dict_free == NULL) { ++ _heap_dict_free = CAST_TO_FN_PTR(heap_dict_free_t, dlsym(handle, "HeapDict_Free")); ++ } ++ if(_heap_vector_add == NULL) { ++ _heap_vector_add = CAST_TO_FN_PTR(heap_vector_add_t, dlsym(handle, "HeapVector_Add")); ++ } ++ if(_heap_vector_get_next == NULL) { ++ _heap_vector_get_next = CAST_TO_FN_PTR(heap_vector_get_next_t, dlsym(handle, "HeapVector_GetNext")); ++ } ++ if(_heap_vector_free == NULL) { ++ _heap_vector_free= CAST_TO_FN_PTR(heap_vector_free_t, dlsym(handle, "HeapVector_Free")); ++ } + } + +- JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr), ++ JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr), + BOOL_TO_STR(_jboltLog_do != nullptr), + BOOL_TO_STR(_jboltMerge_judge != nullptr));) + } +@@ -4747,6 +4778,8 @@ jint os::init_2(void) { + init_adjust_stacksize_for_guard_pages(); + #endif + ++ Linux::load_plugin_library(); ++ + if (UseNUMA || UseNUMAInterleaving) { + Linux::numa_init(); + } +diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp +index 4192c90bd..871581f58 100644 +--- a/src/hotspot/os/linux/os_linux.hpp ++++ b/src/hotspot/os/linux/os_linux.hpp +@@ -223,6 +223,20 @@ class os::Linux { + static jboltLog_do_t _jboltLog_do; + static jboltMerge_judge_t _jboltMerge_judge; + #endif ++ ++ typedef void* (*heap_dict_add_t)(void* key, void* val, void* heap_dict, uint8_t type); ++ typedef void* (*heap_dict_lookup_t)(void* key, void* heap_dict, bool deletable); ++ typedef void (*heap_dict_free_t)(void* heap_dict, bool is_nested); ++ typedef void* (*heap_vector_add_t)(void* val, void* heap_vector, bool &_inserted); ++ typedef void* (*heap_vector_get_next_t)(void* heap_vector, void* heap_vector_node, int &_cnt, void** &_items); ++ typedef void (*heap_vector_free_t)(void* heap_vector); ++ static heap_dict_add_t _heap_dict_add; ++ static heap_dict_lookup_t _heap_dict_lookup; ++ static heap_dict_free_t _heap_dict_free; ++ static heap_vector_add_t _heap_vector_add; ++ static heap_vector_get_next_t _heap_vector_get_next; ++ static heap_vector_free_t _heap_vector_free; ++ + static sched_getcpu_func_t _sched_getcpu; + static numa_node_to_cpus_func_t _numa_node_to_cpus; + static numa_node_to_cpus_v2_func_t _numa_node_to_cpus_v2; +@@ -459,6 +473,46 @@ class os::Linux { + return -1; + } + #endif // INCLUDE_JBOLT ++ ++ static void* heap_dict_add(void* key, void* val, void* heap_dict, uint8_t type) { ++ if(_heap_dict_add == NULL) { ++ return NULL; ++ } ++ return _heap_dict_add(key, val, heap_dict, type); ++ } ++ ++ static void* heap_dict_lookup(void* key, void* heap_dict, bool deletable) { ++ if(_heap_dict_lookup == NULL) { ++ return NULL; ++ } ++ return _heap_dict_lookup(key, heap_dict, deletable); ++ }; ++ ++ static void heap_dict_free(void* heap_dict, bool is_nested) { ++ if(_heap_dict_free != NULL) { ++ _heap_dict_free(heap_dict, is_nested); ++ } ++ } ++ ++ static void* heap_vector_add(void* val, void* heap_vector, bool &_inserted) { ++ if(_heap_vector_add == NULL) { ++ return NULL; ++ } ++ return _heap_vector_add(val, heap_vector, _inserted); ++ } ++ ++ static void* heap_vector_get_next(void* heap_vector, void* heap_vector_node, int &_cnt, void** &_items) { ++ if(_heap_vector_get_next == NULL) { ++ return NULL; ++ } ++ return _heap_vector_get_next(heap_vector, heap_vector_node, _cnt, _items); ++ } ++ ++ static void heap_vector_free(void* heap_vector) { ++ if(_heap_vector_free != NULL) { ++ _heap_vector_free(heap_vector); ++ } ++ } + }; + + #endif // OS_LINUX_OS_LINUX_HPP +diff --git a/src/hotspot/share/oops/annotations.hpp b/src/hotspot/share/oops/annotations.hpp +index c7919ff0f..0260de2d8 100644 +--- a/src/hotspot/share/oops/annotations.hpp ++++ b/src/hotspot/share/oops/annotations.hpp +@@ -41,6 +41,7 @@ typedef Array AnnotationArray; + // a type_annotation instance. + + class Annotations: public MetaspaceObj { ++ friend class VMStructs; + friend class JVMCIVMStructs; + + // If you add a new field that points to any metaspace object, you +diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp +index 2e2a9a0f2..dd053e458 100644 +--- a/src/hotspot/share/runtime/arguments.cpp ++++ b/src/hotspot/share/runtime/arguments.cpp +@@ -58,6 +58,7 @@ + #include "runtime/vm_version.hpp" + #include "services/management.hpp" + #include "services/nmtCommon.hpp" ++#include "services/heapRedactor.hpp" + #include "utilities/align.hpp" + #include "utilities/debug.hpp" + #include "utilities/defaultStream.hpp" +@@ -3691,6 +3692,29 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, + vm_exit(0); + } + ++ if (match_option(option, "-XX:HeapDumpRedact", &tail)) { ++ // HeapDumpRedact arguments. ++ if (!HeapRedactor::check_launcher_heapdump_redact_support(tail)) { ++ warning("Heap dump redacting did not setup properly, using wrong argument?"); ++ vm_exit_during_initialization("Syntax error, expecting -XX:HeapDumpRedact=[off|names|basic|full|diyrules|annotation]",NULL); ++ } ++ continue; ++ } ++ ++ // heapDump redact password ++ if(match_option(option, "-XX:RedactPassword=", &tail)) { ++ if(tail == NULL || strlen(tail) == 0) { ++ VerifyRedactPassword = false; ++ } else { ++ char* split_char = strstr(const_cast(tail), ","); ++ VerifyRedactPassword = !(split_char == NULL || strlen(split_char) < SALT_LEN); ++ } ++ if(!VerifyRedactPassword) { ++ jio_fprintf(defaultStream::output_stream(), "redact password is null or with bad format, disable verify heap dump authority.\n"); ++ } ++ } ++ ++ + #ifndef PRODUCT + if (match_option(option, "-XX:+PrintFlagsWithComments")) { + JVMFlag::printFlags(tty, true); +diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp +index 231c2ef16..5c028a21d 100644 +--- a/src/hotspot/share/runtime/globals.hpp ++++ b/src/hotspot/share/runtime/globals.hpp +@@ -565,6 +565,24 @@ const int ObjectAlignmentInBytes = 8; + "compression. Otherwise the level must be between 1 and 9.") \ + range(0, 9) \ + \ ++ product(ccstr, HeapDumpRedact, NULL, MANAGEABLE, \ ++ "Redact the heapdump information to remove sensitive data") \ ++ \ ++ product(ccstr, RedactMap, NULL, MANAGEABLE, \ ++ "Redact the class and field names to other strings") \ ++ \ ++ product(ccstr, RedactMapFile, NULL, MANAGEABLE, \ ++ "File path of the Redact Map") \ ++ \ ++ product(ccstr, RedactClassPath, NULL, MANAGEABLE, \ ++ "full path of the Redact Annotation") \ ++ \ ++ product(bool, VerifyRedactPassword, false, \ ++ "verify authority for operating heapDump redact feature") \ ++ \ ++ product(ccstr, RedactPassword, NULL, \ ++ "authority for operating heapDump redact feature, format {password,salt}, salt length >= 8") \ ++ \ + product(ccstr, NativeMemoryTracking, DEBUG_ONLY("summary") NOT_DEBUG("off"), \ + "Native memory tracking options") \ + \ +diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp +index 827cb0cdf..15b1102cb 100644 +--- a/src/hotspot/share/runtime/vmStructs.cpp ++++ b/src/hotspot/share/runtime/vmStructs.cpp +@@ -325,7 +325,11 @@ + nonstatic_field(Symbol, _body[0], u1) \ + nonstatic_field(TypeArrayKlass, _max_length, jint) \ + nonstatic_field(OopHandle, _obj, oop*) \ +- \ ++ nonstatic_field(Annotations, _class_annotations, Array*) \ ++ nonstatic_field(Annotations, _class_type_annotations, Array*) \ ++ nonstatic_field(Annotations, _fields_annotations, Array*>*) \ ++ nonstatic_field(Annotations, _fields_type_annotations, Array*>*) \ ++ \ + /***********************/ \ + /* Constant Pool Cache */ \ + /***********************/ \ +@@ -477,6 +481,8 @@ + nonstatic_field(Array, _data[0], Klass*) \ + nonstatic_field(Array, _length, int) \ + nonstatic_field(Array, _data[0], ResolvedIndyEntry) \ ++ nonstatic_field(Array*>, _length, int) \ ++ nonstatic_field(Array*>, _data[0], Array*) \ + \ + /*******************/ \ + /* GrowableArrays */ \ +@@ -1032,6 +1038,7 @@ + unchecked_nonstatic_field(Array, _data, sizeof(Method*)) \ + unchecked_nonstatic_field(Array, _data, sizeof(Klass*)) \ + unchecked_nonstatic_field(Array, _data, sizeof(ResolvedIndyEntry)) \ ++ unchecked_nonstatic_field(Array*>, _data, sizeof(Array*)) \ + \ + /*********************************/ \ + /* java_lang_Class fields */ \ +@@ -1238,6 +1245,7 @@ + declare_type(Method, Metadata) \ + declare_type(MethodCounters, MetaspaceObj) \ + declare_type(ConstMethod, MetaspaceObj) \ ++ declare_type(Annotations, MetaspaceObj) \ + \ + declare_toplevel_type(MethodData::CompilerCounters) \ + \ +@@ -1960,6 +1969,7 @@ + declare_type(Array, MetaspaceObj) \ + declare_type(Array, MetaspaceObj) \ + declare_type(Array, MetaspaceObj) \ ++ declare_type(Array*>, MetaspaceObj) \ + declare_type(Array, MetaspaceObj) \ + \ + declare_toplevel_type(BitMap) \ +diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp +index b426f5d4c..82e721c17 100644 +--- a/src/hotspot/share/services/heapDumper.cpp ++++ b/src/hotspot/share/services/heapDumper.cpp +@@ -54,11 +54,13 @@ + #include "runtime/vframe.hpp" + #include "runtime/vmOperations.hpp" + #include "runtime/vmThread.hpp" ++#include "runtime/fieldDescriptor.inline.hpp" + #include "services/heapDumper.hpp" + #include "services/heapDumperCompression.hpp" + #include "services/threadService.hpp" + #include "utilities/macros.hpp" + #include "utilities/ostream.hpp" ++#include "services/heapRedactor.hpp" + + /* + * HPROF binary format - description copied from: +@@ -413,6 +415,8 @@ class AbstractDumpWriter : public StackObj { + + void write_address(address a); + ++ HeapRedactor* redactor; ++ + public: + AbstractDumpWriter() : + _buffer(nullptr), +@@ -427,6 +431,7 @@ class AbstractDumpWriter : public StackObj { + size_t position() const { return _pos; } + // writer functions + virtual void write_raw(const void* s, size_t len); ++ void write_zero_raw(void* s, size_t len); + void write_u1(u1 x); + void write_u2(u2 x); + void write_u4(u4 x); +@@ -452,6 +457,12 @@ class AbstractDumpWriter : public StackObj { + // Force flush to guarantee data from parallel dumper are written. + flush(true); + } ++ ++ // remove sensitive data from heapdump information ++ void setHeapRedactor(HeapRedactor* value); ++ HeapRedactor* heapRedactor(); ++ HeapDumpRedactLevel getHeapDumpRedactLevel(); ++ + // Called when finished to release the threads. + virtual void deactivate() = 0; + }; +@@ -489,6 +500,27 @@ void AbstractDumpWriter::write_raw(const void* s, size_t len) { + set_position(position() + len); + } + ++void AbstractDumpWriter::write_zero_raw(void* s, size_t len) { ++ assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large"); ++ debug_only(_sub_record_left -= len); ++ ++ // flush buffer to make room. ++ while (len > buffer_size() - position()) { ++ assert(!_in_dump_segment || _is_huge_sub_record, ++ "Cannot overflow in non-huge sub-record."); ++ ++ size_t to_write = buffer_size() - position(); ++ memset(buffer() + position(), 0, to_write); ++ s = (void*) ((char*) s + to_write); ++ len -= to_write; ++ set_position(position() + to_write); ++ flush(); ++ } ++ ++ memset(buffer() + position(), 0, len); ++ set_position(position() + len); ++} ++ + // Makes sure we inline the fast write into the write_u* functions. This is a big speedup. + #define WRITE_KNOWN_TYPE(p, len) do { if (can_write_fast((len))) write_fast((p), (len)); \ + else write_raw((p), (len)); } while (0) +@@ -608,6 +640,21 @@ void AbstractDumpWriter::end_sub_record() { + debug_only(_sub_record_ended = true); + } + ++void AbstractDumpWriter::setHeapRedactor(HeapRedactor* value) { ++ redactor = value; ++} ++ ++HeapRedactor* AbstractDumpWriter::heapRedactor() { ++ return redactor; ++} ++ ++HeapDumpRedactLevel AbstractDumpWriter::getHeapDumpRedactLevel() { ++ if(redactor==NULL){ ++ return REDACT_OFF; ++ } ++ return redactor->redact_level(); ++} ++ + // Supports I/O operations for a dump + + class DumpWriter : public AbstractDumpWriter { +@@ -886,6 +933,9 @@ Monitor* ParDumpWriter::_lock = nullptr; + class DumperClassCacheTable; + class DumperClassCacheTableEntry; + ++typedef char* (*CALL_DO_LOOKUP_REPLACE_VALUE)(AbstractDumpWriter*, typeArrayOop); ++typedef void (*CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS)(AbstractDumpWriter*, Klass*); ++typedef void (*CALL_DUMP_PRIM_ARRAY)(AbstractDumpWriter*, typeArrayOop); + // Support class with a collection of functions used when dumping the heap + class DumperSupport : AllStatic { + public: +@@ -915,14 +965,26 @@ class DumperSupport : AllStatic { + static void dump_static_fields(AbstractDumpWriter* writer, Klass* k); + // dump the raw values of the instance fields of the given object + static void dump_instance_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry); ++ // dump the redact values of the instance fields of the given object ++ static void dump_instance_redact_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry, void* replace_value_table, uint container_id); + // get the count of the instance fields for a given class + static u2 get_instance_fields_count(InstanceKlass* ik); + // dumps the definition of the instance fields for a given class + static void dump_instance_field_descriptors(AbstractDumpWriter* writer, Klass* k); ++ // dumps the definition of the instance fields for a given class ++ static void dump_instance_annotation_field_descriptors(AbstractDumpWriter* writer, Klass* k); ++ // dumps the definition of the instance fields for a given class ++ static void dump_instance_diyrules_field_descriptors(AbstractDumpWriter* writer, Klass* k); + // creates HPROF_GC_INSTANCE_DUMP record for the given object + static void dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache); ++ // creates HPROF_GC_INSTANCE_REDACT_DUMP record for the given object ++ static void dump_redact_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache, uint container_id); ++ // lookup different value type depend on redact mode ++ static char* do_lookup_replace_value_with_symbol(AbstractDumpWriter* writer, typeArrayOop array); ++ static char* do_lookup_replace_value_with_char(AbstractDumpWriter* writer, typeArrayOop array); ++ static bool dump_replace_value(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id); + // creates HPROF_GC_CLASS_DUMP record for the given instance class +- static void dump_instance_class(AbstractDumpWriter* writer, Klass* k); ++ static void dump_instance_class(CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS fn, AbstractDumpWriter* writer, Klass* k); + // creates HPROF_GC_CLASS_DUMP record for a given array class + static void dump_array_class(AbstractDumpWriter* writer, Klass* k); + +@@ -930,15 +992,22 @@ class DumperSupport : AllStatic { + static void dump_object_array(AbstractDumpWriter* writer, objArrayOop array); + // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array + static void dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array); ++ // creates HPROF_GC_PRIM_ARRAY_REDACT_DUMP record for the given type array ++ static void redact_basic_dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array); ++ static void redact_replace_dump_prim_array(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id); ++ static void redact_dump_prim_array(CALL_DUMP_PRIM_ARRAY fn, AbstractDumpWriter* dumpWriter, typeArrayOop o); + // create HPROF_FRAME record for the given method and bci + static void dump_stack_frame(AbstractDumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci); + + // check if we need to truncate an array +- static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size); ++ static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size, int char_length = 0); + + // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record + static void end_of_dump(AbstractDumpWriter* writer); + ++ // is_large function, if oop is large object, retrun true ++ static bool is_large(oop o); ++ + static oop mask_dormant_archived_object(oop o, oop ref_obj) { + if (o != nullptr && o->klass()->java_mirror_no_keepalive() == nullptr) { + // Ignore this object since the corresponding java mirror is not loaded. +@@ -974,6 +1043,7 @@ class DumperClassCacheTableEntry : public CHeapObj { + private: + GrowableArray _sigs_start; + GrowableArray _offsets; ++ GrowableArray

    _name_symbol_addrs; + u4 _instance_size; + int _entries; + +@@ -983,6 +1053,7 @@ public: + int field_count() { return _entries; } + char sig_start(int field_idx) { return _sigs_start.at(field_idx); } + int offset(int field_idx) { return _offsets.at(field_idx); } ++ address name_symbol_addrs(int field_idx) { return _name_symbol_addrs.at(field_idx); } + u4 instance_size() { return _instance_size; } + }; + +@@ -1033,6 +1104,7 @@ public: + Symbol* sig = fld.signature(); + entry->_sigs_start.push(sig->char_at(0)); + entry->_offsets.push(fld.offset()); ++ entry->_name_symbol_addrs.push((address)((uintptr_t)fld.name())); + entry->_entries++; + entry->_instance_size += DumperSupport::sig2size(sig); + } +@@ -1309,6 +1381,37 @@ void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o, Dump + } + } + ++// dump the diyrules values of the instance fields of the given object ++void DumperSupport::dump_instance_redact_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry, void* replace_value_table, uint container_id) { ++ InstanceKlass* ik = InstanceKlass::cast(o->klass()); ++ ++ for (int idx = 0; idx < class_cache_entry->field_count(); idx++) { ++ ++ char type = class_cache_entry->sig_start(idx); ++ int offset = class_cache_entry->offset(idx); ++ ++ ResourceMark rm; ++ address field_adr = class_cache_entry->name_symbol_addrs(idx); ++ void* replace_value = writer->heapRedactor()->lookup_value(field_adr, replace_value_table, false); ++ ++ if (replace_value != nullptr) { ++ oop field_oop = o->obj_field_access(offset); ++ if (!java_lang_String::is_instance(field_oop)) { ++ // data not completed, skip this field value; ++ writer->write_objectID(nullptr); ++ continue; ++ } ++ ++ typeArrayOop field_value_oop = java_lang_String::value(field_oop); ++ address type_array_addr = cast_from_oop
    (field_value_oop); ++ writer->heapRedactor()->insert_anonymous_value(type_array_addr, replace_value, container_id); ++ writer->write_objectID(field_oop); ++ continue; ++ } ++ dump_field_value(writer, type, o, offset); ++ } ++} ++ + // dumps the definition of the instance fields for a given class + u2 DumperSupport::get_instance_fields_count(InstanceKlass* ik) { + u2 field_count = 0; +@@ -1335,6 +1438,97 @@ void DumperSupport::dump_instance_field_descriptors(AbstractDumpWriter* writer, + } + } + ++// dumps the definition of the instance fields for a given class ++void DumperSupport::dump_instance_annotation_field_descriptors(AbstractDumpWriter* writer, Klass* k) { ++ ResourceMark rm; ++ InstanceKlass* ik = InstanceKlass::cast(k); ++ Symbol *class_name_symbol = ik->name(); ++ bool in_exclude_package = false; ++ if (Symbol::is_valid(class_name_symbol)) { ++ char *class_name = class_name_symbol->as_C_string(); ++ in_exclude_package = (strncmp("java/", class_name, 5) == 0) || (strncmp("org/springframework", class_name, 19) == 0); ++ } ++ ++ if(in_exclude_package) { ++ DumperSupport::dump_instance_field_descriptors(writer, k); ++ return; ++ } ++ ++ address obj_adr = (address)((uintptr_t)class_name_symbol); ++ // dump the field descriptors ++ for (JavaFieldStream fld(ik); !fld.done(); fld.next()) { ++ if (!fld.access_flags().is_static()) { ++ Symbol* sig = fld.signature(); ++ Symbol* field_name = fld.name(); ++ ++ writer->write_symbolID(field_name); // name ++ writer->write_u1(sig2tag(sig)); // type ++ ++ if(strcmp(sig->as_C_string(), "Ljava/lang/String;") != 0) { ++ continue; ++ } ++ ++ AnnotationArray *field_annotations = fld.field_descriptor().annotations(); ++ if (field_annotations == nullptr || field_annotations->length() == 0) { ++ continue; ++ } ++ ++ // byte index into field_annotations ++ ConstantPool *cp = fld.field_descriptor().field_holder()->constants(); ++ int byte_i = 0; ++ if (writer->heapRedactor()->lookup_annotation_index_in_constant_pool(field_annotations, cp, byte_i)) { ++ address element_value_addr = (address) field_annotations->adr_at(byte_i); ++ u2 cp_str_index = Bytes::get_Java_u2(element_value_addr); ++ Symbol *element_value_symbol = cp->symbol_at(cp_str_index); ++ ++ address field_adr = (address) ((uintptr_t) field_name); ++ writer->heapRedactor()->insert_class_field_value(obj_adr, field_adr, element_value_symbol); ++ } ++ } ++ } ++} ++ ++// dumps the definition of the instance fields for a given class ++void DumperSupport::dump_instance_diyrules_field_descriptors(AbstractDumpWriter *writer, Klass *k) { ++ ResourceMark rm; ++ InstanceKlass* ik = InstanceKlass::cast(k); ++ Symbol *class_name_symbol = ik->name(); ++ void* redact_class_table = nullptr; ++ bool has_diyrules = false; ++ if (Symbol::is_valid(class_name_symbol)) { ++ char *class_name = class_name_symbol->as_C_string(); ++ redact_class_table = writer->heapRedactor()->lookup_class_rules(class_name); ++ has_diyrules = (redact_class_table != nullptr); ++ } ++ ++ if (!has_diyrules) { ++ DumperSupport::dump_instance_field_descriptors(writer, k); ++ return; ++ } ++ ++ address obj_adr = (address) ((uintptr_t) class_name_symbol); ++ // dump the field descriptors ++ for (JavaFieldStream fld(ik); !fld.done(); fld.next()) { ++ if (!fld.access_flags().is_static()) { ++ Symbol* sig = fld.signature(); ++ Symbol* field_name = fld.name(); ++ ++ writer->write_symbolID(field_name); // name ++ writer->write_u1(sig2tag(sig)); // type ++ ++ if(strcmp(sig->as_C_string(), "Ljava/lang/String;") != 0) { ++ continue; ++ } ++ char *field_name_str = field_name->as_C_string(); ++ char *replace_value = (char *) writer->heapRedactor()->lookup_value(field_name_str, redact_class_table, false); ++ if (replace_value != nullptr) { ++ address field_adr = (address) ((uintptr_t) field_name); ++ writer->heapRedactor()->insert_class_field_value(obj_adr, field_adr, replace_value); ++ } ++ } ++ } ++} ++ + // creates HPROF_GC_INSTANCE_DUMP record for the given object + void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache) { + InstanceKlass* ik = InstanceKlass::cast(o->klass()); +@@ -1360,8 +1554,104 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClass + writer->end_sub_record(); + } + ++// creates HPROF_GC_INSTANCE_REDACT_DUMP record for the given object ++void DumperSupport::dump_redact_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache, uint container_id) { ++ InstanceKlass* ik = InstanceKlass::cast(o->klass()); ++ ++ DumperClassCacheTableEntry* cache_entry = class_cache->lookup_or_create(ik); ++ ++ u4 is = instance_size(ik); ++ u4 size = 1 + sizeof(address) + 4 + sizeof(address) + 4 + is; ++ ++ writer->start_sub_record(HPROF_GC_INSTANCE_DUMP, size); ++ writer->write_objectID(o); ++ writer->write_u4(STACK_TRACE_ID); ++ ++ // class ID ++ writer->write_classID(ik); ++ ++ // number of bytes that follow ++ writer->write_u4(is); ++ ++ // field values ++ void* replace_value_table = nullptr; ++ InstanceKlass* java_super = ik; ++ do { ++ Symbol * class_name_symbol = java_super->name(); ++ address obj_adr = (address)((uintptr_t)class_name_symbol); ++ replace_value_table = writer->heapRedactor()->lookup_class_value(obj_adr); ++ java_super = java_super->java_super(); ++ } while (replace_value_table == nullptr && java_super != nullptr); ++ ++ bool has_rules = replace_value_table != nullptr; ++ if(has_rules) { ++ dump_instance_redact_fields(writer, o, cache_entry, replace_value_table, container_id); ++ } else { ++ dump_instance_fields(writer, o, cache_entry); ++ } ++ ++ writer->end_sub_record(); ++} ++ ++char* DumperSupport::do_lookup_replace_value_with_symbol(AbstractDumpWriter* writer, typeArrayOop array) { ++ address obj_addr = cast_from_oop
    (array); ++ Symbol* anonymous_value_symbol = writer->heapRedactor()->lookup_replace_value(obj_addr); ++ if(anonymous_value_symbol == nullptr) { ++ return nullptr; ++ } ++ return anonymous_value_symbol->as_C_string(); ++} ++ ++char* DumperSupport::do_lookup_replace_value_with_char(AbstractDumpWriter* writer, typeArrayOop array) { ++ address obj_addr = cast_from_oop
    (array); ++ char* anonymous_value = writer->heapRedactor()->lookup_replace_value(obj_addr); ++ return anonymous_value; ++} ++ ++bool DumperSupport::dump_replace_value(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id) { ++ BasicType type = TypeArrayKlass::cast(array->klass())->element_type(); ++ if(type != T_BYTE) { ++ return false; ++ } ++ ++ // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) ++ short header_size = 2 * 1 + 2 * 4 + sizeof(address); ++ ++ int length = 0; ++ ++ char *anonymous_value = nullptr; ++ anonymous_value = fn(writer, array); ++ if(anonymous_value == nullptr) { ++ // record all array, expect who's replace value can be find now ++ return writer->heapRedactor()->record_typeArrayOop(array, container_id); ++ } ++ ++ size_t char_length = strlen(anonymous_value); ++ length = DumperSupport::calculate_array_max_length(writer, array, header_size, char_length); ++ ++ int type_size = type2aelembytes(type); ++ u4 length_in_bytes = (u4)length * type_size; ++ u4 size = header_size + length_in_bytes; ++ ++ writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size); ++ writer->write_objectID(array); ++ writer->write_u4(STACK_TRACE_ID); ++ writer->write_u4(length); ++ writer->write_u1(HPROF_BYTE); ++ ++ // nothing to copy ++ if (length == 0) { ++ writer->end_sub_record(); ++ return true; ++ } ++ ++ writer->write_raw(anonymous_value, char_length); ++ writer->end_sub_record(); ++ return true; ++} ++ + // creates HPROF_GC_CLASS_DUMP record for the given instance class +-void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { ++void DumperSupport::dump_instance_class(CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS fn, AbstractDumpWriter* writer, Klass* k) { + InstanceKlass* ik = InstanceKlass::cast(k); + + // We can safepoint and do a heap dump at a point where we have a Klass, +@@ -1411,7 +1701,7 @@ void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { + + // description of instance fields + writer->write_u2(instance_fields_count); +- dump_instance_field_descriptors(writer, ik); ++ fn(writer, ik); + + writer->end_sub_record(); + } +@@ -1454,12 +1744,11 @@ void DumperSupport::dump_array_class(AbstractDumpWriter* writer, Klass* k) { + + // Hprof uses an u4 as record length field, + // which means we need to truncate arrays that are too long. +-int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size) { ++int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size, int char_length) { + BasicType type = ArrayKlass::cast(array->klass())->element_type(); + assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type"); + +- int length = array->length(); +- ++ int length = char_length == 0 ? array->length() : char_length; + int type_size; + if (type == T_OBJECT) { + type_size = sizeof(address); +@@ -1543,7 +1832,7 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr + break; + } + case T_BYTE : { +- writer->write_raw(array->byte_at_addr(0), length_in_bytes); ++ writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes); + break; + } + case T_CHAR : { +@@ -1601,6 +1890,101 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr + writer->end_sub_record(); + } + ++// creates HPROF_GC_PRIM_ARRAY_DUMP redact record for the given type array ++void DumperSupport::redact_basic_dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array) { ++ BasicType type = TypeArrayKlass::cast(array->klass())->element_type(); ++ ++ // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) ++ short header_size = 2 * 1 + 2 * 4 + sizeof(address); ++ ++ int length = calculate_array_max_length(writer, array, header_size); ++ int type_size = type2aelembytes(type); ++ u4 length_in_bytes = (u4)length * type_size; ++ u4 size = header_size + length_in_bytes; ++ ++ writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size); ++ writer->write_objectID(array); ++ writer->write_u4(STACK_TRACE_ID); ++ writer->write_u4(length); ++ writer->write_u1(type2tag(type)); ++ ++ // nothing to copy ++ if (length == 0) { ++ writer->end_sub_record(); ++ return; ++ } ++ ++ // If the byte ordering is big endian then we can copy most types directly ++ ++ switch (type) { ++ case T_INT : { ++ writer->write_zero_raw((void*)(array->int_at_addr(0)), length_in_bytes); ++ break; ++ } ++ case T_BYTE : { ++ writer->write_zero_raw((void*)(array->byte_at_addr(0)), length_in_bytes); ++ break; ++ } ++ case T_CHAR : { ++ writer->write_zero_raw((void*)(array->char_at_addr(0)), length_in_bytes); ++ break; ++ } ++ case T_SHORT : { ++ if (Endian::is_Java_byte_ordering_different()) { ++ WRITE_ARRAY(array, short, u2, length); ++ } else { ++ writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes); ++ } ++ break; ++ } ++ case T_BOOLEAN : { ++ if (Endian::is_Java_byte_ordering_different()) { ++ WRITE_ARRAY(array, bool, u1, length); ++ } else { ++ writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes); ++ } ++ break; ++ } ++ case T_LONG : { ++ if (Endian::is_Java_byte_ordering_different()) { ++ WRITE_ARRAY(array, long, u8, length); ++ } else { ++ writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes); ++ } ++ break; ++ } ++ ++ // handle float/doubles in a special value to ensure than NaNs are ++ // written correctly. TO DO: Check if we can avoid this on processors that ++ // use IEEE 754. ++ ++ case T_FLOAT : { ++ for (int i = 0; i < length; i++) { ++ dump_float(writer, array->float_at(i)); ++ } ++ break; ++ } ++ case T_DOUBLE : { ++ for (int i = 0; i < length; i++) { ++ dump_double(writer, array->double_at(i)); ++ } ++ break; ++ } ++ default : ShouldNotReachHere(); ++ } ++ ++ writer->end_sub_record(); ++} ++ ++// creates HPROF_GC_PRIM_ARRAY_DUMP redact record for the given type array ++void DumperSupport::redact_replace_dump_prim_array(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter *writer, typeArrayOop array, uint container_id) { ++ if(dump_replace_value(fn, writer, array, container_id)) { ++ return; ++ } ++ ++ DumperSupport::dump_prim_array(writer, array); ++} ++ + // create a HPROF_FRAME record of the given Method* and bci + void DumperSupport::dump_stack_frame(AbstractDumpWriter* writer, + int frame_serial_num, +@@ -1650,6 +2034,39 @@ void SymbolTableDumper::do_symbol(Symbol** p) { + } + } + ++// Support class used to generate HPROF_UTF8 records from the entries in the ++// SymbolTable and Redact the sensitive String. ++ ++class SymbolTableRedactDumper : public SymbolClosure { ++private: ++ AbstractDumpWriter* _writer; ++ AbstractDumpWriter* writer() const { return _writer; } ++public: ++ SymbolTableRedactDumper(AbstractDumpWriter* writer) { _writer = writer; } ++ void do_symbol(Symbol** p); ++}; ++ ++void SymbolTableRedactDumper::do_symbol(Symbol** p) { ++ ResourceMark rm; ++ Symbol* sym = *p; ++ int len = sym->utf8_length(); ++ if (len > 0) { ++ char* s = sym->as_utf8(); ++ ++ char* redact_field = NULL; ++ HeapDumpRedactLevel level = writer()->getHeapDumpRedactLevel(); ++ if((level == REDACT_NAMES || level == REDACT_FULL) && ++ (redact_field = writer()->heapRedactor()->lookup_redact_name(s)) != NULL){ ++ len = (int)strlen(redact_field); ++ s = redact_field; ++ } ++ ++ DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len); ++ writer()->write_symbolID(sym); ++ writer()->write_raw(s, len); ++ } ++} ++ + // Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records + + class JNILocalsDumper : public OopClosure { +@@ -1809,17 +2226,19 @@ class HeapObjectDumper : public ObjectClosure { + private: + AbstractDumpWriter* _writer; + HeapDumpLargeObjectList* _list; ++ CALL_DUMP_PRIM_ARRAY _redact_dump_prim_array; + + AbstractDumpWriter* writer() { return _writer; } +- bool is_large(oop o); ++ // bool is_large(oop o); + + DumperClassCacheTable _class_cache; + + public: +- HeapObjectDumper(AbstractDumpWriter* writer, HeapDumpLargeObjectList* list = nullptr) { +- _writer = writer; +- _list = list; +- } ++ HeapObjectDumper(AbstractDumpWriter* writer, CALL_DUMP_PRIM_ARRAY fn = DumperSupport::dump_prim_array, HeapDumpLargeObjectList* list = nullptr) { ++ _writer = writer; ++ _list = list; ++ _redact_dump_prim_array = fn; ++ } + + // called for each object in the heap + void do_object(oop o); +@@ -1839,7 +2258,7 @@ void HeapObjectDumper::do_object(oop o) { + + // If large object list exists and it is large object/array, + // add oop into the list and skip scan. VM thread will process it later. +- if (_list != nullptr && is_large(o)) { ++ if (_list != nullptr && DumperSupport::is_large(o)) { + _list->atomic_push(o); + return; + } +@@ -1852,11 +2271,72 @@ void HeapObjectDumper::do_object(oop o) { + DumperSupport::dump_object_array(writer(), objArrayOop(o)); + } else if (o->is_typeArray()) { + // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array +- DumperSupport::dump_prim_array(writer(), typeArrayOop(o)); ++ DumperSupport::redact_dump_prim_array(_redact_dump_prim_array, writer(), typeArrayOop(o)); + } + } + +-bool HeapObjectDumper::is_large(oop o) { ++void DumperSupport::redact_dump_prim_array(CALL_DUMP_PRIM_ARRAY fn, AbstractDumpWriter* dumpWriter, typeArrayOop o){ ++ fn(dumpWriter, o); ++} ++ ++class HeapObjectRedactDumper : public ObjectClosure { ++private: ++ AbstractDumpWriter* _writer; ++ HeapDumpLargeObjectList* _list; ++ ++ AbstractDumpWriter* writer() { return _writer; } ++ ++ CALL_DO_LOOKUP_REPLACE_VALUE _do_lookup_replace_value; ++ ++ DumperClassCacheTable _class_cache; ++ ++ uint container_id; ++ ++public: ++ HeapObjectRedactDumper(AbstractDumpWriter* writer, CALL_DO_LOOKUP_REPLACE_VALUE do_lookup_replace_value, HeapDumpLargeObjectList* list = nullptr, uint id = 0) { ++ _writer = writer; ++ _list = list; ++ container_id = id; ++ _do_lookup_replace_value = do_lookup_replace_value; ++ } ++ ++ // called for each object in the heap ++ void do_object(oop o); ++}; ++ ++void HeapObjectRedactDumper::do_object(oop o) { ++ // skip classes as these emitted as HPROF_GC_CLASS_DUMP records ++ if (o->klass() == vmClasses::Class_klass()) { ++ if (!java_lang_Class::is_primitive(o)) { ++ return; ++ } ++ } ++ ++ if (DumperSupport::mask_dormant_archived_object(o, nullptr) == nullptr) { ++ log_debug(cds, heap)("skipped dormant archived object " INTPTR_FORMAT " (%s)", p2i(o), o->klass()->external_name()); ++ return; ++ } ++ ++ // If large object list exists and it is large object/array, ++ // and oop into the list and skip scan. VM thread will process it later. ++ if (_list != nullptr && DumperSupport::is_large(o)) { ++ _list->atomic_push(o); ++ return; ++ } ++ ++ if (o->is_instance()) { ++ // create a HPROF_GC_INSTANCE record for each object ++ DumperSupport::dump_redact_instance(writer(), o, &_class_cache, container_id); ++ } else if (o->is_objArray()) { ++ // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array ++ DumperSupport::dump_object_array(writer(), objArrayOop(o)); ++ } else if (o->is_typeArray()) { ++ // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array ++ DumperSupport::redact_replace_dump_prim_array(_do_lookup_replace_value, writer(), typeArrayOop(o), container_id); ++ } ++} ++ ++bool DumperSupport::is_large(oop o) { + size_t size = 0; + if (o->is_instance()) { + // Use o->size() * 8 as the upper limit of instance size to avoid iterating static fields +@@ -1941,6 +2421,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { + ThreadStackTrace** _stack_traces; + int _num_threads; + // parallel heap dump support ++ static CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS _dump_instance_fields_descriptors; + uint _num_dumper_threads; + uint _num_writer_threads; + DumperController* _dumper_controller; +@@ -2033,6 +2514,9 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { + // HPROF_TRACE and HPROF_FRAME records + void dump_stack_traces(); + ++ // HeapVector Records ++ void do_heapVector(); ++ + // large objects + void dump_large_objects(ObjectClosure* writer); + +@@ -2052,6 +2536,14 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { + _dumper_controller = nullptr; + _poi = nullptr; + _large_object_list = new (std::nothrow) HeapDumpLargeObjectList(); ++ if(writer->getHeapDumpRedactLevel() == REDACT_ANNOTATION) { ++ _dump_instance_fields_descriptors = DumperSupport::dump_instance_annotation_field_descriptors; ++ } else if(writer->getHeapDumpRedactLevel() == REDACT_DIYRULES) { ++ _dump_instance_fields_descriptors = DumperSupport::dump_instance_diyrules_field_descriptors; ++ } else { ++ _dump_instance_fields_descriptors = DumperSupport::dump_instance_field_descriptors; ++ } ++ + if (oome) { + assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread"); + // get OutOfMemoryError zero-parameter constructor +@@ -2089,6 +2581,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { + + VM_HeapDumper* VM_HeapDumper::_global_dumper = nullptr; + DumpWriter* VM_HeapDumper::_global_writer = nullptr; ++CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS VM_HeapDumper::_dump_instance_fields_descriptors = nullptr; + + bool VM_HeapDumper::skip_operation() const { + return false; +@@ -2131,8 +2624,8 @@ void VM_HeapDumper::do_load_class(Klass* k) { + // writes a HPROF_GC_CLASS_DUMP record for the given class + void VM_HeapDumper::do_class_dump(Klass* k) { + if (k->is_instance_klass()) { +- DumperSupport::dump_instance_class(writer(), k); +- } else { ++ DumperSupport::dump_instance_class(_dump_instance_fields_descriptors, writer(), k); ++ } else { + DumperSupport::dump_array_class(writer(), k); + } + } +@@ -2317,14 +2810,15 @@ void VM_HeapDumper::doit() { + set_global_writer(); + + WorkerThreads* workers = ch->safepoint_workers(); +- + if (workers == nullptr) { + // Use serial dump, set dumper threads and writer threads number to 1. + _num_dumper_threads=1; + _num_writer_threads=1; ++ writer()->heapRedactor()->init_containers(_num_dumper_threads); + work(0); + } else { + prepare_parallel_dump(workers->active_workers()); ++ writer()->heapRedactor()->init_containers(_num_dumper_threads); + if (_num_dumper_threads > 1) { + ParallelObjectIterator poi(_num_dumper_threads); + _poi = &poi; +@@ -2361,8 +2855,14 @@ void VM_HeapDumper::work(uint worker_id) { + // timestamp is current time in ms + writer()->write_u8(os::javaTimeMillis()); + // HPROF_UTF8 records +- SymbolTableDumper sym_dumper(writer()); +- SymbolTable::symbols_do(&sym_dumper); ++ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_NAMES || ++ writer()->heapRedactor()->redact_level() == REDACT_FULL)){ ++ SymbolTableRedactDumper sym_dumper(writer()); ++ SymbolTable::symbols_do(&sym_dumper); ++ } else{ ++ SymbolTableDumper sym_dumper(writer()); ++ SymbolTable::symbols_do(&sym_dumper); ++ } + + // write HPROF_LOAD_CLASS records + { +@@ -2403,8 +2903,20 @@ void VM_HeapDumper::work(uint worker_id) { + // of the heap dump. + if (_num_dumper_threads <= 1) { + ResourceMark rm; +- HeapObjectDumper obj_dumper(writer()); +- Universe::heap()->object_iterate(&obj_dumper); ++ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC || ++ writer()->heapRedactor()->redact_level() == REDACT_FULL)) { ++ HeapObjectDumper obj_dumper(writer(), DumperSupport::redact_basic_dump_prim_array); ++ Universe::heap()->object_iterate(&obj_dumper); ++ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) { ++ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_symbol); ++ Universe::heap()->object_iterate(&obj_dumper); ++ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) { ++ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_char); ++ Universe::heap()->object_iterate(&obj_dumper); ++ } else { ++ HeapObjectDumper obj_dumper(writer()); ++ Universe::heap()->object_iterate(&obj_dumper); ++ } + } else { + assert(get_worker_type(worker_id) == DumperType + || get_worker_type(worker_id) == VMDumperType, +@@ -2418,10 +2930,23 @@ void VM_HeapDumper::work(uint worker_id) { + // Heap iteration. + { + ParDumpWriter pw(writer()); ++ pw.setHeapRedactor(writer()->heapRedactor()); + { + ResourceMark rm; +- HeapObjectDumper obj_dumper(&pw, _large_object_list); +- _poi->object_iterate(&obj_dumper, worker_id); ++ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC || ++ writer()->heapRedactor()->redact_level() == REDACT_FULL)) { ++ HeapObjectDumper obj_dumper(&pw, DumperSupport::redact_basic_dump_prim_array, _large_object_list); ++ _poi->object_iterate(&obj_dumper, worker_id); ++ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) { ++ HeapObjectRedactDumper obj_dumper(&pw, DumperSupport::do_lookup_replace_value_with_symbol, _large_object_list, worker_id); ++ _poi->object_iterate(&obj_dumper, worker_id); ++ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) { ++ HeapObjectRedactDumper obj_dumper(&pw, DumperSupport::do_lookup_replace_value_with_char, _large_object_list, worker_id); ++ _poi->object_iterate(&obj_dumper, worker_id); ++ } else { ++ HeapObjectDumper obj_dumper(&pw, DumperSupport::dump_prim_array, _large_object_list); ++ _poi->object_iterate(&obj_dumper, worker_id); ++ } + } + + if (get_worker_type(worker_id) == VMDumperType) { +@@ -2441,8 +2966,26 @@ void VM_HeapDumper::work(uint worker_id) { + assert(get_worker_type(worker_id) == VMDumperType, "Heap dumper must be VMDumper"); + // Use writer() rather than ParDumpWriter to avoid memory consumption. + ResourceMark rm; +- HeapObjectDumper obj_dumper(writer()); +- dump_large_objects(&obj_dumper); ++ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC || ++ writer()->heapRedactor()->redact_level() == REDACT_FULL)) { ++ HeapObjectDumper obj_dumper(writer(), DumperSupport::redact_basic_dump_prim_array); ++ dump_large_objects(&obj_dumper); ++ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) { ++ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_symbol); ++ dump_large_objects(&obj_dumper); ++ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) { ++ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_char); ++ dump_large_objects(&obj_dumper); ++ } else { ++ HeapObjectDumper obj_dumper(writer()); ++ dump_large_objects(&obj_dumper); ++ } ++ ++ // if value in INSTANCE is sensitive ++ // and redact level is REDACT_ANNOTATION ++ // writes HeapVector here ++ do_heapVector(); ++ + // Writes the HPROF_HEAP_DUMP_END record. + DumperSupport::end_of_dump(writer()); + // We are done with writing. Release the worker threads. +@@ -2507,6 +3050,68 @@ void VM_HeapDumper::dump_stack_traces() { + } + } + ++void VM_HeapDumper::do_heapVector(){ ++ CALL_DO_LOOKUP_REPLACE_VALUE fn = nullptr; ++ if(writer()->getHeapDumpRedactLevel() == REDACT_ANNOTATION) { ++ fn = DumperSupport::do_lookup_replace_value_with_symbol; ++ } else if(writer()->getHeapDumpRedactLevel() == REDACT_DIYRULES) { ++ fn = DumperSupport::do_lookup_replace_value_with_char; ++ } else { ++ return; ++ } ++ ++ BasicType type = T_BYTE; ++ short header_size = 2 * 1 + 2 * 4 + sizeof(address); ++ int type_size = type2aelembytes(type); ++ uint max_bytes = max_juint - header_size; ++ ++ uint container_nums = writer()->heapRedactor()->get_container_nums(); ++ for (uint container_index = 0; container_index < container_nums; container_index++) { ++ int node_len = 0, i =0; ++ void** items = nullptr; ++ void *vector_node = writer()->heapRedactor()->get_vector_node_next(nullptr, node_len, items, container_index); ++ while (vector_node != NULL && items != NULL) { ++ for (i = 0; i < node_len; i++) { ++ typeArrayOop array = (typeArrayOopDesc*)items[i]; ++ ++ char *anonymous_value = fn(writer(), array); ++ int length = anonymous_value == NULL ? array->length() : strlen(anonymous_value); ++ ++ u4 length_in_bytes = (u4) length * type_size; ++ if (length_in_bytes > max_bytes) { ++ length = max_bytes / type_size; ++ length_in_bytes = (size_t)length * type_size; ++ } ++ u4 size = header_size + length_in_bytes; ++ ++ writer()->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size); ++ writer()->write_objectID(array); ++ writer()->write_u4(STACK_TRACE_ID); ++ writer()->write_u4(length); ++ writer()->write_u1(HPROF_BYTE); ++ ++ // nothing to copy ++ if (length == 0) { ++ writer()->end_sub_record(); ++ continue; ++ } ++ if(anonymous_value != nullptr){ ++ writer()->write_raw(anonymous_value, length); ++ } else { ++ writer()->write_raw((void *) (array->byte_at_addr(0)), length_in_bytes); ++ } ++ writer()->end_sub_record(); ++ } ++ ++ // clear current node info, maybe next node items is NULL, node_len = 0 will skip this NULL point error ++ node_len = 0; ++ items = nullptr; ++ void *temp = writer()->heapRedactor()->get_vector_node_next(vector_node, node_len, items, container_index); ++ vector_node = temp; ++ } ++ } ++} ++ + // dump the large objects. + void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) { + _large_object_list->drain(cl); +@@ -2516,9 +3121,22 @@ void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) { + int HeapDumper::dump(const char* path, outputStream* out, int compression, bool overwrite, uint num_dump_threads) { + assert(path != nullptr && strlen(path) > 0, "path missing"); + ++ const char* path_and_anonymous = path; ++ const char* redact_params = nullptr; ++ // parse args[0] to get real path and redact_params ++ const char* split_char = strstr(path_and_anonymous, ";"); ++ size_t path_length = (split_char == nullptr) ? strlen(path_and_anonymous) : (unsigned long)(split_char - path_and_anonymous); ++ size_t path_and_anonymous_length = strlen(path_and_anonymous); ++ char* _path = NEW_C_HEAP_ARRAY(char, path_and_anonymous_length + 1, mtInternal); ++ strncpy(_path, path_and_anonymous, path_and_anonymous_length + 1); ++ _path[path_length] = '\0'; ++ if (split_char != NULL) { ++ redact_params = split_char + 1; ++ } ++ + // print message in interactive case + if (out != nullptr) { +- out->print_cr("Dumping heap to %s ...", path); ++ out->print_cr("Dumping heap to %s ...", _path); + timer()->start(); + } + // create JFR event +@@ -2535,17 +3153,26 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool + } + } + +- DumpWriter writer(new (std::nothrow) FileWriter(path, overwrite), compressor); ++ HeapRedactor heapRedactor(redact_params, out); ++ DumpWriter writer(new (std::nothrow) FileWriter(_path, overwrite), compressor); ++ if(heapRedactor.redact_level() > REDACT_UNKNOWN) { ++ if(out != NULL) { ++ out->print_cr("HeapDump Redact Level = %s", heapRedactor.get_redact_level_string()); ++ } ++ } ++ writer.setHeapRedactor(&heapRedactor); + + if (writer.error() != nullptr) { + set_error(writer.error()); + if (out != nullptr) { +- out->print_cr("Unable to create %s: %s", path, +- (error() != nullptr) ? error() : "reason unknown"); +- } +- return -1; ++ out->print_cr("Unable to create %s: %s", _path, ++ (error() != NULL) ? error() : "reason unknown"); ++ } ++ FREE_C_HEAP_ARRAY(char, _path); ++ return -1; + } + ++ FREE_C_HEAP_ARRAY(char, _path); + // generate the dump + VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome, num_dump_threads); + if (Thread::current()->is_VM_thread()) { +diff --git a/src/hotspot/share/services/heapRedactor.cpp b/src/hotspot/share/services/heapRedactor.cpp +new file mode 100644 +index 000000000..9fe4648df +--- /dev/null ++++ b/src/hotspot/share/services/heapRedactor.cpp +@@ -0,0 +1,676 @@ ++/* ++ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. 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. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei in the LICENSE file that accompanied this code. ++ * ++ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++#include "runtime/globals.hpp" ++#include "runtime/os.hpp" ++#include "runtime/arguments.hpp" ++#include "utilities/ostream.hpp" ++#include "memory/allocation.hpp" ++#include "memory/allocation.inline.hpp" ++#include "jvm_md.h" ++#include "utilities/debug.hpp" ++#include "services/heapRedactor.hpp" ++#include "logging/log.hpp" ++#include "logging/logLevel.hpp" ++ ++const char* HeapRedactor::REDACT_UNKNOWN_STR = "UNKNOWN"; ++const char* HeapRedactor::REDACT_OFF_STR = "OFF"; ++const char* HeapRedactor::REDACT_NAMES_STR = "NAMES"; ++const char* HeapRedactor::REDACT_BASIC_STR = "BASIC"; ++const char* HeapRedactor::REDACT_ANNOTATION_STR = "ANNOTATION"; ++const char* HeapRedactor::REDACT_DIYRULES_STR = "DIYRULES"; ++const char* HeapRedactor::REDACT_FULL_STR = "FULL"; ++ ++HeapRedactor::HeapRedactor(outputStream* out) { ++ init_fields(); ++ _use_sys_params = true; ++ init(out); ++} ++ ++HeapRedactor::HeapRedactor(const char *redact_params_string, outputStream* out) { ++ init_fields(); ++ if (redact_params_string != NULL && strlen(redact_params_string) > 0) { ++ _use_sys_params = false; ++ parse_redact_params(redact_params_string); ++ } else { ++ _use_sys_params = true; ++ } ++ init(out); ++} ++ ++HeapRedactor::~HeapRedactor() { ++#ifdef LINUX ++ if(_redact_name_table != NULL) { ++ os::Linux::heap_dict_free(_redact_name_table,false); ++ _redact_name_table = NULL; ++ } ++ ++ if(_redact_rules_table != NULL) { ++ os::Linux::heap_dict_free(_redact_rules_table, true); ++ _redact_rules_table = NULL; ++ } ++ ++ if(_annotation_value_tables != NULL) { ++ for(uint i = 0; i < _container_nums; i++) { ++ if(_annotation_value_tables[i] != NULL) { ++ os::Linux::heap_dict_free(_annotation_value_tables[i], false); ++ _annotation_value_tables[i] = NULL; ++ } ++ } ++ } ++ ++ if(_redact_class_field_table != NULL) { ++ os::Linux::heap_dict_free(_redact_class_field_table, true); ++ _redact_class_field_table = NULL; ++ } ++ ++ if(_redact_records!= NULL) { ++ for(uint i = 0; i < _container_nums; i++) { ++ if(_redact_records[i] != NULL) { ++ os::Linux::heap_vector_free(_redact_records[i]); ++ _redact_records[i] = NULL; ++ } ++ } ++ } ++#endif ++ if(_annotation_value_tables != NULL) { ++ FREE_C_HEAP_ARRAY(void*, _annotation_value_tables); ++ } ++ ++ if(_redact_records != NULL) { ++ FREE_C_HEAP_ARRAY(void*, _redact_records); ++ } ++ ++ if(_name_map_list != NULL){ ++ FREE_C_HEAP_ARRAY(char, _name_map_list); ++ } ++ if(_file_name_map_list != NULL){ ++ FREE_C_HEAP_ARRAY(char, _file_name_map_list); ++ } ++ if(_annotation_class_path != NULL) { ++ FREE_C_HEAP_ARRAY(char, _annotation_class_path); ++ } ++ _file_name_map_list = NULL; ++ _name_map_list = NULL; ++ _annotation_class_path = NULL; ++} ++ ++void HeapRedactor::init_fields() { ++ _redact_level = REDACT_UNKNOWN; ++ _redact_name_table = NULL; ++ _redact_rules_table= NULL; ++ _annotation_value_tables = NULL; ++ _redact_records = NULL; ++ _redact_class_field_table = NULL; ++ _file_name_map_list = NULL; ++ _name_map_list = NULL; ++ _redact_class_full_name = NULL; ++ _annotation_class_path = NULL; ++ ++ _redact_params.params_string = NULL; ++ _redact_params.heap_dump_redact = NULL; ++ _redact_params.redact_map = NULL; ++ _redact_params.redact_map_file = NULL; ++ _redact_params.annotation_class_path = NULL; ++ _redact_params.redact_password = NULL; ++} ++ ++void HeapRedactor::parse_redact_params(const char *redact_params_string) { ++ size_t length = strlen(redact_params_string); ++ char* buf = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal); ++ _redact_params.params_string = buf; ++ strncpy(_redact_params.params_string, redact_params_string, length + 1); ++ size_t start = strlen("-HeapDumpRedact="); ++ _redact_params.heap_dump_redact = _redact_params.params_string + start; ++ char* map_pos = strstr(_redact_params.heap_dump_redact, ",RedactMap="); ++ char* file_pos = strstr(_redact_params.heap_dump_redact, ",RedactMapFile="); ++ char* class_path_pos = strstr(_redact_params.heap_dump_redact, ",RedactClassPath="); ++ char* redact_password_pos = strstr(_redact_params.heap_dump_redact, ",RedactPassword="); ++ ++ _redact_params.redact_map = parse_redact_child_param(map_pos, ",RedactMap=", ++ file_pos); ++ _redact_params.redact_map_file = parse_redact_child_param(file_pos, ",RedactMapFile=", ++ class_path_pos); ++ _redact_params.annotation_class_path = parse_redact_child_param(class_path_pos, ",RedactClassPath=", ++ redact_password_pos); ++ _redact_params.redact_password = parse_redact_child_param(redact_password_pos, ",RedactPassword=", ++ _redact_params.params_string + length); ++} ++ ++char* HeapRedactor::parse_redact_child_param(char *redact_params_sub_string, const char* redact_param_prefix, ++ const char* next_redact_param_prefix) { ++ char* pos = NULL; ++ if (redact_params_sub_string == NULL) { ++ pos = NULL; ++ } else { ++ *redact_params_sub_string = '\0'; ++ pos = redact_params_sub_string + strlen(redact_param_prefix); ++ if (pos == next_redact_param_prefix) { ++ pos = NULL; ++ } ++ } ++ return pos; ++} ++ ++bool HeapRedactor::check_launcher_heapdump_redact_support(const char *value) { ++ if (!strcmp(value, "=basic") || !strcmp(value, "=names") || !strcmp(value, "=off") ++ || !strcmp(value, "=diyrules") || !strcmp(value, "=annotation") || !strcmp(value, "=full")) { ++ return true; ++ } ++ return false; ++} ++ ++void HeapRedactor::init(outputStream* out) { ++ /** -XX:+VerifyRedactPassword, ++ * if HeapDumpRedact is NULL , jmap operation can not open redact feature without password ++ * if HeapDumpRedact is not NULL, jmap operation can not change redact level without password ++ **/ ++ char* split_char = NULL; ++ if(RedactPassword == NULL || (split_char = strstr(const_cast(RedactPassword), ",")) == NULL || strlen(split_char) < SALT_LEN) { ++ VerifyRedactPassword = false; ++ } ++ if(VerifyRedactPassword && !_use_sys_params) { ++ size_t auth_len = strlen(RedactPassword); ++ size_t suffix_len = strlen(split_char); ++ if(_redact_params.redact_password == NULL || ++ strncmp(_redact_params.redact_password, RedactPassword, auth_len-suffix_len) ) { ++ // no password or wrong password ++ _use_sys_params = true; ++ if(out != NULL) { ++ out->print_cr("not correct password, use the default redact mode when stared"); ++ } ++ } ++ } ++ ++ if(_redact_params.redact_password != NULL) { ++ size_t password_Len = strlen(_redact_params.redact_password); ++ memset(_redact_params.redact_password, '\0', password_Len); ++ } ++ ++ if (_redact_level == REDACT_UNKNOWN) { ++ init_heapdump_redact_level(); ++ } ++ return; ++} ++ ++void HeapRedactor::init_redact_map() { ++ const char* map_param = NULL; ++ const char* map_file_param = NULL; ++ if (_use_sys_params) { ++ map_param = RedactMap; ++ map_file_param = RedactMapFile; ++ } else { ++ map_param = _redact_params.redact_map; ++ map_file_param = _redact_params.redact_map_file; ++ } ++ if (map_file_param != NULL) { ++ read_redact_map_from_file(map_file_param); ++ } ++ if (map_param != NULL) { ++ size_t length = strlen(map_param); ++ _name_map_list = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal); ++ strncpy(_name_map_list, map_param, length + 1); ++ read_redact_map_dependon_mode(_name_map_list, _redact_level); ++ } ++} ++ ++void HeapRedactor::read_redact_map_dependon_mode(char* name_map_list, HeapDumpRedactLevel redact_level) { ++ if(redact_level == REDACT_DIYRULES) { ++ parse_redact_diy_rules(name_map_list); ++ } else { ++ parse_redact_map_string(name_map_list); ++ } ++} ++ ++void HeapRedactor::parse_redact_map_string(char *name_map_list) { ++#ifdef LINUX ++ size_t token_start = 0; ++ size_t step = 0; ++ size_t length = strlen(name_map_list); ++ ++ while (step < length) { ++ bool is_seperator = false; ++ if ((is_seperator = (name_map_list[step] == ',' || name_map_list[step] == ';' || name_map_list[step] == '\n' || ++ name_map_list[step] == ' ')) || ++ step == length - 1) { ++ if (is_seperator) { ++ name_map_list[step] = '\0'; ++ } else { ++ step++; ++ } ++ ++ if (token_start >= step) { ++ // to reduce the depth of the method ++ token_start = step + 1; ++ continue; ++ } ++ ++ char *token = name_map_list + token_start; ++ size_t i = 0; ++ size_t token_length = strlen(token); ++ while (i < token_length && token[i] != ':') { ++ i++; ++ } ++ if (i < token_length - 1) { ++ token[i] = '\0'; ++ _redact_name_table = os::Linux::heap_dict_add(token, token + i + 1, _redact_name_table, 0); ++ } ++ token_start = step + 1; ++ } ++ step++; ++ } ++#endif ++} ++ ++void HeapRedactor::read_redact_map_from_file(const char *path) { ++ char base_path[JVM_MAXPATHLEN] = {'\0'}; ++ char buffer[MAX_MAP_FILE_LENGTH + 1] = {'\0'}; ++ if (path == NULL || path[0] == '\0') { ++ // RedactMapFile= not specified ++ } else { ++ if (strlen(path) >= JVM_MAXPATHLEN) { ++ warning("RedactMap File path is too long "); ++ return; ++ } ++ strncpy(base_path, path, sizeof(base_path)); ++ // check if the path is a directory (must exist) ++ FILE* fm = NULL; ++ fm = fopen(base_path, "r"); ++ if (fm == NULL) { ++ return; ++ } ++ size_t num_read = fread((char *)buffer, 1, MAX_MAP_FILE_LENGTH, fm); ++ if((int)num_read != -1){ ++ _file_name_map_list = NEW_C_HEAP_ARRAY(char, (size_t)num_read + 1, mtInternal); ++ strncpy(_file_name_map_list, buffer, num_read + 1); ++ read_redact_map_dependon_mode(_file_name_map_list, _redact_level); ++ } ++ ++ fclose(fm); ++ } ++} ++ ++void HeapRedactor::parse_redact_diy_rules(char* name_map_list) { ++ size_t token_start = 0; ++ size_t step = 0; ++ size_t length = strlen(name_map_list); ++ ++ while (step < length) { ++ bool is_seperator = false; ++ if ((is_seperator = (name_map_list[step] == ',' || name_map_list[step] == ';' || name_map_list[step] == '\n' || ++ name_map_list[step] == ' ')) || ++ step == length - 1) { ++ if (is_seperator) { ++ name_map_list[step] = '\0'; ++ } else { ++ step++; ++ } ++ ++ if (token_start >= step) { ++ // to reduce the depth of the method ++ token_start = step + 1; ++ continue; ++ } ++ ++ char *token = name_map_list + token_start; ++ parse_token(token); ++ token_start = step + 1; ++ } ++ step++; ++ } ++ ++ // clear _redact_class_full_name, encase RedactMap has an unformatted value(without class name), ++ // will rewrite the last class's value_map ++ _redact_class_full_name = NULL; ++} ++ ++void HeapRedactor::parse_token(char* token) { ++#ifdef LINUX ++ size_t i = 0; ++ size_t token_length = strlen(token); ++ while (i < token_length && token[i] != ':') { ++ if(token[i] == '.' ) { ++ token[i] = '/'; ++ } ++ i++; ++ } ++ ++ void* _redact_rules_sub_table = _redact_class_full_name == NULL ? NULL : ++ os::Linux::heap_dict_lookup(_redact_class_full_name, _redact_rules_table, false); ++ if (i < token_length - 1 && _redact_rules_sub_table != NULL) { ++ token[i] = '\0'; ++ os::Linux::heap_dict_add(token, token + i + 1, _redact_rules_sub_table, 0); ++ } else if( i == token_length) { ++ _redact_class_full_name = token; ++ _redact_rules_sub_table = os::Linux::heap_dict_lookup(token, _redact_rules_table, false); ++ if (_redact_rules_sub_table == NULL) { ++ _redact_rules_sub_table = os::Linux::heap_dict_add(token, NULL, _redact_rules_sub_table, 0); ++ _redact_rules_table = os::Linux::heap_dict_add(token, _redact_rules_sub_table, _redact_rules_table, 0); ++ } ++ } ++#endif ++} ++ ++HeapDumpRedactLevel HeapRedactor::init_heapdump_redact_level() { ++ const char* redact_string = NULL; ++ if (_use_sys_params) { ++ redact_string = HeapDumpRedact; ++ } else { ++ redact_string = _redact_params.heap_dump_redact; ++ } ++ if (redact_string == NULL) { ++ _redact_level = REDACT_OFF; ++ } else { ++#ifdef LINUX ++ if (strcmp(redact_string, "basic") == 0) { ++ _redact_level = REDACT_BASIC; ++ } else if (strcmp(redact_string, "names") == 0) { ++ _redact_level = REDACT_NAMES; ++ init_redact_map(); ++ } else if (strcmp(redact_string, "full") == 0) { ++ _redact_level = REDACT_FULL; ++ init_redact_map(); ++ } else if (strcmp(redact_string, "diyrules") == 0) { ++ _redact_level = REDACT_DIYRULES; ++ init_redact_map(); ++ } else if (strcmp(redact_string, "annotation") == 0) { ++ _redact_level = REDACT_ANNOTATION; ++ init_class_path(); ++ if(_annotation_class_path == NULL) { ++ _redact_level = REDACT_OFF; ++ } ++ } else { ++ _redact_level = REDACT_OFF; ++ } ++#else ++ if (strcmp(redact_string, "basic") == 0) { ++ _redact_level = REDACT_BASIC; ++ } else if (strcmp(redact_string, "full") == 0) { ++ _redact_level = REDACT_BASIC; ++ } else { ++ _redact_level = REDACT_OFF; ++ } ++#endif ++ ++ } ++ ++ if (_redact_params.params_string != NULL) { ++ FREE_C_HEAP_ARRAY(char, _redact_params.params_string); ++ } ++ return _redact_level; ++} ++ ++void HeapRedactor::init_class_path() { ++ const char* class_path = NULL; ++ if (_use_sys_params) { ++ class_path = RedactClassPath; ++ } else { ++ class_path = _redact_params.annotation_class_path; ++ } ++ ++ if(class_path != NULL) { ++ size_t class_path_len = strlen(class_path); ++ _annotation_class_path = NEW_C_HEAP_ARRAY(char, class_path_len + 3, mtInternal); ++ _annotation_class_path[0] = 'L'; ++ strncpy(_annotation_class_path + 1, class_path, class_path_len + 1); ++ _annotation_class_path[class_path_len + 1] = ';'; ++ _annotation_class_path[class_path_len + 2] = '\0'; ++ } ++} ++ ++void HeapRedactor::insert_anonymous_value(void* key, void* value, uint index){ ++#ifdef LINUX ++ _annotation_value_tables[index] = os::Linux::heap_dict_add(key, value, _annotation_value_tables[index], 1); ++#endif ++} ++ ++bool HeapRedactor::recursion_cp_refs_in_annotation_struct( ++ AnnotationArray* annotations_typeArray, int &byte_i_ref) { ++ if ((byte_i_ref + 2 + 2) > annotations_typeArray->length()) { ++ // not enough room for smallest annotation_struct ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("length() is too small for annotation_struct"); ++ } ++ return false; ++ } ++ ++ u2 type_index = Bytes::get_Java_u2((address)annotations_typeArray->adr_at(byte_i_ref)); ++ byte_i_ref += 2; ++ ++ u2 num_element_value_pairs = Bytes::get_Java_u2((address) annotations_typeArray->adr_at(byte_i_ref)); ++ byte_i_ref += 2; ++ ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("type_index=%d num_element_value_pairs=%d", type_index, num_element_value_pairs); ++ } ++ ++ int calc_num_element_value_pairs = 0; ++ for (; calc_num_element_value_pairs < num_element_value_pairs; ++ calc_num_element_value_pairs++) { ++ if ((byte_i_ref + 2) > annotations_typeArray->length()) { ++ // not enough room for another element_name_index, let alone ++ // the rest of another component ++ log_debug(cds, heap)("length() is too small for element_name_index"); ++ return false; ++ } ++ ++ u2 element_name_index = Bytes::get_Java_u2((address) annotations_typeArray->adr_at(byte_i_ref)); ++ byte_i_ref += 2; ++ ++ log_debug(cds, heap)("element_name_index=%d", element_name_index); ++ ++ if (!recursion_cp_refs_in_element_value(annotations_typeArray, byte_i_ref)) { ++ log_debug(cds, heap)("bad element_value at %d", calc_num_element_value_pairs); ++ // propagate failure back to caller ++ return false; ++ } ++ } // end for each component ++ assert(num_element_value_pairs == calc_num_element_value_pairs, "sanity check"); ++ ++ return true; ++} // end recursion_cp_refs_in_annotation_struct() ++ ++bool HeapRedactor::lookup_annotation_index_in_constant_pool(AnnotationArray* field_annotations, ConstantPool *cp, int &byte_i_ref) { ++ u2 num_annotations = 0; ++ bool has_anonymous_annotation = false; ++ ++ if ((byte_i_ref + 2) > field_annotations->length()) { ++ // not enough room for num_annotations field ++ log_debug(cds, heap)("length() is too small for num_annotations field"); ++ return false; ++ } else { ++ num_annotations = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref)); ++ } ++ ++ byte_i_ref += 2; ++ ++ for (int calc_num_annotations = 0; calc_num_annotations < num_annotations; calc_num_annotations++) { ++ ++ if ((byte_i_ref + 2 + 2) > field_annotations->length()) { ++ // not enough room for smallest annotation_struct ++ log_debug(cds, heap)("length() is too small for annotation_struct"); ++ return false; ++ } ++ ++ // get constants pool index ++ address cp_index_addr = (address) field_annotations->adr_at(byte_i_ref); ++ byte_i_ref += 2; ++ u2 cp_index = Bytes::get_Java_u2(cp_index_addr); ++ Symbol *annotate_class_symbol = cp->symbol_at(cp_index); ++ if (!Symbol::is_valid(annotate_class_symbol)) { ++ return false; ++ } ++ char *annotate_class_name = annotate_class_symbol->as_C_string(); ++ ++ u2 num_element_value_pairs = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref)); ++ byte_i_ref += 2; ++ if ((byte_i_ref + 2 + 1) > field_annotations->length()) { ++ // not enough room for smallest annotation_struct ++ log_debug(cds, heap)("length() is too small for element_name_index"); ++ return false; ++ } ++ ++ const char *annotation_class_path = get_annotation_class_path(); ++ has_anonymous_annotation = (strcmp(annotation_class_path, annotate_class_name) == 0); ++ if (has_anonymous_annotation) { ++ address element_name_addr = (address) field_annotations->adr_at(byte_i_ref); ++ byte_i_ref += 2; ++ u2 cp_name_index = Bytes::get_Java_u2(element_name_addr); ++ Symbol *element_name_symbol = cp->symbol_at(cp_name_index); ++ char *element_name = element_name_symbol->as_C_string(); ++ if(element_name == NULL || strcmp(element_name, "value")) { ++ // expected annotation has only one field "value" ++ return false; ++ } ++ // skip element tag ++ byte_i_ref++; ++ return true; ++ } ++ ++ int calc_num_element_value_pairs = 0; ++ // skip element_name_index ++ byte_i_ref += 2; ++ for (; calc_num_element_value_pairs < num_element_value_pairs; calc_num_element_value_pairs++) { ++ if (!recursion_cp_refs_in_element_value(field_annotations, byte_i_ref)) { ++ return false; ++ } ++ } ++ } ++ return false; ++} ++ ++bool HeapRedactor::recursion_cp_refs_in_element_value(AnnotationArray* field_annotations, int &byte_i_ref) { ++ if ((byte_i_ref + 1) > field_annotations->length()) { ++ // not enough room for a tag let alone the rest of an element_value ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("length() is too small for a tag"); ++ } ++ return false; ++ } ++ ++ u1 tag = field_annotations->at(byte_i_ref); ++ byte_i_ref++; ++ switch (tag) { ++ case JVM_SIGNATURE_BYTE: ++ case JVM_SIGNATURE_CHAR: ++ case JVM_SIGNATURE_DOUBLE: ++ case JVM_SIGNATURE_FLOAT: ++ case JVM_SIGNATURE_INT: ++ case JVM_SIGNATURE_LONG: ++ case JVM_SIGNATURE_SHORT: ++ case JVM_SIGNATURE_BOOLEAN: ++ case 's': ++ case 'c': ++ { ++ if ((byte_i_ref + 2) > field_annotations->length()) { ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("length() is too small for a const_value_index"); ++ } ++ break; ++ } ++ byte_i_ref += 2; ++ } break; ++ case 'e': ++ { ++ if ((byte_i_ref + 4) > field_annotations->length()) { ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("length() is too small for a enum_const_value"); ++ } ++ break; ++ } ++ byte_i_ref += 4; ++ } break; ++ ++ case '@': ++ // For the above tag value, value.attr_value is the right union ++ // field. This is a nested annotation. ++ if (!recursion_cp_refs_in_annotation_struct(field_annotations, byte_i_ref)) { ++ // propagate failure back to caller ++ return false; ++ } ++ break; ++ ++ case JVM_SIGNATURE_ARRAY: ++ { ++ if ((byte_i_ref + 2) > field_annotations->length()) { ++ // not enough room for a num_values field ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("length() is too small for a num_values field"); ++ } ++ return false; ++ } ++ ++ // For the above tag value, value.array_value is the right union ++ // field. This is an array of nested element_value. ++ u2 num_values = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref)); ++ byte_i_ref += 2; ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("num_values=%d", num_values); ++ } ++ ++ int calc_num_values = 0; ++ for (; calc_num_values < num_values; calc_num_values++) { ++ if (!recursion_cp_refs_in_element_value(field_annotations, byte_i_ref)) { ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("bad nested element_value at %d", calc_num_values); ++ } ++ // propagate failure back to caller ++ return false; ++ } ++ } ++ } break; ++ ++ default: ++ if (log_is_enabled(Debug, cds, heap)) { ++ log_debug(cds, heap)("bad tag=0x%x", tag); ++ } ++ return false; ++ } ++ ++ return true; ++} ++ ++bool HeapRedactor::record_typeArrayOop(typeArrayOop array, uint index) { ++ bool _inserted = false; ++#ifdef LINUX ++ _redact_records[index] = os::Linux::heap_vector_add(array, _redact_records[index], _inserted); ++#endif ++ return _inserted; ++} ++ ++void HeapRedactor::insert_class_field_value(void* class_key, void* field_key, void* value) { ++#ifdef LINUX ++ void* _redact_sub_table = os::Linux::heap_dict_lookup(class_key, _redact_class_field_table, false); ++ _redact_sub_table = os::Linux::heap_dict_add(field_key, value, _redact_sub_table, 1); ++ _redact_class_field_table = os::Linux::heap_dict_add(class_key, _redact_sub_table, _redact_class_field_table, 1); ++#endif ++} ++ ++void HeapRedactor::init_containers(uint nums) { ++ _container_nums = (nums == 0 ? 1 : nums); ++ _annotation_value_tables = NEW_C_HEAP_ARRAY(void*, _container_nums, mtInternal); ++ memset(_annotation_value_tables, 0, sizeof(void*)*_container_nums); ++ _redact_records = NEW_C_HEAP_ARRAY(void*, _container_nums, mtInternal); ++ memset(_redact_records, 0, sizeof(void*)*_container_nums); ++} +\ No newline at end of file +diff --git a/src/hotspot/share/services/heapRedactor.hpp b/src/hotspot/share/services/heapRedactor.hpp +new file mode 100644 +index 000000000..467baa39d +--- /dev/null ++++ b/src/hotspot/share/services/heapRedactor.hpp +@@ -0,0 +1,225 @@ ++/* ++ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. 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. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei in the LICENSE file that accompanied this code. ++ * ++ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++#ifndef SHARE_SERVICES_HEAPREDACTOR_HPP ++#define SHARE_SERVICES_HEAPREDACTOR_HPP ++#include "memory/allocation.hpp" ++#include "oops/annotations.hpp" ++#include "oops/constantPool.hpp" ++#ifdef LINUX ++#include "os_linux.hpp" ++#endif ++ ++#define MAX_MAP_FILE_LENGTH 1024 ++#define SALT_LEN 9 ++ ++enum HeapDumpRedactLevel { ++ REDACT_UNKNOWN, ++ REDACT_OFF, ++ REDACT_NAMES, ++ REDACT_BASIC, ++ REDACT_DIYRULES, ++ REDACT_ANNOTATION, ++ REDACT_FULL ++}; ++ ++struct RedactParams { ++ char* params_string; ++ char* heap_dump_redact; ++ char* redact_map; ++ char* redact_map_file; ++ char* annotation_class_path; ++ char* redact_password; ++}; ++ ++class HeapRedactor : public StackObj { ++public: ++ static const char* REDACT_UNKNOWN_STR; ++ static const char* REDACT_OFF_STR; ++ static const char* REDACT_NAMES_STR; ++ static const char* REDACT_BASIC_STR; ++ static const char* REDACT_DIYRULES_STR; ++ static const char* REDACT_ANNOTATION_STR; ++ static const char* REDACT_FULL_STR; ++ HeapRedactor(outputStream* out); ++ HeapRedactor(const char* redact_params, outputStream* out); ++ ~HeapRedactor(); ++ static bool check_launcher_heapdump_redact_support(const char* value); ++ HeapDumpRedactLevel redact_level() { ++ if(_redact_level == REDACT_UNKNOWN) { ++ _redact_level = init_heapdump_redact_level(); ++ } ++ ++ return _redact_level; ++ } ++ ++ const char* get_redact_level_string() const { ++#ifdef LINUX ++ switch (_redact_level) { ++ case REDACT_OFF: ++ return REDACT_OFF_STR; ++ case REDACT_NAMES: ++ return REDACT_NAMES_STR; ++ case REDACT_BASIC: ++ return REDACT_BASIC_STR; ++ case REDACT_DIYRULES: ++ return REDACT_DIYRULES_STR; ++ case REDACT_ANNOTATION: ++ return REDACT_ANNOTATION_STR; ++ case REDACT_FULL: ++ return REDACT_FULL_STR; ++ case REDACT_UNKNOWN: ++ default: ++ return REDACT_UNKNOWN_STR; ++ } ++#else ++ switch (_redact_level) { ++ case REDACT_OFF: ++ return REDACT_OFF_STR; ++ case REDACT_BASIC: ++ return REDACT_BASIC_STR; ++ case REDACT_UNKNOWN: ++ default: ++ return REDACT_UNKNOWN_STR; ++ } ++#endif ++ ++ } ++ ++ char* lookup_redact_name(const void* name) { ++ void* val = NULL; ++#ifdef LINUX ++ val = os::Linux::heap_dict_lookup(const_cast(name), _redact_name_table, false); ++#endif ++ if(val != NULL) { ++ return (char*)val; ++ } ++ return NULL; ++ } ++ ++ void* lookup_class_rules(const void* name) { ++ void* val = NULL; ++#ifdef LINUX ++ val = os::Linux::heap_dict_lookup(const_cast(name), _redact_rules_table, false); ++#endif ++ return val; ++ } ++ ++ const char* get_annotation_class_path(){ ++ return _annotation_class_path; ++ } ++ ++ void insert_anonymous_value(void* key, void* value, uint index); ++ ++ template ++ T lookup_replace_value(void* key) { ++ void* val = NULL; ++#ifdef LINUX ++ for(uint i = 0; i < _container_nums; i++) { ++ if(_annotation_value_tables[i] == NULL) { ++ continue; ++ } ++ val = os::Linux::heap_dict_lookup(key, _annotation_value_tables[i], true); ++ if(val != NULL) { ++ break; ++ } ++ } ++#endif ++ if(val != NULL) { ++ return (T)val; ++ } ++ return NULL; ++ } ++ ++ bool lookup_annotation_index_in_constant_pool(AnnotationArray* field_annotations, ConstantPool *cp, int &byte_i_ref); ++ bool recursion_cp_refs_in_element_value(AnnotationArray* field_annotations, int &byte_i_ref); ++ bool recursion_cp_refs_in_annotation_struct(AnnotationArray* field_annotations, int &byte_i_ref); ++ ++ bool record_typeArrayOop(typeArrayOop array, uint index); ++ void* get_vector_node_next(void* node, int &_cnt, void** &_items, uint index) { ++ void* val = NULL; ++#ifdef LINUX ++ val = os::Linux::heap_vector_get_next(_redact_records[index], node, _cnt, _items); ++#endif ++ return val; ++ } ++ ++ void insert_class_field_value(void* class_key, void* field_key, void* value); ++ void* lookup_class_value(void* key) { ++ void* val = NULL; ++#ifdef LINUX ++ if(_redact_class_field_table == NULL) { ++ return val; ++ } ++ val = os::Linux::heap_dict_lookup(key, _redact_class_field_table, false); ++#endif ++ return val; ++ } ++ ++ void* lookup_value(void* key, void* heap_dict, bool deletable) { ++ void* val = NULL; ++#ifdef LINUX ++ val = os::Linux::heap_dict_lookup(key, heap_dict, deletable); ++#endif ++ return val; ++ } ++ ++ void init_containers(uint nums); ++ const uint get_container_nums() { ++ return _container_nums; ++ } ++ ++private: ++ HeapDumpRedactLevel _redact_level; ++ RedactParams _redact_params; ++ bool _use_sys_params; ++ void* _redact_name_table; ++ void* _redact_rules_table; ++ void** _annotation_value_tables; ++ // void* _annotation_value_table; ++ void* _redact_class_field_table; ++ char* _file_name_map_list; ++ char* _name_map_list; ++ char* _annotation_class_path; ++ char* _redact_class_full_name; ++ void** _redact_records; ++ //void* _redact_record; ++ // safety: every dump thread has one map and one vector ++ uint _container_nums; ++ ++ HeapDumpRedactLevel init_heapdump_redact_level(); ++ void read_redact_map_from_file(const char* path); ++ void read_redact_map_dependon_mode(char* name_map_list, HeapDumpRedactLevel redact_level); ++ void parse_redact_map_string(char* name_map_list); ++ void parse_redact_diy_rules(char* name_map_list); ++ void parse_token(char* token); ++ void parse_redact_params(const char *redact_params_string); ++ char* parse_redact_child_param(char *redact_params_sub_string, const char* redact_param_prefix, const char* next_redact_param_prefix); ++ void init(outputStream* out); ++ void init_fields(); ++ void init_redact_map(); ++ void init_class_path(); ++ ++}; ++#endif // SHARE_SERVICES_HEAPREDACTOR_HPP +\ No newline at end of file +diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp +index d4f601ed8..6e8924c86 100644 +--- a/src/hotspot/share/services/writeableFlags.cpp ++++ b/src/hotspot/share/services/writeableFlags.cpp +@@ -235,6 +235,13 @@ JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVM + + JVMFlag* f = JVMFlag::find_flag(name); + if (f) { ++ if(VerifyRedactPassword) { ++ if(strcmp(name, "HeapDumpRedact") == 0 || strcmp(name, "RedactMap") == 0 || strcmp(name, "RedactMapFile") == 0 ++ || strcmp(name, "RedactClassPath") == 0) { ++ err_msg.print("has no authority to reset redact params"); ++ return JVMFlag::NON_WRITABLE; ++ } ++ } + // only writeable flags are allowed to be set + if (f->is_writeable()) { + return setter(f, value, origin, err_msg); +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +index 9cc51934d..80d64ea97 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +@@ -41,15 +41,16 @@ import sun.jvm.hotspot.gc.g1.*; + import sun.jvm.hotspot.gc.x.*; + import sun.jvm.hotspot.gc.z.*; + import sun.jvm.hotspot.interpreter.*; +-import sun.jvm.hotspot.oops.*; + import sun.jvm.hotspot.runtime.*; + import sun.jvm.hotspot.ui.*; ++import sun.jvm.hotspot.ui.Annotation; + import sun.jvm.hotspot.ui.tree.*; + import sun.jvm.hotspot.ui.classbrowser.*; + import sun.jvm.hotspot.utilities.*; + import sun.jvm.hotspot.utilities.Observable; + import sun.jvm.hotspot.utilities.Observer; +- ++import sun.jvm.hotspot.oops.*; ++ + /** The top-level HotSpot Debugger. FIXME: make this an embeddable + component! (Among other things, figure out what to do with the + menu bar...) */ +@@ -1003,7 +1004,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { + } + + if (curFrame.getFP() != null) { +- annoPanel.addAnnotation(new Annotation(curFrame.getSP(), ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.getSP(), + curFrame.getFP(), + anno)); + } else { +@@ -1013,14 +1014,14 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { + if (Assert.ASSERTS_ENABLED) { + Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size"); + } +- annoPanel.addAnnotation(new Annotation(sp, ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(sp, + sp.addOffsetTo(cb.getFrameSize()), + anno)); + } + + // Add interpreter frame annotations + if (curFrame.isInterpretedFrame()) { +- annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameExpressionStack(), ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.addressOfInterpreterFrameExpressionStack(), + curFrame.addressOfInterpreterFrameTOS(), + "Interpreter expression stack")); + Address monBegin = curFrame.interpreterFrameMonitorBegin().address(); +@@ -1032,7 +1033,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { + if (interpreterFrameMethod != null) { + // The offset is just to get the right stack slots highlighted in the output + int offset = 1; +- annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameLocal(offset), ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.addressOfInterpreterFrameLocal(offset), + curFrame.addressOfInterpreterFrameLocal((int) interpreterFrameMethod.getMaxLocals() + offset), + "Interpreter locals area for frame with SP = " + curFrame.getSP())); + } +@@ -1041,9 +1042,9 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { + methodAnno += " (BAD OOP)"; + } + Address a = curFrame.addressOfInterpreterFrameMethod(); +- annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), methodAnno)); ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(a, a.addOffsetTo(addressSize), methodAnno)); + a = curFrame.addressOfInterpreterFrameCPCache(); +- annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache")); ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache")); + } + + RegisterMap rm = (RegisterMap) vf.getRegisterMap().clone(); +@@ -1160,7 +1161,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { + } + } + +- annoPanel.addAnnotation(new Annotation(addr, addr.addOffsetTo(addressSize), anno)); ++ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(addr, addr.addOffsetTo(addressSize), anno)); + } + }, rm); + } catch (Exception e) { +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java +index b884058a3..1adabf833 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java +@@ -130,6 +130,10 @@ public class SALauncher { + System.out.println(" --histo To print histogram of java object heap."); + System.out.println(" --clstats To print class loader statistics."); + System.out.println(" --finalizerinfo To print information on objects awaiting finalization."); ++ System.out.println(" --HeapDumpRedact redact the heapdump information to remove sensitive data."); ++ System.out.println(" --RedactMap Redact the class and field names to other strings."); ++ System.out.println(" --RedactMapFile file path of the redact map."); ++ System.err.println(" --RedactClassPath full path of the redact annotation"); + return commonHelpWithConnect("jmap"); + } + +@@ -302,8 +306,8 @@ public class SALauncher { + jstack.runWithArgs(buildAttachArgs(newArgMap, false)); + } + +- private static void runJMAP(String[] oldArgs) { +- Map longOptsMap = Map.ofEntries( ++ private static Map getLongOptsMap() { ++ return Map.ofEntries( + Map.entry("exe=", "exe"), + Map.entry("core=", "core"), + Map.entry("pid=", "pid"), +@@ -314,13 +318,27 @@ public class SALauncher { + Map.entry("gz=", "gz"), + Map.entry("histo", "-histo"), + Map.entry("clstats", "-clstats"), +- Map.entry("finalizerinfo", "-finalizerinfo")); ++ Map.entry("finalizerinfo", "-finalizerinfo"), ++ Map.entry("HeapDumpRedact=", "HeapDumpRedact"), ++ Map.entry("RedactMap=", "RedactMap"), ++ Map.entry("RedactMapFile=", "RedactMapFile"), ++ Map.entry("RedactClassPath=", "RedactClassPath"), ++ Map.entry("RedactPassword", "RedactPassword")); ++ } ++ ++ private static void runJMAP(String[] oldArgs) { ++ Map longOptsMap = getLongOptsMap(); + Map newArgMap = parseOptions(oldArgs, longOptsMap); + + boolean requestHeapdump = newArgMap.containsKey("binaryheap"); + String dumpfile = newArgMap.get("dumpfile"); + String gzLevel = newArgMap.get("gz"); + String command = "-heap:format=b"; ++ String heapDumpRedact = newArgMap.get("HeapDumpRedact"); ++ String redactMap = newArgMap.get("RedactMap"); ++ String redactMapFile = newArgMap.get("RedactMapFile"); ++ String redactClassPath = newArgMap.get("RedactClassPath"); ++ boolean hasRedactPassword = newArgMap.containsKey("RedactPassword"); + if (!requestHeapdump && (dumpfile != null)) { + throw new IllegalArgumentException("Unexpected argument: dumpfile"); + } +@@ -331,15 +349,37 @@ public class SALauncher { + if (dumpfile != null) { + command += ",file=" + dumpfile; + } ++ if (heapDumpRedact != null) { ++ command += ",HeapDumpRedact=" + heapDumpRedact; ++ } ++ if (redactMap != null) { ++ command += ",RedactMap=" + redactMap; ++ } ++ if (redactMapFile != null) { ++ command += ",RedactMapFile=" + redactMapFile; ++ } ++ if (redactClassPath != null) { ++ command += ",RedactClassPath=" + redactClassPath; ++ } ++ if(hasRedactPassword) { ++ command += ",RedactPassword"; ++ } + newArgMap.put(command, null); + } + + newArgMap.remove("binaryheap"); + newArgMap.remove("dumpfile"); + newArgMap.remove("gz"); ++ newArgMap.remove("HeapDumpRedact"); ++ newArgMap.remove("RedactMap"); ++ newArgMap.remove("RedactMapFile"); ++ newArgMap.remove("RedactClassPath"); ++ newArgMap.remove("RedactPassword"); + JMap.main(buildAttachArgs(newArgMap, false)); + } + ++ ++ + private static void runJINFO(String[] oldArgs) { + Map longOptsMap = Map.of("exe=", "exe", + "core=", "core", +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java +new file mode 100644 +index 000000000..617e8952b +--- /dev/null ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java +@@ -0,0 +1,70 @@ ++/* ++ * Copyright (c) 2000, 2020, 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. ++ * ++ */ ++ ++package sun.jvm.hotspot.oops; ++ ++import sun.jvm.hotspot.debugger.Address; ++import sun.jvm.hotspot.runtime.VM; ++import sun.jvm.hotspot.runtime.VMObject; ++import sun.jvm.hotspot.types.AddressField; ++import sun.jvm.hotspot.types.Type; ++import sun.jvm.hotspot.types.TypeDataBase; ++import sun.jvm.hotspot.types.WrongTypeException; ++import sun.jvm.hotspot.utilities.AnnotationArray2D; ++import sun.jvm.hotspot.utilities.Observable; ++import sun.jvm.hotspot.utilities.Observer; ++ ++// An Annotation is an oop containing class annotations ++ ++public class Annotation extends VMObject { ++ private static AddressField class_annotations; ++ private static AddressField class_type_annotations; ++ private static AddressField fields_annotations; ++ private static AddressField fields_type_annotations; ++ ++ static { ++ VM.registerVMInitializedObserver(new Observer() { ++ public void update(Observable o, Object data) { ++ initialize(VM.getVM().getTypeDataBase()); ++ } ++ }); ++ } ++ ++ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { ++ Type type = db.lookupType("Annotations"); ++ class_annotations = type.getAddressField("_class_annotations"); ++ class_type_annotations = type.getAddressField("_class_type_annotations"); ++ fields_annotations = type.getAddressField("_fields_annotations"); ++ fields_type_annotations = type.getAddressField("_fields_type_annotations"); ++ } ++ ++ public Annotation(Address addr) { ++ super(addr); ++ } ++ ++ public AnnotationArray2D getFieldsAnnotations() { ++ Address addr = getAddress().getAddressAt(fields_annotations.getOffset()); ++ return new AnnotationArray2D(addr); ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java +index ebf571c7b..98cb416c9 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java +@@ -131,6 +131,8 @@ public class Field { + private Symbol genericSignature; + private AccessFlags accessFlags; + private int fieldIndex; ++ // java field redact annotation ++ private U1Array fieldAnnotations; + + /** Returns the byte offset of the field within the object or klass */ + public long getOffset() { return offset; } +@@ -182,6 +184,14 @@ public class Field { + public boolean hasInitialValue() { return holder.getFieldInitialValueIndex(fieldIndex) != 0; } + public int getInitialValueIndex() { return values.initialValueIndex; } + ++ public void setFieldAnnotations(U1Array fieldAnnotations){ ++ this.fieldAnnotations = fieldAnnotations; ++ } ++ ++ public U1Array getFieldAnnotations(){ ++ return fieldAnnotations; ++ } ++ + // + // Following accessors are for named, non-VM fields only + // +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +index cec603be2..719aa8435 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +@@ -75,6 +75,7 @@ public class InstanceKlass extends Klass { + constants = new MetadataField(type.getAddressField("_constants"), 0); + sourceDebugExtension = type.getAddressField("_source_debug_extension"); + innerClasses = type.getAddressField("_inner_classes"); ++ annotate = type.getAddressField("_annotations"); + nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0); + staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0); + staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0); +@@ -145,6 +146,7 @@ public class InstanceKlass extends Klass { + private static CIntField initState; + private static CIntField itableLen; + private static AddressField breakpoints; ++ private static AddressField annotate; + + // type safe enum for ClassState from instanceKlass.hpp + public static class ClassState { +@@ -854,6 +856,10 @@ public class InstanceKlass extends Klass { + return VMObjectFactory.newObject(U2Array.class, addr); + } + ++ public Annotation getAnnotation() { ++ Address addr = getAddress().getAddressAt(annotate.getOffset()); ++ return VMObjectFactory.newObject(Annotation.class, addr); ++ } + + //---------------------------------------------------------------------- + // Internals only below this point +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java +index 4c80ecd6c..fbead3ce4 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java +@@ -25,6 +25,9 @@ + package sun.jvm.hotspot.tools; + + import java.io.*; ++import java.nio.CharBuffer; ++import java.util.regex.Pattern; ++ + import sun.jvm.hotspot.debugger.JVMDebugger; + import sun.jvm.hotspot.utilities.*; + +@@ -78,6 +81,7 @@ public class JMap extends Tool { + + private static String dumpfile = "heap.bin"; + private static int gzLevel = 0; ++ private static HeapRedactor heapRedactor; + + public void run() { + Tool tool = null; +@@ -123,6 +127,7 @@ public class JMap extends Tool { + + public static void main(String[] args) { + int mode = MODE_PMAP; ++ HeapRedactor.RedactParams redactParams = new HeapRedactor.RedactParams(); + if (args.length > 1 ) { + String modeFlag = args[0]; + boolean copyArgs = true; +@@ -177,6 +182,19 @@ public class JMap extends Tool { + System.err.println("compression level out of range (1-9): " + level); + System.exit(1); + } ++ } else if (keyValue[0].equals("HeapDumpRedact")) { ++ if (!redactParams.setAndCheckHeapDumpRedact(keyValue[1])) { ++ System.exit(1); ++ } ++ } else if (keyValue[0].equals("RedactMap")) { ++ redactParams.setRedactMap(keyValue[1]); ++ } else if (keyValue[0].equals("RedactMapFile")) { ++ redactParams.setRedactMapFile(keyValue[1]); ++ } else if (keyValue[0].equals("RedactClassPath")) { ++ redactParams.setRedactClassPath(keyValue[1]); ++ } else if (keyValue[0].equals("RedactPassword")) { ++ redactParams.setRedactPassword(getRedactPassword()); ++ + } else { + System.err.println("unknown option:" + keyValue[0]); + +@@ -189,12 +207,24 @@ public class JMap extends Tool { + } + } + ++ if (redactParams.getHeapDumpRedact() == null) { ++ if (redactParams.getRedactMap() == null && redactParams.getRedactMapFile() == null ++ && redactParams.getRedactClassPath() == null) { ++ redactParams.setEnableRedact(false); ++ } else { ++ System.err.println("Error: HeapDumpRedact must be specified to enable heap-dump-redacting"); ++ copyArgs = false; ++ System.exit(1); ++ } ++ } ++ + if (copyArgs) { + String[] newArgs = new String[args.length - 1]; + for (int i = 0; i < newArgs.length; i++) { + newArgs[i] = args[i + 1]; + } + args = newArgs; ++ heapRedactor = new HeapRedactor(redactParams); + } + } + +@@ -202,9 +232,39 @@ public class JMap extends Tool { + jmap.execute(args); + } + ++ private static CharBuffer getRedactPassword() { ++ CharBuffer redactPassword = CharBuffer.wrap(""); ++ // heap dump may need a password ++ Console console = System.console(); ++ char[] passwords = null; ++ if (console == null) { ++ return redactPassword; ++ } ++ ++ try { ++ passwords = console.readPassword("redact authority password:"); ++ } catch (Exception e) { ++ } ++ if(passwords == null) { ++ return redactPassword; ++ } ++ ++ try { ++ CharBuffer cb = CharBuffer.wrap(passwords); ++ String passwordPattern = "^[0-9a-zA-Z!@#$]{1,9}$"; ++ if(!Pattern.matches(passwordPattern, cb)) { ++ return redactPassword; ++ } ++ redactPassword = cb; ++ } catch (Exception e) { ++ } ++ ++ return redactPassword; ++ } ++ + public boolean writeHeapHprofBin(String fileName, int gzLevel) { + try { +- HeapGraphWriter hgw; ++ HeapHprofBinWriter hgw; + if (gzLevel == 0) { + hgw = new HeapHprofBinWriter(); + } else if (gzLevel >=1 && gzLevel <= 9) { +@@ -213,6 +273,7 @@ public class JMap extends Tool { + System.err.println("Illegal compression level: " + gzLevel); + return false; + } ++ hgw.setHeapRedactor(heapRedactor); + hgw.write(fileName); + System.out.println("heap written to " + fileName); + return true; +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java +new file mode 100644 +index 000000000..fa2b06776 +--- /dev/null ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei in the LICENSE file that accompanied this code. ++ * ++ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++package sun.jvm.hotspot.utilities; ++ ++import sun.jvm.hotspot.debugger.Address; ++import sun.jvm.hotspot.runtime.VM; ++import sun.jvm.hotspot.types.Type; ++import sun.jvm.hotspot.types.TypeDataBase; ++import sun.jvm.hotspot.types.WrongTypeException; ++ ++public class AnnotationArray2D extends GenericArray { ++ static { ++ VM.registerVMInitializedObserver(new Observer() { ++ public void update(Observable o, Object data) { ++ initialize(VM.getVM().getTypeDataBase()); ++ } ++ }); ++ } ++ ++ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { ++ elemType = db.lookupType("Array*"); ++ ++ Type type = db.lookupType("Array*>"); ++ dataFieldOffset = type.getAddressField("_data").getOffset(); ++ } ++ ++ private static long dataFieldOffset; ++ protected static Type elemType; ++ ++ public AnnotationArray2D(Address addr) { ++ super(addr, dataFieldOffset); ++ } ++ ++ public U1Array getAt(int i) { ++ return new U1Array(getAddressAt(i)); ++ } ++ public Type getElemType() { ++ return elemType; ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +index c9ffca89e..8501f4d93 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +@@ -28,6 +28,10 @@ import java.io.*; + import java.nio.ByteBuffer; + import java.nio.ByteOrder; + import java.nio.channels.*; ++import java.nio.CharBuffer; ++import java.security.NoSuchAlgorithmException; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.KeySpec; + import java.util.*; + import java.util.zip.*; + import sun.jvm.hotspot.debugger.*; +@@ -36,6 +40,10 @@ import sun.jvm.hotspot.oops.*; + import sun.jvm.hotspot.runtime.*; + import sun.jvm.hotspot.classfile.*; + ++import javax.crypto.SecretKey; ++import javax.crypto.SecretKeyFactory; ++import javax.crypto.spec.PBEKeySpec; ++ + import static java.nio.charset.StandardCharsets.UTF_8; + + /* +@@ -387,6 +395,71 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + private static final long MAX_U4_VALUE = 0xFFFFFFFFL; + int serialNum = 1; + ++ // encrypt ++ private static int SALT_MIN_LENGTH = 8; ++ private static int HASH_BIT_SIZE = 256; ++ private static int HASH_ITERATIONS_COUNT = 10000; ++ ++ // Heap Redact ++ private HeapRedactor heapRedactor; ++ ++ public HeapRedactor getHeapRedactor() { ++ return heapRedactor; ++ } ++ ++ public void setHeapRedactor(HeapRedactor heapRedactor) { ++ this.heapRedactor = heapRedactor; ++ } ++ ++ public HeapRedactor.HeapDumpRedactLevel getHeapDumpRedactLevel(){ ++ if(heapRedactor==null){ ++ return HeapRedactor.HeapDumpRedactLevel.REDACT_OFF; ++ } ++ return heapRedactor.getHeapDumpRedactLevel(); ++ } ++ ++ public Optional getHeapDumpRedactPassword() { ++ return heapRedactor == null ? Optional.empty() : Optional.ofNullable(heapRedactor.getRedactPassword()); ++ } ++ ++ private Optional lookupRedactName(String name){ ++ return heapRedactor == null ? Optional.empty() : heapRedactor.lookupRedactName(name); ++ } ++ ++ private void resetRedactParams(){ ++ Optional redactOption = getVMRedactParameter("HeapDumpRedact"); ++ String redactStr= redactOption.isPresent() ? redactOption.get() : null; ++ if(redactStr!=null && !redactStr.isEmpty()){ ++ HeapRedactor.RedactParams redactParams = new HeapRedactor.RedactParams(); ++ if(HeapRedactor.REDACT_ANNOTATION_OPTION.equals(redactStr)){ ++ Optional classPathOption = getVMRedactParameter("RedactClassPath"); ++ String classPathStr = classPathOption.isPresent() ? classPathOption.get() : null; ++ redactStr = classPathOption.isPresent() ? redactStr : HeapRedactor.REDACT_OFF_OPTION; ++ redactParams.setRedactClassPath(classPathStr); ++ } else { ++ Optional redactMapOption = getVMRedactParameter("RedactMap"); ++ String redactMapStr = redactMapOption.isPresent() ? redactMapOption.get() : null; ++ redactParams.setRedactMap(redactMapStr); ++ Optional redactMapFileOption = getVMRedactParameter("RedactMapFile"); ++ String redactMapFileStr = redactMapFileOption.isPresent() ? redactMapFileOption.get() : null; ++ redactParams.setRedactMapFile(redactMapFileStr); ++ } ++ if(!redactParams.setAndCheckHeapDumpRedact(redactStr)){ ++ redactParams.setAndCheckHeapDumpRedact(HeapRedactor.REDACT_OFF_OPTION); ++ } ++ setHeapRedactor(new HeapRedactor(redactParams)); ++ } ++ } ++ ++ private Optional getVMRedactParameter(String name) { ++ VM vm = VM.getVM(); ++ VM.Flag flag = vm.getCommandLineFlag(name); ++ if(flag == null){ ++ return Optional.empty(); ++ } ++ return Optional.ofNullable(flag.getCcstr()); ++ } ++ + public HeapHprofBinWriter() { + this.KlassMap = new ArrayList(); + this.names = new HashSet(); +@@ -399,9 +472,69 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + this.gzLevel = gzLevel; + } + ++ private boolean checkPassword() { ++ Optional redactAuthOption = getVMRedactParameter("RedactPassword"); ++ String redactAuth = redactAuthOption.isPresent() ? redactAuthOption.get() : null; ++ boolean redactAuthFlag = true; ++ if(redactAuth != null) { ++ String[] auths = redactAuth.split(","); ++ if(auths.length != 2) { ++ return redactAuthFlag; ++ } ++ ++ Optional passwordOption = getHeapDumpRedactPassword(); ++ CharBuffer password = passwordOption.isPresent() ? passwordOption.get() : CharBuffer.wrap(""); ++ char[] passwordChars = null; ++ try { ++ passwordChars = password.array(); ++ ++ byte[] saltBytes = auths[1].getBytes("UTF-8"); ++ if(saltBytes.length < SALT_MIN_LENGTH) { ++ return redactAuthFlag; ++ } ++ ++ String digestStr = getEncryptValue(passwordChars, saltBytes); ++ redactAuthFlag = auths[0].equals(digestStr); ++ } catch (Exception e) { ++ // ignore ++ redactAuthFlag = false; ++ } finally { ++ // clear all password ++ if(passwordChars != null) { ++ Arrays.fill(passwordChars, '0'); ++ } ++ } ++ } ++ ++ return redactAuthFlag; ++ } ++ ++ private String getEncryptValue(char[] passwordValue, byte[] saltBytes) throws InvalidKeySpecException, NoSuchAlgorithmException { ++ StringBuilder digestStrBuilder = new StringBuilder(); ++ ++ KeySpec spec = new PBEKeySpec(passwordValue, saltBytes, HASH_ITERATIONS_COUNT, HASH_BIT_SIZE); ++ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); ++ SecretKey secretKey = secretKeyFactory.generateSecret(spec); ++ byte[] digestBytes = secretKey.getEncoded(); ++ for (byte b : digestBytes) { ++ String hex = Integer.toHexString(0xff & b); ++ if (hex.length() == 1) { ++ digestStrBuilder.append('0'); ++ } ++ digestStrBuilder.append(hex); ++ } ++ String digestStr = digestStrBuilder.toString(); ++ ++ return digestStr; ++ } ++ + public synchronized void write(String fileName) throws IOException { + VM vm = VM.getVM(); + ++ if(getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_UNKNOWN || !checkPassword()) { ++ resetRedactParams(); ++ } ++ + // Check whether we should dump the heap as segments + useSegmentedHeapDump = isCompression() || + (vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD); +@@ -465,6 +598,9 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + // this will write heap data into the buffer stream + super.write(); + ++ // write redacted String Field record ++ writeAnnotateFieldValue(); ++ + // flush buffer stream. + out.flush(); + if (!useSegmentedHeapDump) { +@@ -725,6 +861,68 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + } + } + ++ private void writeAnnotateFieldValue() throws IOException { ++ HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel(); ++ if(level != HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION ++ && level != HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES) { ++ return; ++ } ++ ++ HeapRedactor.RedactVectorNode redactVector = heapRedactor.getHeaderNode(); ++ if(redactVector == null) { ++ return; ++ } ++ ++ while(redactVector != null) { ++ List typeArrayList = redactVector.getTypeArrayList(); ++ for(int i = 0; i < redactVector.getCurrentIndex(); i++) { ++ TypeArray array = typeArrayList.get(i); ++ TypeArrayKlass tak = (TypeArrayKlass) array.getKlass(); ++ final int type = (int) tak.getElementType(); ++ ++ if(type != TypeArrayKlass.T_BYTE) { ++ continue; ++ } ++ ++ OopHandle handle = (array != null)? array.getHandle() : null; ++ long address = getAddressValue(handle); ++ Optional annotateValueOptional = heapRedactor.lookupRedactAnnotationValue(address); ++ String annotateValue = annotateValueOptional.isPresent() ? annotateValueOptional.get() : null; ++ long expectLength = array.getLength(); ++ if(annotateValue != null) { ++ expectLength = annotateValue.length(); ++ } ++ ++ int headerSize = getArrayHeaderSize(false); ++ final String typeName = tak.getElementTypeName(); ++ final long typeSize = getSizeForType(type); ++ final int length = calculateArrayMaxLength(expectLength, ++ headerSize, ++ typeSize, ++ typeName); ++ out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP); ++ writeObjectID(array); ++ out.writeInt(DUMMY_STACK_TRACE_ID); ++ out.writeInt(length); ++ out.writeByte((byte) type); ++ ++ if (annotateValue != null) { ++ for(int index = 0; index < expectLength; index++) { ++ out.writeByte(annotateValue.charAt(index)); ++ } ++ } else { ++ for (int index = 0; index < length; index++) { ++ long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE; ++ out.writeByte(array.getHandle().getJByteAt(offset)); ++ } ++ } ++ } ++ ++ HeapRedactor.RedactVectorNode tempVector = redactVector.getNext(); ++ redactVector = tempVector; ++ } ++ } ++ + protected void writeClass(Instance instance) throws IOException { + Klass reflectedKlass = java_lang_Class.asKlass(instance); + // dump instance record only for primitive type Class objects. +@@ -958,9 +1156,18 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + } + + protected void writePrimitiveArray(TypeArray array) throws IOException { ++ HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel(); ++ + int headerSize = getArrayHeaderSize(false); + TypeArrayKlass tak = (TypeArrayKlass) array.getKlass(); + final int type = tak.getElementType(); ++ ++ if(type == TypeArrayKlass.T_BYTE && (level == HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION ++ || level == HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES)) { ++ heapRedactor.recordTypeArray(array); ++ return; ++ } ++ + final String typeName = tak.getElementTypeName(); + final long typeSize = getSizeForType(type); + final int length = calculateArrayMaxLength(array.getLength(), +@@ -972,12 +1179,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + out.writeInt(DUMMY_STACK_TRACE_ID); + out.writeInt(length); + out.writeByte((byte) type); ++ ++ boolean shouldRedact = ( level == HeapRedactor.HeapDumpRedactLevel.REDACT_BASIC ++ || level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL); ++ + switch (type) { + case TypeArrayKlass.T_BOOLEAN: + writeBooleanArray(array, length); + break; + case TypeArrayKlass.T_CHAR: +- writeCharArray(array, length); ++ writeCharArray(array, length, shouldRedact); + break; + case TypeArrayKlass.T_FLOAT: + writeFloatArray(array, length); +@@ -986,13 +1197,13 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + writeDoubleArray(array, length); + break; + case TypeArrayKlass.T_BYTE: +- writeByteArray(array, length); ++ writeByteArray(array, length, shouldRedact); + break; + case TypeArrayKlass.T_SHORT: + writeShortArray(array, length); + break; + case TypeArrayKlass.T_INT: +- writeIntArray(array, length); ++ writeIntArray(array, length, shouldRedact); + break; + case TypeArrayKlass.T_LONG: + writeLongArray(array, length); +@@ -1010,10 +1221,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + } + } + +- private void writeByteArray(TypeArray array, int length) throws IOException { +- for (int index = 0; index < length; index++) { +- long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE; +- out.writeByte(array.getHandle().getJByteAt(offset)); ++ private void writeByteArray(TypeArray array, int length, boolean shouldRedact) throws IOException { ++ if (shouldRedact) { ++ for(int index = 0; index < length; index++) { ++ out.writeByte(0); ++ } ++ } else { ++ for (int index = 0; index < length; index++) { ++ long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE; ++ out.writeByte(array.getHandle().getJByteAt(offset)); ++ } + } + } + +@@ -1024,10 +1241,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + } + } + +- private void writeIntArray(TypeArray array, int length) throws IOException { +- for (int index = 0; index < length; index++) { +- long offset = INT_BASE_OFFSET + index * INT_SIZE; +- out.writeInt(array.getHandle().getJIntAt(offset)); ++ private void writeIntArray(TypeArray array, int length, boolean shouldRedact) throws IOException { ++ if (shouldRedact) { ++ for(int index = 0; index < length; index++) { ++ out.writeInt(0); ++ } ++ } else { ++ for (int index = 0; index < length; index++) { ++ long offset = INT_BASE_OFFSET + index * INT_SIZE; ++ out.writeInt(array.getHandle().getJIntAt(offset)); ++ } + } + } + +@@ -1038,10 +1261,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + } + } + +- private void writeCharArray(TypeArray array, int length) throws IOException { +- for (int index = 0; index < length; index++) { +- long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE; +- out.writeChar(array.getHandle().getJCharAt(offset)); ++ private void writeCharArray(TypeArray array, int length, boolean shouldRedact) throws IOException { ++ if (shouldRedact) { ++ for(int index = 0; index < length; index++) { ++ out.writeChar(0); ++ } ++ } else { ++ for (int index = 0; index < length; index++) { ++ long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE; ++ out.writeChar(array.getHandle().getJCharAt(offset)); ++ } + } + } + +@@ -1083,6 +1312,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + for (Iterator itr = fields.iterator(); itr.hasNext();) { + writeField(itr.next(), instance); + } ++ ++ // record the anonymous value for every field ++ if(klass instanceof InstanceKlass && heapRedactor != null) { ++ if(heapRedactor.getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION ++ && heapRedactor.getRedactAnnotationClassPath() != null && !heapRedactor.getRedactAnnotationClassPath().isEmpty()) { ++ recordAnnotationValueMap(fields, instance); ++ } else if( heapRedactor.getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES) { ++ recordDiyRulesValueMap(fields, instance); ++ } ++ } + } + + //-- Internals only below this point +@@ -1105,6 +1344,131 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + } + } + ++ private void recordAnnotationValueMap(List fields, Instance instance) { ++ Klass klass = instance.getKlass(); ++ boolean inJavaPackage = false; ++ Symbol classNameSymbol = klass.getName(); ++ if(classNameSymbol != null) { ++ String className = classNameSymbol.asString(); ++ inJavaPackage = (className != null && className.startsWith("java/")); ++ } ++ if(inJavaPackage){ ++ return; ++ } ++ for (Field field : fields) { ++ Symbol fieldSignature = field.getSignature(); ++ if(fieldSignature == null || fieldSignature.asString() == null ++ || !"Ljava/lang/String;".equals(fieldSignature.asString())) { ++ continue; ++ } ++ try { ++ InstanceKlass fieldHolder = field.getFieldHolder(); ++ U1Array fieldAnnotations = field.getFieldAnnotations(); ++ Optional anonymousValueOption = getAnonymousValue(fieldAnnotations, fieldHolder.getConstants()); ++ if(!anonymousValueOption.isPresent()) { ++ continue; ++ } ++ long address = getStringFieldAddress(field, instance); ++ if(address > 0L) { ++ heapRedactor.recordRedactAnnotationValue(address, anonymousValueOption.get()); ++ } ++ } catch (Exception e) { ++ } ++ } ++ } ++ ++ private Optional getAnonymousValue(U1Array fieldAnnotations, ConstantPool cp) { ++ Optional anonymousValueOption = Optional.empty(); ++ if (fieldAnnotations.getAddress() == null) { ++ return anonymousValueOption; ++ } ++ ++ int fieldAnnotationsTagsLen = fieldAnnotations.length(); ++ boolean isAnonymousAnnotation = false; ++ int annotationStart = 0; ++ int annotationEnd = 0; ++ for (int j = 0; j < fieldAnnotationsTagsLen; j++) { ++ int cpIndex = fieldAnnotations.at(j); ++ if (cpIndex >= cp.getLength() || cpIndex < 0) { ++ continue; ++ } ++ byte cpConstType = cp.getTags().at(cpIndex); ++ if (cpConstType == ConstantPool.JVM_CONSTANT_Utf8) { ++ annotationStart += (isAnonymousAnnotation ? 0 : 1); ++ annotationEnd++; ++ Symbol symbol = cp.getSymbolAt(cpIndex); ++ if (symbol.asString() == null || symbol.asString().isEmpty()) { ++ continue; ++ } ++ if (symbol.asString().equals("L" + heapRedactor.getRedactAnnotationClassPath() + ";")) { ++ isAnonymousAnnotation = true; ++ } ++ if(annotationEnd - annotationStart == 1 && !"value".equals(symbol.asString())) { ++ break; ++ } ++ if(annotationEnd - annotationStart == 2) { ++ anonymousValueOption = Optional.ofNullable(cp.getSymbolAt(cpIndex).asString()); ++ break; ++ } ++ } ++ } ++ return anonymousValueOption; ++ } ++ ++ private void recordDiyRulesValueMap(List fields, Instance instance) { ++ Klass klass = instance.getKlass(); ++ boolean diyRulesFlag = false; ++ Symbol classNameSymbol = klass.getName(); ++ Map redactRulesMap = null; ++ if(classNameSymbol != null) { ++ String className = classNameSymbol.asString(); ++ Optional> redactRulesMapOptional = className == null ? Optional.empty() : heapRedactor.getRedactRulesTable(className); ++ redactRulesMap = redactRulesMapOptional.isPresent() ? redactRulesMapOptional.get() : null; ++ diyRulesFlag = (redactRulesMap != null); ++ } ++ if(!diyRulesFlag){ ++ return; ++ } ++ for (Field field : fields) { ++ Symbol fieldSignature = field.getSignature(); ++ if(fieldSignature == null || fieldSignature.asString() == null || !"Ljava/lang/String;".equals(fieldSignature.asString())) { ++ continue; ++ } ++ ++ try { ++ Symbol filedNameSymbol = field.getName(); ++ if(filedNameSymbol == null) { ++ continue; ++ } ++ ++ String filedName = filedNameSymbol.asString(); ++ String replaceValue = filedName == null ? null : redactRulesMap.get(filedName); ++ long address = getStringFieldAddress(field, instance); ++ if(address > 0L && replaceValue != null) { ++ heapRedactor.recordRedactAnnotationValue(address, replaceValue); ++ } ++ } catch (Exception e) { ++ } ++ } ++ } ++ ++ private long getStringFieldAddress(Field field, Instance instance) { ++ long address = 0L; ++ if(field instanceof OopField) { ++ Oop fieldOop = ((OopField) field).getValue(instance); ++ Field stringField = null; ++ if (fieldOop != null && fieldOop.getKlass() instanceof InstanceKlass) { ++ List oopFiledSubs = ((InstanceKlass) fieldOop.getKlass()).getAllFields(); ++ stringField = oopFiledSubs.iterator().next(); ++ } ++ if (stringField != null && stringField instanceof OopField) { ++ OopHandle handle = ((OopField) stringField).getValueAsOopHandle(fieldOop); ++ address = getAddressValue(handle); ++ } ++ } ++ return address; ++ } ++ + public static int signatureToHprofKind(char ch) { + switch (ch) { + case JVM_SIGNATURE_CLASS: +@@ -1221,7 +1585,18 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + // If name is already written don't write it again. + if (names.add(sym)) { + if(sym != null) { +- byte[] buf = sym.asString().getBytes(UTF_8); ++ String symbolStr = sym.asString(); ++ HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel(); ++ boolean shouldRedact = (level == HeapRedactor.HeapDumpRedactLevel.REDACT_NAMES || ++ level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL); ++ byte[] buf = null; ++ if(shouldRedact) { ++ Optional redactField = lookupRedactName(symbolStr); ++ buf = redactField.isPresent() ? redactField.get().getBytes("UTF-8") : null; ++ } ++ if(buf == null) { ++ buf = symbolStr.getBytes(UTF_8); ++ } + writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE); + writeSymbolID(sym); + out.write(buf); +@@ -1301,11 +1676,23 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + List res = new ArrayList<>(); + while (klass != null) { + List curFields = klass.getImmediateFields(); ++ Annotation annotation = klass.getAnnotation(); ++ AnnotationArray2D fieldsAnnotations = (annotation == null) ? null : annotation.getFieldsAnnotations(); ++ boolean hasAnnotations = false; ++ if(fieldsAnnotations != null && fieldsAnnotations.getAddress() != null) { ++ hasAnnotations = true; ++ } ++ int fieldIndex = 0; + for (Iterator itr = curFields.iterator(); itr.hasNext();) { + Field f = itr.next(); + if (! f.isStatic()) { + res.add(f); ++ // record annotation for class Field ++ if(hasAnnotations) { ++ f.setFieldAnnotations(fieldsAnnotations.getAt(fieldIndex)); ++ } + } ++ fieldIndex++; + } + klass = (InstanceKlass) klass.getSuper(); + } +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java +new file mode 100644 +index 000000000..5c442b2bb +--- /dev/null ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java +@@ -0,0 +1,454 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei in the LICENSE file that accompanied this code. ++ * ++ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++package sun.jvm.hotspot.utilities; ++ ++import sun.jvm.hotspot.oops.TypeArray; ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.nio.CharBuffer; ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.Locale; ++import java.util.Optional; ++ ++public class HeapRedactor { ++ public enum HeapDumpRedactLevel { ++ REDACT_UNKNOWN, ++ REDACT_OFF, ++ REDACT_NAMES, ++ REDACT_BASIC, ++ REDACT_DIYRULES, ++ REDACT_ANNOTATION, ++ REDACT_FULL ++ } ++ ++ private HeapDumpRedactLevel redactLevel; ++ private Map redactNameTable; ++ private Map> redactClassTable; ++ private String redactClassFullName = null; ++ private Map redactValueTable; ++ private RedactVectorNode headerNode; ++ private RedactVectorNode currentNode; ++ ++ private RedactParams redactParams; ++ ++ public static final String HEAP_DUMP_REDACT_PREFIX = "HeapDumpRedact="; ++ public static final String REDACT_MAP_PREFIX = "RedactMap="; ++ public static final String REDACT_MAP_FILE_PREFIX = "RedactMapFile="; ++ public static final String REDACT_CLASS_PATH_PREFIX = "RedactClassPath="; ++ public static final String REDACT_PASSWORD_PREFIX = "RedactPassword="; ++ ++ public static final String REDACT_UNKNOWN_STR = "UNKNOWN"; ++ public static final String REDACT_OFF_STR = "OFF"; ++ public static final String REDACT_NAME_STR = "NAMES"; ++ public static final String REDACT_BASIC_STR = "BASIC"; ++ public static final String REDACT_DIYRULES_STR = "DIYRULES"; ++ public static final String REDACT_ANNOTATION_STR = "ANNOTATION"; ++ public static final String REDACT_FULL_STR = "FULL"; ++ ++ public static final String REDACT_UNKNOWN_OPTION = REDACT_UNKNOWN_STR.toLowerCase(Locale.ROOT); ++ public static final String REDACT_OFF_OPTION = REDACT_OFF_STR.toLowerCase(Locale.ROOT); ++ public static final String REDACT_NAME_OPTION = REDACT_NAME_STR.toLowerCase(Locale.ROOT); ++ public static final String REDACT_BASIC_OPTION = REDACT_BASIC_STR.toLowerCase(Locale.ROOT); ++ public static final String REDACT_DIYRULES_OPTION = REDACT_DIYRULES_STR.toLowerCase(Locale.ROOT); ++ public static final String REDACT_ANNOTATION_OPTION = REDACT_ANNOTATION_STR.toLowerCase(Locale.ROOT); ++ public static final String REDACT_FULL_OPTION = REDACT_FULL_STR.toLowerCase(Locale.ROOT); ++ ++ public static final int PATH_MAX = 4096; ++ public static final int REDACT_VECTOR_SIZE = 1024; ++ ++ public HeapRedactor(RedactParams redactParams) { ++ this.redactParams = redactParams; ++ redactLevel = HeapDumpRedactLevel.REDACT_UNKNOWN; ++ redactNameTable = null; ++ redactClassTable = null; ++ redactValueTable = null; ++ init(null); ++ } ++ ++ private void init(String options) { ++ if (redactLevel == HeapDumpRedactLevel.REDACT_UNKNOWN) { ++ initHeapdumpRedactLevel(options); ++ } ++ } ++ ++ public HeapDumpRedactLevel getHeapDumpRedactLevel() { ++ return redactLevel; ++ } ++ ++ public String getRedactLevelString() { ++ switch (redactLevel) { ++ case REDACT_BASIC: ++ return REDACT_BASIC_STR; ++ case REDACT_NAMES: ++ return REDACT_NAME_STR; ++ case REDACT_FULL: ++ return REDACT_FULL_STR; ++ case REDACT_DIYRULES: ++ return REDACT_DIYRULES_STR; ++ case REDACT_ANNOTATION: ++ return REDACT_ANNOTATION_STR; ++ case REDACT_OFF: ++ return REDACT_OFF_STR; ++ case REDACT_UNKNOWN: ++ default: ++ return REDACT_UNKNOWN_STR; ++ } ++ } ++ ++ public Optional lookupRedactName(String name){ ++ return Optional.ofNullable(redactNameTable == null ? null : redactNameTable.get(name)); ++ } ++ ++ public void recordTypeArray(TypeArray oop) { ++ int tmp_index = currentNode.getCurrentIndex(); ++ if(tmp_index == REDACT_VECTOR_SIZE){ ++ RedactVectorNode newNode = new RedactVectorNode(); ++ List list = new ArrayList<>(REDACT_VECTOR_SIZE); ++ newNode.setTypeArrayList(list); ++ newNode.setNext(null); ++ newNode.setCurrentIndex(0); ++ tmp_index = 0; ++ currentNode.setNext(newNode); ++ currentNode = newNode; ++ } ++ currentNode.getTypeArrayList().add(tmp_index, oop); ++ tmp_index++; ++ currentNode.setCurrentIndex(tmp_index); ++ ++ } ++ ++ public RedactVectorNode getHeaderNode(){ ++ return headerNode; ++ } ++ ++ public void recordRedactAnnotationValue(Long addr, String value) { ++ redactValueTable.put(addr, value); ++ } ++ ++ public Optional lookupRedactAnnotationValue(Long addr){ ++ return Optional.ofNullable(redactValueTable == null ? null : redactValueTable.get(addr)); ++ } ++ ++ public String getRedactAnnotationClassPath(){ ++ return redactParams.getRedactClassPath(); ++ } ++ ++ public CharBuffer getRedactPassword(){ ++ return redactParams.getRedactPassword(); ++ } ++ ++ public Optional> getRedactRulesTable(String key) { ++ return Optional.ofNullable(redactClassTable == null ? null: redactClassTable.get(key)); ++ } ++ ++ private HeapDumpRedactLevel initHeapdumpRedactLevel(String options) { ++ RedactParams customizedParams = parseRedactOptions(options); ++ ++ if (customizedParams.isEnableRedact() || this.redactParams == null) { ++ this.redactParams = customizedParams; ++ } ++ ++ if (redactParams.heapDumpRedact == null) { ++ redactLevel = HeapDumpRedactLevel.REDACT_UNKNOWN; ++ } else { ++ if (REDACT_BASIC_OPTION.equals(redactParams.heapDumpRedact)) { ++ redactLevel = HeapDumpRedactLevel.REDACT_BASIC; ++ } else if (REDACT_NAME_OPTION.equals(redactParams.heapDumpRedact)) { ++ redactLevel = HeapDumpRedactLevel.REDACT_NAMES; ++ initRedactMap(); ++ } else if (REDACT_FULL_OPTION.equals(redactParams.heapDumpRedact)) { ++ redactLevel = HeapDumpRedactLevel.REDACT_FULL; ++ initRedactMap(); ++ } else if (REDACT_DIYRULES_OPTION.equals(redactParams.heapDumpRedact)) { ++ redactLevel = HeapDumpRedactLevel.REDACT_DIYRULES; ++ initRedactMap(); ++ initRedactVector(); ++ } else if (REDACT_ANNOTATION_OPTION.equals(redactParams.heapDumpRedact)) { ++ redactLevel = HeapDumpRedactLevel.REDACT_ANNOTATION; ++ initRedactVector(); ++ } else { ++ redactLevel = HeapDumpRedactLevel.REDACT_OFF; ++ } ++ } ++ return redactLevel; ++ } ++ ++ private void initRedactVector(){ ++ if(redactValueTable == null) { ++ redactValueTable = new HashMap<>(); ++ } ++ if(headerNode == null) { ++ headerNode = new RedactVectorNode(); ++ List list = new ArrayList<>(REDACT_VECTOR_SIZE); ++ headerNode.setTypeArrayList(list); ++ headerNode.setNext(null); ++ headerNode.setCurrentIndex(0); ++ currentNode = headerNode; ++ } ++ } ++ ++ private RedactParams parseRedactOptions(String optionStr) { ++ RedactParams params = new RedactParams(REDACT_OFF_OPTION, null, null, null, null); ++ if (optionStr != null) { ++ String[] options = optionStr.split(","); ++ for (String option : options) { ++ if (option.startsWith(HEAP_DUMP_REDACT_PREFIX)) { ++ params.setAndCheckHeapDumpRedact(option.substring(HEAP_DUMP_REDACT_PREFIX.length())); ++ } else if (option.startsWith(REDACT_MAP_PREFIX)) { ++ params.setRedactMap(option.substring(REDACT_MAP_PREFIX.length())); ++ } else if (option.startsWith(REDACT_MAP_FILE_PREFIX)) { ++ params.setRedactMapFile(option.substring(REDACT_MAP_FILE_PREFIX.length())); ++ } else if (option.startsWith(REDACT_CLASS_PATH_PREFIX)) { ++ params.setRedactClassPath(option.substring(REDACT_CLASS_PATH_PREFIX.length())); ++ } else { ++ continue; ++ } ++ } ++ } ++ return params; ++ } ++ ++ private void initRedactMap() { ++ if (redactParams.redactMapFile != null) { ++ readRedactMapFromFile(redactParams.redactMapFile); ++ } ++ if (redactParams.redactMap != null) { ++ parseRedactMapStringDependOnMode(redactParams.redactMap, redactLevel); ++ } ++ } ++ ++ private void readRedactMapFromFile(String path) { ++ if (path == null || path.isEmpty()) { ++ // RedactMapFile= not specified ++ return; ++ } else { ++ if (path.length() >= PATH_MAX) { ++ System.err.println("RedactMap File path is too long"); ++ return; ++ } ++ File file = new File(path); ++ if (!file.exists() || !file.isFile()) { ++ System.err.println("RedactMap File does not exist"); ++ } ++ try (BufferedReader reader = new BufferedReader(new FileReader(path))) { ++ String line; ++ while ((line = reader.readLine()) != null) { ++ parseRedactMapStringDependOnMode(line, redactLevel); ++ } ++ } catch (IOException e) { ++ System.err.println("Encounter an error when reading " + path + " , skip processing RedactMap File."); ++ e.printStackTrace(); ++ return; ++ } ++ } ++ } ++ ++ private void parseRedactMapStringDependOnMode(String nameMapList, HeapDumpRedactLevel redactLevel) { ++ if(redactLevel == HeapDumpRedactLevel.REDACT_DIYRULES) { ++ parseRedactDiyRulesString(nameMapList); ++ } else { ++ parseRedactMapString(nameMapList); ++ } ++ } ++ ++ private void parseRedactMapString(String nameMapList) { ++ if (redactNameTable == null) { ++ redactNameTable = new HashMap<>(); ++ } ++ String[] tokens = nameMapList.split("[,;\\s+]"); ++ for (String token : tokens) { ++ String[] pair = token.split(":"); ++ if (pair.length == 2) { ++ redactNameTable.put(pair[0], pair[1]); ++ } ++ } ++ } ++ ++ private void parseRedactDiyRulesString(String nameMapList) { ++ if (redactClassTable == null) { ++ redactClassTable = new HashMap<>(); ++ } ++ Map redactRulesTable = redactClassFullName == null ? null : redactClassTable.get(redactClassFullName); ++ String[] tokens = nameMapList.split("[,;\\s+]"); ++ for (String token : tokens) { ++ String[] pair = token.split(":"); ++ if (pair.length == 1) { ++ redactClassFullName = pair[0].replace(".", "/"); ++ redactRulesTable = redactClassTable.get(redactClassFullName); ++ if(redactRulesTable == null) { ++ redactRulesTable = new HashMap<>(); ++ redactClassTable.put(redactClassFullName, redactRulesTable); ++ } ++ } ++ if (pair.length == 2 && redactRulesTable != null) { ++ redactRulesTable.put(pair[0], pair[1]); ++ } ++ } ++ } ++ ++ public static class RedactParams { ++ private String heapDumpRedact; ++ private String redactMap; ++ private String redactMapFile; ++ private String redactClassPath; ++ private CharBuffer redactPassword; ++ private boolean enableRedact = false; ++ ++ public RedactParams() { ++ } ++ ++ public RedactParams(String heapDumpRedact, String redactMap, String redactMapFile, String redactClassPath, CharBuffer redactPassword) { ++ this.heapDumpRedact = heapDumpRedact; ++ this.redactMap = redactMap; ++ this.redactMapFile = redactMapFile; ++ this.redactClassPath = redactClassPath; ++ this.redactPassword = redactPassword; ++ } ++ ++ @Override ++ public String toString() { ++ StringBuilder builder = new StringBuilder(); ++ if (heapDumpRedact != null) { ++ builder.append(HEAP_DUMP_REDACT_PREFIX); ++ builder.append(heapDumpRedact); ++ builder.append(","); ++ } ++ if (redactMap != null) { ++ builder.append(REDACT_MAP_PREFIX); ++ builder.append(redactMap); ++ builder.append(","); ++ } ++ if (redactMapFile != null) { ++ builder.append(REDACT_MAP_FILE_PREFIX); ++ builder.append(redactMapFile); ++ builder.append(","); ++ } ++ if (redactClassPath != null) { ++ builder.append(REDACT_CLASS_PATH_PREFIX); ++ builder.append(redactClassPath); ++ } ++ return builder.toString(); ++ } ++ ++ public String getHeapDumpRedact() { ++ return heapDumpRedact; ++ } ++ ++ public boolean setAndCheckHeapDumpRedact(String heapDumpRedact) { ++ if (!checkLauncherHeapdumpRedactSupport(heapDumpRedact)) { ++ return false; ++ } ++ this.heapDumpRedact = heapDumpRedact; ++ this.enableRedact = true; ++ return true; ++ } ++ ++ public String getRedactMap() { ++ return redactMap; ++ } ++ ++ public void setRedactMap(String redactMap) { ++ this.redactMap = redactMap; ++ } ++ ++ public String getRedactMapFile() { ++ return redactMapFile; ++ } ++ ++ public void setRedactMapFile(String redactMapFile) { ++ this.redactMapFile = redactMapFile; ++ } ++ ++ public String getRedactClassPath() { ++ return redactClassPath; ++ } ++ ++ public void setRedactClassPath(String redactClassPath) { ++ this.redactClassPath = redactClassPath; ++ } ++ ++ public CharBuffer getRedactPassword() { ++ return redactPassword; ++ } ++ ++ public void setRedactPassword(CharBuffer redactPassword) { ++ this.redactPassword = redactPassword; ++ } ++ ++ public static boolean checkLauncherHeapdumpRedactSupport(String value) { ++ String[] validValues = {REDACT_BASIC_OPTION, REDACT_NAME_OPTION, REDACT_FULL_OPTION, REDACT_DIYRULES_OPTION, REDACT_ANNOTATION_OPTION, REDACT_OFF_OPTION}; ++ for (String validValue : validValues) { ++ if (validValue.equals(value)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ public boolean isEnableRedact() { ++ return enableRedact; ++ } ++ ++ public void setEnableRedact(boolean enableRedact) { ++ this.enableRedact = enableRedact; ++ } ++ } ++ ++ public class RedactVectorNode{ ++ private List typeArrayList; ++ private RedactVectorNode next; ++ private int currentIndex; ++ ++ public List getTypeArrayList() { ++ return typeArrayList; ++ } ++ ++ public void setTypeArrayList(List list) { ++ this.typeArrayList = list; ++ } ++ ++ public RedactVectorNode getNext() { ++ return next; ++ } ++ ++ public void setNext(RedactVectorNode next) { ++ this.next = next; ++ } ++ ++ public int getCurrentIndex() { ++ return currentIndex; ++ } ++ ++ public void setCurrentIndex(int index) { ++ this.currentIndex = index; ++ } ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +index 8939d6093..50757d2d7 100644 +--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java ++++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +@@ -25,16 +25,29 @@ + + package sun.tools.jmap; + ++import java.io.BufferedInputStream; ++import java.io.Console; + import java.io.File; + import java.io.IOException; + import java.io.InputStream; ++import java.io.InputStreamReader; ++import java.nio.CharBuffer; ++import java.security.NoSuchAlgorithmException; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.KeySpec; ++import java.util.Arrays; + import java.util.Collection; ++import java.util.regex.Pattern; + + import com.sun.tools.attach.VirtualMachine; + import com.sun.tools.attach.AttachNotSupportedException; + import sun.tools.attach.HotSpotVirtualMachine; + import sun.tools.common.ProcessArgumentMatcher; + ++import javax.crypto.SecretKey; ++import javax.crypto.SecretKeyFactory; ++import javax.crypto.spec.PBEKeySpec; ++ + import static java.nio.charset.StandardCharsets.UTF_8; + + /* +@@ -45,6 +58,10 @@ import static java.nio.charset.StandardCharsets.UTF_8; + * options are mapped to SA tools. + */ + public class JMap { ++ // encrypt ++ private static int SALT_MIN_LENGTH = 8; ++ private static int HASH_BIT_SIZE = 256; ++ private static int HASH_ITERATIONS_COUNT = 10000; + + public static void main(String[] args) throws Exception { + if (args.length == 0) { +@@ -206,6 +223,8 @@ public class JMap { + String filename = null; + String liveopt = "-all"; + String compress_level = null; ++ RedactParams redactParams = new RedactParams(); ++ String redactPassword = ",RedactPassword="; + + for (String subopt : subopts) { + if (subopt.equals("") || subopt.equals("all")) { +@@ -226,6 +245,18 @@ public class JMap { + System.err.println("Fail: no number provided in option: '" + subopt + "'"); + usage(1); + } ++ } else if (subopt.startsWith("HeapDumpRedact=")) { ++ if (!redactParams.setAndCheckHeapDumpRedact(subopt.substring("HeapDumpRedact=".length()))) { ++ usage(1); ++ } ++ } else if (subopt.startsWith("RedactMap=")) { ++ redactParams.setRedactMap(subopt.substring("RedactMap=".length())); ++ } else if (subopt.startsWith("RedactMapFile=")) { ++ redactParams.setRedactMapFile(subopt.substring("RedactMapFile=".length())); ++ } else if (subopt.startsWith("RedactClassPath")) { ++ redactParams.setRedactClassPath(subopt.substring("RedactClassPath=".length())); ++ } else if (subopt.startsWith("RedactPassword")) { ++ redactPassword = getRedactPassword(pid); + } else { + System.err.println("Fail: invalid option: '" + subopt + "'"); + usage(1); +@@ -237,10 +268,121 @@ public class JMap { + usage(1); + } + ++ checkRedactParams(redactParams); ++ + System.out.flush(); + + // dumpHeap is not the same as jcmd GC.heap_dump +- executeCommandForPid(pid, "dumpheap", filename, liveopt, compress_level); ++ String heapDumpRedactParams = redactParams.isEnableRedact() ? ";" + redactParams.toDumpArgString() + redactPassword : ""; ++ executeCommandForPid(pid, "dumpheap", filename + heapDumpRedactParams, liveopt, compress_level); ++ } ++ ++ private static void checkRedactParams(RedactParams redactParams) { ++ if (redactParams.getHeapDumpRedact() == null) { ++ if (redactParams.getRedactMap() == null && redactParams.getRedactMapFile() == null) { ++ redactParams.setEnableRedact(false); ++ } else { ++ System.err.println("Error: HeapDumpRedact must be specified to enable heap-dump-redacting"); ++ usage(1); ++ } ++ } ++ } ++ ++ private static String getRedactPassword(String pid) { ++ String redactPassword = ",RedactPassword="; ++ // heap dump may need a password ++ Console console = System.console(); ++ char[] passwords = null; ++ if (console == null) { ++ return redactPassword; ++ } ++ ++ try { ++ passwords = console.readPassword("redact authority password:"); ++ } catch (Exception e) { ++ } ++ if(passwords == null) { ++ return redactPassword; ++ } ++ ++ String digestStr = null; ++ try { ++ CharBuffer cb = CharBuffer.wrap(passwords); ++ String passwordPattern = "^[0-9a-zA-Z!@#$]{1,9}$"; ++ if(!Pattern.matches(passwordPattern, cb)) { ++ return redactPassword; ++ } ++ ++ String salt = getSalt(pid); ++ if(salt == null) { ++ return redactPassword; ++ } ++ byte[] saltBytes = salt.getBytes("UTF-8"); ++ if(saltBytes.length < SALT_MIN_LENGTH) { ++ return redactPassword; ++ } ++ digestStr = getEncryptValue(passwords, saltBytes); ++ } catch (Exception e) { ++ }finally { ++ // clear all password ++ if(passwords != null) { ++ Arrays.fill(passwords, '0'); ++ } ++ } ++ ++ redactPassword += (digestStr == null ? "" : digestStr); ++ return redactPassword; ++ } ++ ++ private static String getSalt(String pid) throws Exception { ++ String salt = null; ++ StringBuilder redactAuth = new StringBuilder(); ++ ++ VirtualMachine vm = VirtualMachine.attach(pid); ++ HotSpotVirtualMachine hvm = (HotSpotVirtualMachine) vm; ++ String flag = "RedactPassword"; ++ try (InputStream in = hvm.printFlag(flag); BufferedInputStream bis = new BufferedInputStream(in); ++ InputStreamReader isr = new InputStreamReader(bis, "UTF-8")) { ++ char c[] = new char[256]; ++ int n; ++ do { ++ n = isr.read(c); ++ ++ if (n > 0) { ++ redactAuth.append(n == c.length ? c : Arrays.copyOf(c, n)); ++ } ++ } while (n > 0); ++ } ++ vm.detach(); ++ ++ if(redactAuth.length() > 0) { ++ String[] auths = redactAuth.toString().split(","); ++ if(auths.length != 2) { ++ return salt; ++ } ++ return auths[1].trim(); ++ } ++ ++ return salt; ++ } ++ ++ private static String getEncryptValue(char[] passwordValue, byte[] saltBytes) throws InvalidKeySpecException, NoSuchAlgorithmException { ++ StringBuilder digestStrBuilder = new StringBuilder(); ++ ++ KeySpec spec = new PBEKeySpec(passwordValue, saltBytes, HASH_ITERATIONS_COUNT, HASH_BIT_SIZE); ++ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); ++ SecretKey secretKey = secretKeyFactory.generateSecret(spec); ++ byte[] digestBytes = secretKey.getEncoded(); ++ for (byte b : digestBytes) { ++ String hex = Integer.toHexString(0xff & b); ++ if (hex.length() == 1) { ++ digestStrBuilder.append('0'); ++ } ++ digestStrBuilder.append(hex); ++ } ++ String digestStr = digestStrBuilder.toString(); ++ ++ return digestStr; + } + + private static void checkForUnsupportedOptions(String[] args) { +@@ -307,6 +449,12 @@ public class JMap { + System.err.println(" file= dump heap to "); + System.err.println(" gz= If specified, the heap dump is written in gzipped format using the given compression level."); + System.err.println(" 1 (recommended) is the fastest, 9 the strongest compression."); ++ System.err.println(" HeapDumpRedact= redact the heapdump information to remove sensitive data,"); ++ System.err.println(" RedactMap= Redact the class and field names to other strings"); ++ System.err.println(" RedactMapFile= file path of the redact map"); ++ System.err.println(" RedactClassPath= full path of the redact annotation"); ++ System.err.println(" RedactPassword maybe redact feature has an authority, will wait for a password, "); ++ System.err.println(" without a correct password, heap dump with default redact level"); + System.err.println(""); + System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin "); + System.err.println(""); +@@ -322,4 +470,112 @@ public class JMap { + System.err.println(" Example: jmap -histo:live,file=/tmp/histo.data "); + System.exit(exit); + } ++ ++ public static class RedactParams { ++ private boolean enableRedact = false; ++ private String heapDumpRedact; ++ private String redactMap; ++ private String redactMapFile; ++ private String redactClassPath; ++ ++ public RedactParams() { ++ } ++ ++ public RedactParams(String heapDumpRedact, String redactMap, String redactMapFile, String redactClassPath) { ++ if (heapDumpRedact != null && checkLauncherHeapdumpRedactSupport(heapDumpRedact)) { ++ enableRedact = true; ++ } ++ this.heapDumpRedact = heapDumpRedact; ++ this.redactMap = redactMap; ++ this.redactMapFile = redactMapFile; ++ this.redactClassPath = redactClassPath; ++ } ++ ++ @Override ++ public String toString() { ++ StringBuilder builder = new StringBuilder(); ++ if (heapDumpRedact != null) { ++ builder.append("HeapDumpRedact="); ++ builder.append(heapDumpRedact); ++ builder.append(","); ++ } ++ if (redactMap != null) { ++ builder.append("RedactMap="); ++ builder.append(redactMap); ++ builder.append(","); ++ } ++ if (redactMapFile != null) { ++ builder.append("RedactMapFile="); ++ builder.append(redactMapFile); ++ builder.append(","); ++ } ++ if (redactClassPath != null) { ++ builder.append("RedactClassPath="); ++ builder.append(redactClassPath); ++ } ++ return builder.toString(); ++ } ++ ++ public String toDumpArgString() { ++ return "-HeapDumpRedact=" + (heapDumpRedact == null ? "off" : heapDumpRedact) + ++ ",RedactMap=" + (redactMap == null ? "" : redactMap) + ++ ",RedactMapFile=" + (redactMapFile == null ? "" : redactMapFile) + ++ ",RedactClassPath=" + (redactClassPath == null ? "" : redactClassPath); ++ } ++ ++ public static boolean checkLauncherHeapdumpRedactSupport(String value) { ++ String[] validValues = {"basic", "names", "full", "diyrules", "annotation", "off"}; ++ for (String validValue : validValues) { ++ if (validValue.equals(value)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ public boolean isEnableRedact() { ++ return enableRedact; ++ } ++ ++ public void setEnableRedact(boolean enableRedact) { ++ this.enableRedact = enableRedact; ++ } ++ ++ public String getHeapDumpRedact() { ++ return heapDumpRedact; ++ } ++ ++ public boolean setAndCheckHeapDumpRedact(String heapDumpRedact) { ++ if (!checkLauncherHeapdumpRedactSupport(heapDumpRedact)) { ++ return false; ++ } ++ this.heapDumpRedact = heapDumpRedact; ++ this.enableRedact = true; ++ return true; ++ } ++ ++ public String getRedactMap() { ++ return redactMap; ++ } ++ ++ public void setRedactMap(String redactMap) { ++ this.redactMap = redactMap; ++ } ++ ++ public String getRedactMapFile() { ++ return redactMapFile; ++ } ++ ++ public void setRedactMapFile(String redactMapFile) { ++ this.redactMapFile = redactMapFile; ++ } ++ ++ public String getRedactClassPath() { ++ return redactClassPath; ++ } ++ ++ public void setRedactClassPath(String redactClassPath) { ++ this.redactClassPath = redactClassPath; ++ } ++ } + } +-- +2.47.0.windows.2 + diff --git a/jdk-updates-jdk21u-jdk-21.0.7+6.tar.gz b/jdk-updates-jdk21u-jdk-21.0.7+6.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..48562cf217c8af99e67ec04ee8c31979053b6091 Binary files /dev/null and b/jdk-updates-jdk21u-jdk-21.0.7+6.tar.gz differ diff --git a/openjdk-21.spec b/openjdk-21.spec index d8d1b8f7582f86da05878733898a953de6f0ea28..98ce7a842ed6c066f8b52bdd9e7204be6d5916f4 100644 --- a/openjdk-21.spec +++ b/openjdk-21.spec @@ -21,6 +21,8 @@ %bcond_without slowdebug # Enable release builds by default on relevant arches. %bcond_without release +# Disable global LTO +%define _lto_cflags %{nil} # The -g flag says to use strip -g instead of full strip on DSOs or EXEs. # This fixes detailed NMT and other tools which need minimal debug info. @@ -81,7 +83,7 @@ # By default, we build a debug build during main build on JIT architectures %if %{with slowdebug} %ifarch %{jit_arches} -%global include_debug_build 1 +%global include_debug_build 0 %else %global include_debug_build 0 %endif @@ -158,7 +160,7 @@ # Used via new version scheme. JDK 19 was # GA'ed in March 2022 => 22.3 %global vendor_version_string BiSheng -%global securityver 4 +%global securityver 7 # buildjdkver is usually same as %%{majorver}, # but in time of bootstrap of next jdk, it is majorver-1, # and this it is better to change it here, on single place @@ -178,7 +180,7 @@ %global origin_nice OpenJDK %global top_level_dir_name %{origin} %global minorver 0 -%global buildver 7 +%global buildver 6 %global rpmrelease 1 # priority must be 8 digits in total; up to openjdk 1.8, we were using 18..... so when we moved to 11, we had to add another digit %if %is_system_jdk @@ -558,6 +560,9 @@ exit 0 %ifarch %{svml_arches} %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libjsvml.so %endif +%ifarch %{aarch64} +%{_jvmdir}/%{sdkdir -- %{?1}}/lib/libj2kae.so +%endif %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libsyslookup.so %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libverify.so %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libzip.so @@ -594,6 +599,9 @@ exit 0 %{etcjavadir -- %{?1}}/conf/security/policy/README.txt %config(noreplace) %{etcjavadir -- %{?1}}/conf/security/java.policy %config(noreplace) %{etcjavadir -- %{?1}}/conf/security/java.security +%ifarch %{aarch64} +%config(noreplace) %{etcjavadir -- %{?1}}/conf/kaeprovider.conf +%endif %config(noreplace) %{etcjavadir -- %{?1}}/conf/logging.properties %config(noreplace) %{etcjavadir -- %{?1}}/conf/security/nss.cfg %config(noreplace) %{etcjavadir -- %{?1}}/conf/management/jmxremote.access @@ -897,7 +905,7 @@ Name: java-21-%{origin} Version: %{newjavaver}.%{buildver} # This package needs `.rolling` as part of Release so as to not conflict on install with # java-X-openjdk. I.e. when latest rolling release is also an LTS release packaged as -Release: 0 +Release: 5 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages @@ -926,15 +934,13 @@ Summary: %{origin_nice} Runtime Environment %{majorver} # The test code includes copies of NSS under the Mozilla Public License v2.0 # The PCSClite headers are under a BSD with advertising license # The elliptic curve cryptography (ECC) source code is licensed under the LGPLv2.1 or any later version -License: ASL 1.1 and ASL 2.0 and BSD and BSD with advertising and GPL+ and GPLv2 and GPLv2 with exceptions and IJG and LGPLv2+ and MIT and MPLv2.0 and Public Domain and W3C and zlib and ISC and FTL and RSA +License: ASL 1.1 and ASL 2.0 and BSD and BSD with advertising and GPL+ and GPLv2 and GPLv2 with exceptions and IJG and LGPLv2+ and MIT and MPLv2.0 and Public Domain and W3C and zlib and ISC and FTL and RSA-MD URL: http://openjdk.java.net/ # to regenerate source0 (jdk) and source8 (jdk's taspets) run update_package.sh # update_package.sh contains hard-coded repos, revisions, tags, and projects to regenerate the source archives Source0: jdk-updates-jdk%{majorver}u-jdk-%{filever}+%{buildver}.tar.gz -Source1: OpenJDK20U-jdk_aarch64_linux_hotspot_20.0.2_9.tar.xz -Source2: OpenJDK20U-jdk_x64_linux_hotspot_20.0.2_9.tar.xz Source8: systemtap_3.2_tapsets_hg-icedtea8-9d464368e06d.tar.xz # Desktop files. Adapted from IcedTea @@ -958,10 +964,6 @@ Source14: TestECDSA.java # ############################################ -# NSS via SunPKCS11 Provider (disabled comment -# due to memory leak). -Patch1000: rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch - # Ignore AWTError when assistive technologies are loaded Patch1: rh1648242-accessible_toolkit_crash_do_not_break_jvm.patch # Restrict access to java-atk-wrapper classes @@ -979,6 +981,62 @@ Patch7: add-downgrade-the-glibc-symver-of-log2f-posix_spawn.patch Patch8: add-downgrade-the-glibc-symver-of-memcpy.patch Patch9: add-downgrade-the-glibc-symbol-of-fcntl.patch +# 21.0.4 +Patch10: Backport-JDK-8336855-Duplicate-protected-declaration.patch +Patch11: Backport-JDK-8334758-Incorrect-note-in-Javadoc-for-a.patch +Patch12: Backport-JDK-8323699-MessageFormat.toPattern-generat.patch +Patch16: Backport-JDK-8333805-Replaying-compilation-with-null.patch +Patch19: 8339351-Remove-duplicate-line-in-FileMapHeader-print.patch +Patch21: 8339149-jfr_flush_event_writer-return-value-type-mis.patch +Patch22: 8300800-UB-Shift-exponent-32-is-too-large-for-32-bit.patch +Patch23: 8334780-Crash-assert-h_array_list.not_null-failed-in.patch +Patch24: 8337982-Remove-dead-undef-assrt0n.patch +Patch26: 8335610-DiagnosticFramework-CmdLine-is_executable-co.patch +Patch27: Backport-of-8337245-Fix-wrong-comment-of-StringConca.patch +Patch28: Backport-of-8337274-Remove-repeated-the.patch +Patch29: backport-of-8339298-Remove-unused-function-declarati.patch +Patch32: BackPort-JDK-8336346-Fix--Wzero-as-null-pointer-cons.patch +Patch37: Backport-JDK-8336080-Fix--Wzero-as-null-pointer-cons.patch +Patch38: Backport-JDK-8336152-Remove-unused-forward-declarati.patch +Patch39: Backport-of-8330191-Fix-typo-in-precompiled.hpp.patch +Patch40: Backport-of-8337787-Fix-Wzero-as-null-pointer-consta.patch +Patch41: Backport-of-8337712-Wrong-javadoc-in-java.util.Date-.patch +Patch49: Backport-JDK-8328107-Shenandoah-C2-TestVerifyLoopOpt.patch +Patch51: Backport-JDK-8329754-The-ThreadSafe-attribute-is-ign.patch +Patch53: Backport-JDK-8335638-Calling-VarHandle.-access-mode-.patch +Patch54: Backport-JDK-8338938-The-result-of-the-combine-metho.patch +Patch55: Backport-JDK-8313909-JVMCI-assert-cp-tag_at-index-.i.patch +Patch56: Backport-JDK-8304484-CDS-dynamic-dumping-incorrectly.patch +Patch57: Backport-JDK-8322812-Manpage-for-jcmd-is-missing-JFR.patch +Patch58: Backport-JDK-8327538-The-SSLExtension-class-specifie.patch +Patch60: Backport-JDK-8333599-Improve-description-of-b-matche.patch +Patch63: Backport-JDK-8336879-Always-true-condition-img-null-.patch +Patch64: Backport-JDK-8337334-Test-tools-javac-7142086-T71420.patch +Patch65: Backport-JDK-8340623-Remove-outdated-PROCESSOR_ARCHI.patch +Patch66: Backport-JDK-8338010-WB_IsFrameDeoptimized-miss-Reso.patch +Patch67: Backport-JDK-8340186-Shenandoah-Missing-load_referen.patch +Patch68: Backport-JDK-8340273-Remove-CounterHalfLifeTime.patch +Patch69: Backport-JDK-8339460-CDS-error-when-module-is-locate.patch +Patch70: Backport-JDK-8332297-annotation-processor-that-gener.patch +Patch71: Backport-JDK-8329174-update-CodeBuffer-layout-in-com.patch +Patch72: Backport-JDK-8325994-JFR-Examples-in-JFR.start-help-.patch +Patch73: Backport-JDK-8325730-StringBuilder.toString-allocati.patch +Patch74: Backport-JDK-8337679-Memset-warning-in-src-hotspot-s.patch +Patch75: Backport-JDK-8326957-Implement-JEP-474-ZGC-Generatio.patch +Patch76: Backport-JDK-8320308-C2-compilation-crashes-in-Libra.patch +Patch78: huawei-Add-KAE-Provider.patch +Patch79: huawei-Add-KAE-zip-feature.patch +Patch80: huawei-Fix-arm32-build-failed-undefined-reference.patch +Patch81: huawei-Add-Fast-Serialzer.patch +Patch82: huawei-Add-Hashmap-frontCache-opt.patch +Patch83: huawei-1-add-port-jbolt-feature.patch +Patch84: huawei-heap-dump-redact-support.patch +Patch85: huawei-Adapt-to-clang-build-toolchain.patch + +#21.0.7 +Patch87: huawei-fix-build-fail-realpath.patch +Patch88: 8352716-tz-Update-Timezone-Data-to-2025b.patch +Patch89: heapdump-bug-fix.patch ############################################ # # LoongArch64 specific patches @@ -986,6 +1044,19 @@ Patch9: add-downgrade-the-glibc-symbol-of-fcntl.patch ############################################ Patch2000: LoongArch64-support.patch +############################################ +# +# RISC-V specific patches +# +############################################ +Patch3001: Backport-JDK-8315338-RISC-V-Change-flags-for-stable-.patch +Patch3002: Backport-JDK-8329083-RISC-V-Update-profiles-supporte.patch +Patch3003: Backport-JDK-8343555-RISC-V-make-some-verified-on-ha.patch +Patch3004: Backport-JDK-8348554-Enhance-Linux-kernel-version-ch.patch +Patch3005: Backport-JDK-8348384-RISC-V-Disable-auto-enable-Vect.patch +Patch3006: Backport-JDK-8352673-RISC-V-Vector-can-t-be-turned-o.patch +Patch3007: Backport-JDK-8355878-RISC-V-jdk-incubator-vector-Dou.patch + BuildRequires: autoconf BuildRequires: automake BuildRequires: alsa-lib-devel @@ -1017,8 +1088,9 @@ BuildRequires: nss-devel BuildRequires: pkgconfig BuildRequires: xorg-x11-proto-devel BuildRequires: zip +BuildRequires: openssl-devel BuildRequires: javapackages-filesystem -#BuildRequires: java-21-openjdk-devel +BuildRequires: java-21-openjdk-devel # Zero-assembler build requirement %ifnarch %{jit_arches} BuildRequires: libffi-devel @@ -1207,7 +1279,7 @@ fi # OpenJDK patches # Remove libraries that are linked -sh %{SOURCE12} +# sh %{SOURCE12} %ifnarch loongarch64 pushd %{top_level_dir_name} %patch1 -p1 @@ -1215,6 +1287,59 @@ pushd %{top_level_dir_name} %patch7 -p1 %patch8 -p1 %patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch16 -p1 +%patch19 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch32 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch49 -p1 +%patch51 -p1 +%patch53 -p1 +%patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 +%patch60 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 +%patch68 -p1 +%patch69 -p1 +%patch70 -p1 +%patch71 -p1 +%patch72 -p1 +%patch73 -p1 +%patch74 -p1 +%patch75 -p1 +%patch76 -p1 +%patch78 -p1 +%patch79 -p1 +%patch80 -p1 +%patch81 -p1 +%patch82 -p1 +%patch83 -p1 +%patch84 -p1 +%patch85 -p1 +%patch87 -p1 +%patch88 -p1 +%patch89 -p1 popd # openjdk %endif @@ -1224,7 +1349,17 @@ pushd %{top_level_dir_name} popd %endif -%patch1000 +%ifarch riscv64 +pushd %{top_level_dir_name} +%patch3001 -p1 +%patch3002 -p1 +%patch3003 -p1 +%patch3004 -p1 +%patch3005 -p1 +%patch3006 -p1 +%patch3007 -p1 +popd +%endif # Extract systemtap tapsets %if %{with_systemtap} @@ -1330,22 +1465,6 @@ fi ARCH=$(uname -m) BOOTJDKPATH=/usr/lib/jvm/java-%{buildjdkver}-openjdk -if [ "$ARCH" = "x86_64" ]; then - tar -xf %{SOURCE2} - BOOTJDKPATH=$PWD/jdk-20.0.2+9 -elif [ "$ARCH" = "aarch64" ]; then - tar -xf %{SOURCE1} - BOOTJDKPATH=$PWD/jdk-20.0.2+9 -elif [ "$ARCH" = "riscv64" ]; then - : -elif [ "$ARCH" = "loongarch64" ]; then - : -elif [ "$ARCH" = "ppc64le" ]; then - : -else - echo " Failed to set BOOTJDKPATH " - exit 18 -fi echo $BOOTJDKPATH @@ -1359,11 +1478,14 @@ bash ../configure \ %ifarch %{ppc64le} --with-jobs=1 \ %endif +%ifarch %{aarch64} + --enable-kae=yes \ +%endif %if "%toolchain" == "clang" --with-toolchain-type=clang \ %endif --with-version-build=%{buildver} \ - --with-version-pre=\"${EA_DESIGNATOR}\" \ + --with-version-pre="${EA_DESIGNATOR}" \ --with-version-opt=%{lts_designator} \ --with-vendor-version-string="%{vendor_version_string}" \ --with-vendor-name="BiSheng" \ @@ -1665,9 +1787,10 @@ else end end -- run content of included file with fake args +arg = nil; -- it is better to null the arg up, no meter if they exists or not, and use cjc as module in unified way, instead of relaying on "main" method during require "copy_jdk_configs.lua" cjc = require "copy_jdk_configs.lua" -arg = {"--currentjvm", "%{uniquesuffix %{nil}}", "--jvmdir", "%{_jvmdir %{nil}}", "--origname", "%{name}", "--origjavaver", "%{javaver}", "--arch", "%{_arch}", "--temp", "%{rpm_state_dir}/%{name}.%{_arch}"} -cjc.mainProgram(arg) +args = {"--currentjvm", "%{uniquesuffix %{nil}}", "--jvmdir", "%{_jvmdir %{nil}}", "--origname", "%{name}", "--origjavaver", "%{javaver}", "--arch", "%{_arch}", "--temp", "%{rpm_state_dir}/%{name}.%{_arch}"} +cjc.mainProgram(args) -- the returns from copy_jdk_configs.lua should not affect this 'main', so it should run under all circumstances, except fatal error %post %{post_script %{nil}} @@ -1792,6 +1915,180 @@ cjc.mainProgram(arg) %changelog +* Sat May 17 2025 Benshuai5D - 1:21.0.7.6-5 +- add heapdump-bug-fix.patch + +* Wed May 14 2025 Dingli Zhang - 1:21.0.7.6-4 +- add Backport-JDK-8352673-RISC-V-Vector-can-t-be-turned-o.patch +- add Backport-JDK-8355878-RISC-V-jdk-incubator-vector-Dou.patch + +* Sat May 10 2025 wulongyao - 1:21.0.7.6-3 +- delete huawei-Add-KAE-SM2.patch + +* Wed Apr 30 2025 songliyang - 1:21.0.7.6-2 +- update LoongArch64 port to 21.0.7 +- fix changelog date error + +* Tue Apr 29 2025 wulongyao - 1:21.0.7.6-1 +- add 8352716-tz-Update-Timezone-Data-to-2025b.patch + +* Thu Apr 17 2025 DXwangg - 1:21.0.7.6-0 +- update to jdk21.0.7-ga +- delete Backport-JDK-8328553-Get-rid-of-JApplet-in-test-jdk-.patch +- delete Backport-JDK-8336012-Fix-usages-of-jtreg-reserved-pr.patch +- delete huawei-8347965-tz-Update-Timezone-Data-to-2025a.patch +- modify huawei-Adapt-to-clang-build-toolchain.patch +- add huawei-fix-build-fail-realpath.patch +- modify huawei-heap-dump-redact-support.patch + +* Mon Mar 24 2025 Dingli Zhang - 1:21.0.6.7-3 +- add RVA23 profile and disable auto-enable Vector on buggy kernels for riscv64 +- add Backport-JDK-8315338-RISC-V-Change-flags-for-stable-.patch +- add Backport-JDK-8329083-RISC-V-Update-profiles-supporte.patch +- add Backport-JDK-8343555-RISC-V-make-some-verified-on-ha.patch +- add Backport-JDK-8348554-Enhance-Linux-kernel-version-ch.patch +- add Backport-JDK-8348384-RISC-V-Disable-auto-enable-Vect.patch + +* Sat Mar 22 2025 wulongyao - 1:21.0.6.7-2 +- add huawei-8347965-tz-Update-Timezone-Data-to-2025a.patch +- add huawei-Add-KAE-Provider.patch +- add huawei-Add-KAE-zip-feature.patch +- add huawei-Fix-arm32-build-failed-undefined-reference.patch +- add huawei-Add-Fast-Serialzer.patch +- add huawei-Add-Hashmap-frontCache-opt.patch +- add huawei-1-add-port-jbolt-feature.patch +- add huawei-heap-dump-redact-support.patch +- add huawei-Adapt-to-clang-build-toolchain.patch +- add huawei-Add-KAE-SM2.patch + +* Tue Feb 11 2025 Pan Xuefeng - 1:21.0.6.7-1 +- update LoongArch64 port to 21.0.6 + +* Thu Jan 23 2025 Benshuai5D - 1:21.0.6.7-0 +- update to jdk21.0.6-ga +- delete Backport-JDK-8207908-JMXStatusTest.java-fails-assert.patch +- delete Backport-JDK-8320682-[AArch64]-C1-compilation-fails-.patch +- delete Backport-JDK-8331391-Enhance-the-keytool-code-by-inv.patch +- delete Backport-JDK-8332866-Crash-in-ImageIO-JPEG-decoding-.patch +- delete Backport-of-8337067-Test-runtime-classFileParserBug-.patch +- delete Backport-of-JDK-8316895-SeenThread-print_action_que.patch +- delete Backport-of-JDK-8328723-IP-Address-error-when-client.patch +- modify Backport-JDK-8329174-update-CodeBuffer-layout-in-com.patch +- modify Backport-JDK-8340623-Remove-outdated-PROCESSOR_ARCHI.patch + +* Wed Dec 25 2024 Dingli Zhang - 1:21.0.5.11-4 +- Remove double colons from patch names +- Fix typo in chagelog + +* Thu Dec 5 2024 kuenking111 - 1:21.0.5.11-3 +- disable LTO + +* Mon Nov 11 2024 Dingli Zhang - 1:21.0.5.11-2 +- Remove redundant patch to fix ci check + +* Wed Nov 6 2024 Pan Xuefeng - 1:21.0.5.11-1 +- update LoongArch64 port to 21.0.5 + +* Wed Oct 16 2024 huangjie - 1:21.0.5.11-0 +- update to jdk21.0.5-ga +- delete Backport-JDK-8333462-Performance-regression-of-new-D.patch +- delete Backport-JDK-8332818-ubsan-archiveHeapLoader.cpp:70:.patch +- detete Backport-JDK-8333887-ubsan-unsafe.cpp:247:13:-runtim.patch +- detete BackPort-JDK-8324580-SIGFPE-on-THP-initialization-on.patch +- delete Backport-JDK-8334239-Introduce-macro-for-ubsan-metho.patch +- delete Backport-of-8333088-ubsan-shenandoahAdaptiveHeuristi.patch +- detete Backport-JDK-8332524-Instead-of-printing-TLSv1.3,-.patch +- delete Backport-JDK-8333149-ubsan-memset-on-nullptr-target-.patch +- detete Backport-JDK-8333622-ubsan-relocInfo_x86.cpp:101:56:.patch +- detete Backport-JDK-8333354-ubsan-frame.inline.hpp:91:25:-a.patch +- delete Backport-JDK-8333639-ubsan-cppVtables.cpp:81:55-runt.patch +- delete Backport-of-JDK-8336343-Add-more-known-sysroot-libra.patch +- delete Backport-of-JDK-8332720-ubsan-instanceKlass.cpp:3550.patch +- delete Backport-JDK-8332920-C2-Partial-Peeling-is-wrongly-a.patch +- delete Backport-JDK-8334123-log-the-opening-of-Type-1-fonts.patch +- delete Backport-JDK-8325022-Incorrect-error-message-on-clie.patch + +* Sat Oct 12 2024 Autistic_boyya - 1:21.0.4.7-5 +- add 8300800-UB-Shift-exponent-32-is-too-large-for-32-bit.patch +- add 8334780-Crash-assert-h_array_list.not_null-failed-in.patch +- add 8335610-DiagnosticFramework-CmdLine-is_executable-co.patch +- add 8337982-Remove-dead-undef-assrt0n.patch +- add 8339149-jfr_flush_event_writer-return-value-type-mis.patch +- add 8339351-Remove-duplicate-line-in-FileMapHeader-print.patch +- add BackPort-JDK-8324580-SIGFPE-on-THP-initialization-on.patch +- add BackPort-JDK-8336346-Fix--Wzero-as-null-pointer-cons.patch +- add Backport-JDK-8207908-JMXStatusTest.java-fails-assert.patch +- add Backport-JDK-8304484-CDS-dynamic-dumping-incorrectly.patch +- add Backport-JDK-8313909-JVMCI-assert-cp-tag_at-index-.i.patch +- add Backport-JDK-8320308-C2-compilation-crashes-in-Libra.patch +- add Backport-JDK-8320682-[AArch64]-C1-compilation-fails-.patch +- add Backport-JDK-8322812-Manpage-for-jcmd-is-missing-JFR.patch +- add Backport-JDK-8323699-MessageFormat.toPattern-generat.patch +- add Backport-JDK-8325022-Incorrect-error-message-on-clie.patch +- add Backport-JDK-8325730-StringBuilder.toString-allocati.patch +- add Backport-JDK-8325994-JFR-Examples-in-JFR.start-help-.patch +- add Backport-JDK-8326957-Implement-JEP-474-ZGC-Generatio.patch +- add Backport-JDK-8327538-The-SSLExtension-class-specifie.patch +- add Backport-JDK-8328107-Shenandoah-C2-TestVerifyLoopOpt.patch +- add Backport-JDK-8328553-Get-rid-of-JApplet-in-test-jdk-.patch +- add Backport-JDK-8329174-update-CodeBuffer-layout-in-com.patch +- add Backport-JDK-8329754-The-ThreadSafe-attribute-is-ign.patch +- add Backport-JDK-8331391-Enhance-the-keytool-code-by-inv.patch +- add Backport-JDK-8332297-annotation-processor-that-gener.patch +- add Backport-JDK-8332524-Instead-of-printing-TLSv1.3,-.patch +- add Backport-JDK-8332818-ubsan-archiveHeapLoader.cpp:70:.patch +- add Backport-JDK-8332866-Crash-in-ImageIO-JPEG-decoding-.patch +- add Backport-JDK-8332920-C2-Partial-Peeling-is-wrongly-a.patch +- add Backport-JDK-8333149-ubsan-memset-on-nullptr-target-.patch +- add Backport-JDK-8333354-ubsan-frame.inline.hpp:91:25:-a.patch +- add Backport-JDK-8333462-Performance-regression-of-new-D.patch +- add Backport-JDK-8333599-Improve-description-of-b-matche.patch +- add Backport-JDK-8333622-ubsan-relocInfo_x86.cpp:101:56:.patch +- add Backport-JDK-8333639-ubsan-cppVtables.cpp:81:55-runt.patch +- add Backport-JDK-8333805-Replaying-compilation-with-null.patch +- add Backport-JDK-8333887-ubsan-unsafe.cpp:247:13:-runtim.patch +- add Backport-JDK-8334123-log-the-opening-of-Type-1-fonts.patch +- add Backport-JDK-8334239-Introduce-macro-for-ubsan-metho.patch +- add Backport-JDK-8334758-Incorrect-note-in-Javadoc-for-a.patch +- add Backport-JDK-8335638-Calling-VarHandle.-access-mode-.patch +- add Backport-JDK-8336012-Fix-usages-of-jtreg-reserved-pr.patch +- add Backport-JDK-8336080-Fix--Wzero-as-null-pointer-cons.patch +- add Backport-JDK-8336152-Remove-unused-forward-declarati.patch +- add Backport-JDK-8336855-Duplicate-protected-declaration.patch +- add Backport-JDK-8336879-Always-true-condition-img-null-.patch +- add Backport-JDK-8337334-Test-tools-javac-7142086-T71420.patch +- add Backport-JDK-8337679-Memset-warning-in-src-hotspot-s.patch +- add Backport-JDK-8338010-WB_IsFrameDeoptimized-miss-Reso.patch +- add Backport-JDK-8338938-The-result-of-the-combine-metho.patch +- add Backport-JDK-8339460-CDS-error-when-module-is-locate.patch +- add Backport-JDK-8340186-Shenandoah-Missing-load_referen.patch +- add Backport-JDK-8340273-Remove-CounterHalfLifeTime.patch +- add Backport-JDK-8340623-Remove-outdated-PROCESSOR_ARCHI.patch +- add Backport-of-8330191-Fix-typo-in-precompiled.hpp.patch +- add Backport-of-8333088-ubsan-shenandoahAdaptiveHeuristi.patch +- add Backport-of-8337067-Test-runtime-classFileParserBug-.patch +- add Backport-of-8337245-Fix-wrong-comment-of-StringConca.patch +- add Backport-of-8337274-Remove-repeated-the.patch +- add Backport-of-8337712-Wrong-javadoc-in-java.util.Date-.patch +- add Backport-of-8337787-Fix-Wzero-as-null-pointer-consta.patch +- add Backport-of-JDK-8316895-SeenThread::print_action_que.patch +- add Backport-of-JDK-8328723-IP-Address-error-when-client.patch +- add Backport-of-JDK-8332720-ubsan-instanceKlass.cpp:3550.patch +- add Backport-of-JDK-8336343-Add-more-known-sysroot-libra.patch +- add backport-of-8339298-Remove-unused-function-declarati.patch + +* Wed Aug 14 2024 songliyang - 1:21.0.4.7-4 +- delete redundant symbols while viewing spec file with vim that make it strange on highlight + +* Wed Aug 7 2024 Autistic_boyya - 1:21.0.4.7-3 +- delete rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch + +* Fri Aug 2 2024 zhaosaisai - 1:21.0.4.7-2 +- change boot jdk to itself + +* Thu Aug 1 2024 aoqi - 1:21.0.4.7-1 +- update LoongArch64 port to 21.0.4 + * Thu Jul 18 2024 Autistic_boyya -1:21.0.4.7-rolling - update to jdk21.0.4-ga diff --git a/pr3183-rh1340845-support_system_crypto_policy.patch b/pr3183-rh1340845-support_system_crypto_policy.patch deleted file mode 100644 index 9ca3dc6eb9149d4f085844ca4147402a978ce925..0000000000000000000000000000000000000000 --- a/pr3183-rh1340845-support_system_crypto_policy.patch +++ /dev/null @@ -1,87 +0,0 @@ - -# HG changeset patch -# User andrew -# Date 1478057514 0 -# Node ID 1c4d5cb2096ae55106111da200b0bcad304f650c -# Parent 3d53f19b48384e5252f4ec8891f7a3a82d77af2a -diff -r 3d53f19b4838 -r 1c4d5cb2096a src/java.base/share/classes/java/security/Security.java ---- a/src/java.base/share/classes/java/security/Security.java Wed Oct 26 03:51:39 2016 +0100 -+++ b/src/java.base/share/classes/java/security/Security.java Wed Nov 02 03:31:54 2016 +0000 -@@ -43,6 +43,9 @@ - * implementation-specific location, which is typically the properties file - * {@code conf/security/java.security} in the Java installation directory. - * -+ *

    Additional default values of security properties are read from a -+ * system-specific location, if available.

    -+ * - * @author Benjamin Renaud - * @since 1.1 - */ -@@ -52,6 +55,10 @@ - private static final Debug sdebug = - Debug.getInstance("properties"); - -+ /* System property file*/ -+ private static final String SYSTEM_PROPERTIES = -+ "/etc/crypto-policies/back-ends/java.config"; -+ - /* The java.security properties */ - private static Properties props; - -@@ -93,6 +100,7 @@ - if (sdebug != null) { - sdebug.println("reading security properties file: " + - propFile); -+ sdebug.println(props.toString()); - } - } catch (IOException e) { - if (sdebug != null) { -@@ -114,6 +122,31 @@ - } - - if ("true".equalsIgnoreCase(props.getProperty -+ ("security.useSystemPropertiesFile"))) { -+ -+ // now load the system file, if it exists, so its values -+ // will win if they conflict with the earlier values -+ try (BufferedInputStream bis = -+ new BufferedInputStream(new FileInputStream(SYSTEM_PROPERTIES))) { -+ props.load(bis); -+ loadedProps = true; -+ -+ if (sdebug != null) { -+ sdebug.println("reading system security properties file " + -+ SYSTEM_PROPERTIES); -+ sdebug.println(props.toString()); -+ } -+ } catch (IOException e) { -+ if (sdebug != null) { -+ sdebug.println -+ ("unable to load security properties from " + -+ SYSTEM_PROPERTIES); -+ e.printStackTrace(); -+ } -+ } -+ } -+ -+ if ("true".equalsIgnoreCase(props.getProperty - ("security.overridePropertiesFile"))) { - - String extraPropFile = System.getProperty -diff -r 3d53f19b4838 -r 1c4d5cb2096a src/java.base/share/conf/security/java.security ---- a/src/java.base/share/conf/security/java.security Wed Oct 26 03:51:39 2016 +0100 -+++ b/src/java.base/share/conf/security/java.security Wed Nov 02 03:31:54 2016 +0000 -@@ -276,6 +276,13 @@ - security.overridePropertiesFile=true - - # -+# Determines whether this properties file will be appended to -+# using the system properties file stored at -+# /etc/crypto-policies/back-ends/java.config -+# -+security.useSystemPropertiesFile=true -+ -+# - # Determines the default key and trust manager factory algorithms for - # the javax.net.ssl package. - # diff --git a/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch b/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch deleted file mode 100644 index ef4c82864f2bb6b187401dfb31281a8f8f84fe2a..0000000000000000000000000000000000000000 --- a/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -r e3f940bd3c8f src/java.base/share/conf/security/java.security ---- openjdk/src/java.base/share/conf/security/java.security Thu Jun 11 21:54:51 2020 +0530 -+++ openjdk/src/java.base/share/conf/security/java.security Mon Aug 24 10:14:31 2020 +0200 -@@ -77,7 +77,7 @@ - #ifdef macosx - security.provider.tbd=Apple - #endif --security.provider.tbd=SunPKCS11 -+#security.provider.tbd=SunPKCS11 ${java.home}/lib/security/nss.cfg - - # - # A list of preferred providers for specific algorithms. These providers will