Author SHA1 Message Date
DingliZhang 1d0c2e911f Add supports_misaligned_vector_accesses
OpenJDK GHA Sanity Checks / Prepare the run (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-nopch (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-zero (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-minimal (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-hs-optimized (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-static (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-x64-static-libs (push) Has been cancelled
OpenJDK GHA Sanity Checks / linux-cross-compile (push) Has been cancelled
OpenJDK GHA Sanity Checks / alpine-linux-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / macos-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / macos-aarch64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / windows-x64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / windows-aarch64 (push) Has been cancelled
OpenJDK GHA Sanity Checks / docs (push) Has been cancelled
2025-10-09 16:03:20 +08:00
DingliZhang a36d5f8fa9 8368722: RISC-V: Several vector load/store tests fail without support for misaligned vector access 2025-09-30 10:31:18 +08:00
Fei Yang 538a722c2e 8368732: RISC-V: Detect support for misaligned vector access via hwprobe
Reviewed-by: mli, dzhang
2025-09-30 01:40:35 +00:00
Alexey Semenyuk c57003c9b8 8368890: open/test/jdk/tools/jpackage/macosx/NameWithSpaceTest.java fails randomly
Reviewed-by: almatvee
2025-09-29 21:39:42 +00:00
Afshin Zafari 2f29b3f24a 8366884: NMT fails with MallocLimit: reached category "mtCompiler" limit
Reviewed-by: phubner, jsjolen
2025-09-29 19:24:28 +00:00
Hannes GreuleandChristian Hagedorn 59e76af47b 8367967: C2: "fatal error: Not monotonic" with Mod nodes
Co-authored-by: Christian Hagedorn <chagedorn@openjdk.org>
Reviewed-by: bmaillard, vlivanov, chagedorn, shade
2025-09-29 18:40:43 +00:00
Chen Liang 6c8e384c63 8356022: Migrate descriptor parsing from generics to BytecodeDescriptor
Reviewed-by: rriggs
2025-09-29 18:22:24 +00:00
Chris Plummer 3d97e17a31 8367318: Test vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_rt/filter_rt001/TestDescription.java timed out after passing
Reviewed-by: amenkov, sspitsyn
2025-09-29 17:46:17 +00:00
Brian Burkhalter aabf699dd0 8355339: Test java/io/File/GetCanonicalPath.java failed: The specified network name is no longer available
Reviewed-by: alanb
2025-09-29 17:43:35 +00:00
Hamlin Li 9d71af108e 8367253: RISC-V: refactor dependent cpu extensions
Reviewed-by: fyang, luhenry
2025-09-29 16:04:54 +00:00
Joe Darcy 63688d894e 8368822: Refactor Float16.valueOf(double)
Reviewed-by: rgiulietti
2025-09-29 14:48:04 +00:00
Roger Riggs 9d9c0e0670 8368793: java/lang/StringBuilder/RacingSBThreads.java timed out in Xcomp subtest
Reviewed-by: iris, alanb, syan
2025-09-29 13:55:49 +00:00
Daniel Gredler fdbba049a2 8368775: Remove outdated comment in OutlineTextRenderer
Reviewed-by: prr, dnguyen, serb
2025-09-29 10:39:25 +00:00
Daniel Gredler 6165921449 7156751: [macosx] Problem with printing
Reviewed-by: prr, serb
2025-09-29 10:28:45 +00:00
Thomas Schatzl 08b677bba4 8071277: G1: Merge commits and uncommits of contiguous memory
Reviewed-by: iwalulya, ayang
2025-09-29 10:05:45 +00:00
Albert Mingkun Yang 75269fdb49 8368715: Serial: Add GCTraceTime for marking from roots subphases during full gc marking
Reviewed-by: fandreuzzi, tschatzl, iwalulya
2025-09-29 07:26:43 +00:00
Jan Lahoda d53190ac44 8366582: Test jdk/jshell/ToolSimpleTest.java failed: provider not found
Reviewed-by: asotona
2025-09-29 05:36:18 +00:00
Axel Boldt-Christmas e19ec6f785 8368754: runtime/cds/appcds/SignedJar.java log regex is too strict
Reviewed-by: iklam, dholmes
2025-09-29 05:19:56 +00:00
Sergey Bylokhov 320230db5f 8367795: HeadlessMalfunctionTest may fail due to timeout
Reviewed-by: prr
2025-09-28 04:49:58 +00:00
Kelvin Nilsen af8fb20ac0 8368307: Shenandoah: get_next_bit_impl should special case weak and strong mark bits
Reviewed-by: wkemper
2025-09-27 04:07:29 +00:00
SendaoYan 9093d3a04c 8368668: Several vmTestbase/vm/gc/compact tests timed out on large memory machine
Reviewed-by: lmesnik
2025-09-27 02:37:39 +00:00
Archie Cobbs 5b1ebbb271 8366561: Improve documentation for how the -Xlint flag works
Reviewed-by: vromero
2025-09-27 02:34:27 +00:00
Mohamed Issa 37f0e74d32 8364305: Support AVX10 saturating floating point conversion instructions
Reviewed-by: sviswanathan, sparasa, jbhateja
2025-09-26 21:10:30 +00:00
Alex MenkovandAlan Bateman cedc0117ac 8365057: Add support for java.util.concurrent lock information to Thread.dump_to_file
Co-authored-by: Alex Menkov <amenkov@openjdk.org>
Co-authored-by: Alan Bateman <alanb@openjdk.org>
Reviewed-by: sspitsyn, alanb
2025-09-26 20:49:36 +00:00
Justin Lu 12c0f29b97 8368498: Use JUnit instead of TestNG for jdk_text tests
Reviewed-by: naoto
2025-09-26 20:12:48 +00:00
Francesco Andreuzzi c6cecc581f 8283198: Remove src/jdk.hotspot.agent/test
Reviewed-by: amenkov, ayang, sspitsyn
2025-09-26 19:51:04 +00:00
Leonid Mesnik 62cc347242 8368699: nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp destroys jvmti monitor when VM is dead
Reviewed-by: sspitsyn
2025-09-26 19:36:00 +00:00
Leonid Mesnik 556dfddac8 8308027: GetThreadListStackTraces/OneGetThreadListStackTraces.java should be skipped when thread factory is used
Reviewed-by: dholmes, sspitsyn
2025-09-26 19:34:04 +00:00
Naoto Sato bdf6853cfd 8368328: CompactNumberFormat.clone does not produce independent instances
Reviewed-by: rgiulietti, jlu
2025-09-26 16:50:05 +00:00
Ashutosh Mehra aa6ff45052 8368693: Duplicate methods in vmClasses
Reviewed-by: liach, coleenp, dholmes
2025-09-26 14:56:03 +00:00
Albert Mingkun Yang 25abdd85c4 8368752: Serial: Remove unused arg of DefNewGeneration::gc_epilogue
Reviewed-by: tschatzl, fandreuzzi
2025-09-26 14:48:26 +00:00
Manuel Hässig 501b2b3ebc 8368615: VSCode IDE: Oracle Java extension routinely runs out of memory
Reviewed-by: erikj
2025-09-26 14:28:35 +00:00
Roger Riggs 2360542e89 8368683: [process] Increase jtreg debug output maxOutputSize for TreeTest
Reviewed-by: msheppar
2025-09-26 14:19:12 +00:00
Alexey Semenyuk bdb7d25ac1 8358723: jpackage signing issues: the main launcher doesn't have entitlements
Reviewed-by: almatvee
2025-09-26 13:59:39 +00:00
Joachim Kern f0e1078c71 8368250: [AIX] now ubsan vptr check is also possible (follow up of JDK-8354686)
Reviewed-by: erikj, stuefe, mbaesken
2025-09-26 12:14:58 +00:00
Matthias Baesken 7bfdb01207 8368565: Adjust comment regarding dependency of libjvm.so to librt
Reviewed-by: dholmes
2025-09-26 09:00:59 +00:00
Matthias Baesken a80ba6260e 8357691: File blocked.certs contains bad content when boot jdk 25 is used, sun/security/lib/CheckBlockedCerts.java failing
Reviewed-by: erikj, iklam
2025-09-26 07:56:40 +00:00
Arno Zeller b90799c0e9 8368616: runtime/cds/appcds/aotCache/JavaAgent.java#dynamic fails on non CDS platforms/builds after JDK-8362561
Reviewed-by: mbaesken, shade, iklam
2025-09-26 07:47:26 +00:00
Albert Mingkun Yang 873078028b 8368006: Parallel: Skip full regions in dense prefix during Full GC
Reviewed-by: gli, fandreuzzi
2025-09-26 07:27:51 +00:00
Thomas Stuefe a663812121 8368124: Show useful thread names in ASAN reports
Reviewed-by: dholmes, mbaesken
2025-09-26 06:14:28 +00:00
Alexey Semenyuk ca03080c9f 8368030: Make package bundlers stateless
Reviewed-by: almatvee
2025-09-26 00:10:21 +00:00
Daniel D. Daugherty 648582ab78 8368714: [BACKOUT] JDK-8368468 Split out everything but configure results from spec.gmk
Reviewed-by: ihse
2025-09-25 20:55:05 +00:00
Ioi Lam 52e777845f 8367910: Reduce warnings about unsupported classes in AOT cache creation
Reviewed-by: dholmes, kvn, shade
2025-09-25 19:59:52 +00:00
Daniel Jeliński 3c9fd7688f 8368514: TLS stateless session ticket decryption fails on some providers
Reviewed-by: valeriep, abarashev
2025-09-25 18:47:32 +00:00
Johannes Graham a48538dd63 8367324: Avoid redundant parsing when formatting with DigitList
Reviewed-by: jlu, rgiulietti
2025-09-25 18:23:13 +00:00
Daniel Jeliński 80cb0ead50 8367133: DTLS: fragmentation of Finished message results in handshake failure
Reviewed-by: jnimeh
2025-09-25 18:17:19 +00:00
Valerie Peng 5c596e2a95 8360463: Ambiguity in Cipher.getInstance() specification between NoSuchAlgorithmException and NoSuchPaddingException
Reviewed-by: mullan
2025-09-25 18:10:58 +00:00
Magnus Ihse Bursie 32ab0dbc0b 8368674: Incremental builds keep rebuilding interim jmod
Reviewed-by: cstein, erikj
2025-09-25 17:44:55 +00:00
Magnus Ihse Bursie de1f5a3c43 8368468: Split out everything but configure results from spec.gmk
Reviewed-by: erikj
2025-09-25 17:42:46 +00:00
Albert Mingkun Yang 741221988e 8368261: Serial: Use more precise nmethod scope during Full GC marking
Reviewed-by: stefank, fandreuzzi
2025-09-25 16:47:22 +00:00
William Kemper 8ca1feaf7e 8368499: GenShen: Do not collect age census during evac when adaptive tenuring is disabled
Reviewed-by: kdnilsen, ysr
2025-09-25 15:37:02 +00:00
250 changed files with 5890 additions and 3326 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ TOOL_GENERATECURRENCYDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_
TOOL_TZDB = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
build.tools.tzdb.TzdbZoneRulesCompiler
TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -Xlog:disable -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
--add-exports java.base/sun.security.util=ALL-UNNAMED \
build.tools.blockedcertsconverter.BlockedCertsConverter
+1 -1
View File
@@ -79,7 +79,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
fi
if test "x$OPENJDK_TARGET_OS" = xaix; then
BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-blibpath:/usr/lib:lib -Wl,-bnoexpall \
-Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
-Wl,-bernotok -Wl,-bcdtors:mbr::s -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc"
fi
+7 -2
View File
@@ -565,9 +565,14 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER],
# with an additional define LLVM_SYMBOLIZER, which we set here.
# To calculate the correct llvm_symbolizer path we can use the location of the compiler, because
# their relation is fixed.
# In the ubsan case we have to link every binary with the C++-compiler as linker, because inherently
# the C-Compiler and the C++-compiler used as linker provide a different set of ubsan exports.
# Linking an executable with the C-compiler and one of its shared libraries with the C++-compiler
# leeds to unresolved symbols.
if test "x$TOOLCHAIN_TYPE" = "xclang" && test "x$OPENJDK_TARGET_OS" = "xaix"; then
UBSAN_CFLAGS="$UBSAN_CFLAGS -fno-sanitize=function,vptr -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer"
UBSAN_LDFLAGS="$UBSAN_LDFLAGS -fno-sanitize=function,vptr -Wl,-bbigtoc"
UBSAN_CFLAGS="$UBSAN_CFLAGS -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer"
UBSAN_LDFLAGS="$UBSAN_LDFLAGS -Wl,-bbigtoc"
LD="$LDCXX"
fi
UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED,
DESC: [enable UndefinedBehaviorSanitizer],
+1 -5
View File
@@ -136,12 +136,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBPTHREAD"
fi
# librt for legacy clock_gettime
# librt - for timers (timer_* functions)
if test "x$OPENJDK_TARGET_OS" = xlinux; then
# Hotspot needs to link librt to get the clock_* functions.
# But once our supported minimum build and runtime platform
# has glibc 2.17, this can be removed as the functions are
# in libc.
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lrt"
fi
+1 -1
View File
@@ -149,7 +149,7 @@ define SetupExecuteBody
endif
$1_VARDEPS := $$($1_COMMAND) $$($1_PRE_COMMAND) $$($1_POST_COMMAND)
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS)
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BASE)_exec.vardeps)
ifneq ($$($1_PRE_COMMAND), )
@@ -22,6 +22,7 @@
// Java extension
"jdk.project.jdkhome": "{{OUTPUTDIR}}/jdk",
"jdk.java.onSave.organizeImports": false, // prevents unnecessary changes
"jdk.serverVmOptions": ["-Xmx2G"], // prevent out of memory
// Additional conventions
"files.associations": {
@@ -199,6 +199,8 @@ enum Ampere_CPU_Model {
constexpr static bool supports_secondary_supers_table() { return true; }
constexpr static bool supports_misaligned_vector_accesses() { return true; }
static void get_compatible_board(char *buf, int buflen);
static const SpinWait& spin_wait_desc() { return _spin_wait; }
+1
View File
@@ -64,6 +64,7 @@ public:
constexpr static bool supports_stack_watermark_barrier() { return true; }
constexpr static bool supports_recursive_lightweight_locking() { return true; }
constexpr static bool supports_secondary_supers_table() { return true; }
constexpr static bool supports_misaligned_vector_accesses() { return true; }
static bool supports_float16() { return PowerArchitecturePPC64 >= 9; }
+10 -32
View File
@@ -160,7 +160,7 @@ void VM_Version::common_initialize() {
if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) {
FLAG_SET_DEFAULT(AvoidUnalignedAccesses,
unaligned_access.value() != MISALIGNED_FAST);
unaligned_scalar.value() != MISALIGNED_SCALAR_FAST);
}
if (!AvoidUnalignedAccesses) {
@@ -175,7 +175,15 @@ void VM_Version::common_initialize() {
// This machine has fast unaligned memory accesses
if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) {
FLAG_SET_DEFAULT(UseUnalignedAccesses,
unaligned_access.value() == MISALIGNED_FAST);
(unaligned_scalar.value() == MISALIGNED_SCALAR_FAST));
}
if (FLAG_IS_DEFAULT(AlignVector)) {
FLAG_SET_DEFAULT(AlignVector,
unaligned_vector.value() != MISALIGNED_VECTOR_FAST);
} else if (unaligned_vector.value() != MISALIGNED_VECTOR_FAST){
warning("Misaligned vector accesses are not supported on this CPU");
FLAG_SET_DEFAULT(AlignVector, true);
}
#ifdef __riscv_ztso
@@ -234,36 +242,6 @@ void VM_Version::common_initialize() {
warning("CRC32C intrinsics are not available on this CPU.");
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
}
// UseZvbb (depends on RVV).
if (UseZvbb && !UseRVV) {
warning("Cannot enable UseZvbb on cpu without RVV support.");
FLAG_SET_DEFAULT(UseZvbb, false);
}
// UseZvbc (depends on RVV).
if (UseZvbc && !UseRVV) {
warning("Cannot enable UseZvbc on cpu without RVV support.");
FLAG_SET_DEFAULT(UseZvbc, false);
}
// UseZvkn (depends on RVV).
if (UseZvkn && !UseRVV) {
warning("Cannot enable UseZvkn on cpu without RVV support.");
FLAG_SET_DEFAULT(UseZvkn, false);
}
// UseZvfh (depends on RVV)
if (UseZvfh) {
if (!UseRVV) {
warning("Cannot enable UseZvfh on cpu without RVV support.");
FLAG_SET_DEFAULT(UseZvfh, false);
}
if (!UseZfh) {
warning("Cannot enable UseZvfh on cpu without Zfh support.");
FLAG_SET_DEFAULT(UseZvfh, false);
}
}
}
#ifdef COMPILER2
+110 -63
View File
@@ -70,6 +70,35 @@ class VM_Version : public Abstract_VM_Version {
int64_t value() { return _value; }
virtual bool enabled() = 0;
virtual void update_flag() = 0;
protected:
bool deps_all_enabled(RVFeatureValue* dep0, ...) {
assert(dep0 != nullptr, "must not");
va_list va;
va_start(va, dep0);
RVFeatureValue* next = dep0;
bool enabled = true;
while (next != nullptr && enabled) {
enabled = next->enabled();
next = va_arg(va, RVFeatureValue*);
}
va_end(va);
return enabled;
}
void deps_string(stringStream& ss, RVFeatureValue* dep0, ...) {
assert(dep0 != nullptr, "must not");
ss.print("%s (%s)", dep0->pretty(), dep0->enabled() ? "enabled" : "disabled");
va_list va;
va_start(va, dep0);
RVFeatureValue* next = nullptr;
while ((next = va_arg(va, RVFeatureValue*)) != nullptr) {
ss.print(", %s (%s)", next->pretty(), next->enabled() ? "enabled" : "disabled");
}
va_end(va);
}
};
#define UPDATE_DEFAULT(flag) \
@@ -85,27 +114,34 @@ class VM_Version : public Abstract_VM_Version {
} \
} \
#define UPDATE_DEFAULT_DEP(flag, dep) \
void update_flag() { \
assert(enabled(), "Must be."); \
/* dep must be declared before */ \
assert((uintptr_t)(this) > \
(uintptr_t)(&dep), "Invalid"); \
if (FLAG_IS_DEFAULT(flag)) { \
if (dep.enabled()) { \
FLAG_SET_DEFAULT(flag, true); \
} else { \
FLAG_SET_DEFAULT(flag, false); \
/* Sync CPU features with flags */ \
disable_feature(); \
} \
} else { \
/* Sync CPU features with flags */ \
if (!flag) { \
disable_feature(); \
} \
} \
} \
#define UPDATE_DEFAULT_DEP(flag, dep0, ...) \
void update_flag() { \
assert(enabled(), "Must be."); \
if (FLAG_IS_DEFAULT(flag)) { \
if (this->deps_all_enabled(dep0, ##__VA_ARGS__)) { \
FLAG_SET_DEFAULT(flag, true); \
} else { \
FLAG_SET_DEFAULT(flag, false); \
stringStream ss; \
deps_string(ss, dep0, ##__VA_ARGS__); \
warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \
/* Sync CPU features with flags */ \
disable_feature(); \
} \
} else { \
/* Sync CPU features with flags */ \
if (!flag) { \
disable_feature(); \
} else if (!deps_all_enabled(dep0, ##__VA_ARGS__)) { \
FLAG_SET_DEFAULT(flag, false); \
stringStream ss; \
deps_string(ss, dep0, ##__VA_ARGS__); \
warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \
/* Sync CPU features with flags */ \
disable_feature(); \
} \
} \
} \
#define NO_UPDATE_DEFAULT \
void update_flag() {} \
@@ -191,7 +227,8 @@ class VM_Version : public Abstract_VM_Version {
// mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2..
// marchid Id for microarch. Mvendorid plus marchid uniquely identify the microarch.
// mimpid A unique encoding of the version of the processor implementation.
// unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast)
// unaligned_scalar Performance of misaligned scalar accesses (unknown, emulated, slow, fast, unsupported)
// unaligned_vector Performance of misaligned vector accesses (unknown, unspported, slow, fast)
// satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64
public:
@@ -202,40 +239,40 @@ class VM_Version : public Abstract_VM_Version {
//
// Fields description in `decl`:
// declaration name, extension name, bit value from linux, feature string?, mapped flag)
#define RV_EXT_FEATURE_FLAGS(decl) \
decl(ext_I , i , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_M , m , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_A , a , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_F , f , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_D , d , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_C , c , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
decl(ext_Q , q , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_H , h , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_V , v , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
decl(ext_Zicbom , Zicbom , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
decl(ext_Zicboz , Zicboz , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
decl(ext_Zicbop , Zicbop , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
decl(ext_Zba , Zba , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
decl(ext_Zbb , Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
decl(ext_Zbc , Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zbs , Zbs , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
decl(ext_Zbkb , Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \
decl(ext_Zcb , Zcb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
decl(ext_Zfa , Zfa , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \
decl(ext_Zfh , Zfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
decl(ext_Zfhmin , Zfhmin , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
decl(ext_Zicsr , Zicsr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zicntr , Zicntr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zifencei , Zifencei , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zic64b , Zic64b , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
decl(ext_Ztso , Ztso , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
decl(ext_Zihintpause , Zihintpause , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
decl(ext_Zacas , Zacas , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
decl(ext_Zvbb , Zvbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, ext_V)) \
decl(ext_Zvbc , Zvbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, ext_V)) \
decl(ext_Zvfh , Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, ext_V)) \
decl(ext_Zvkn , Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, ext_V)) \
decl(ext_Zicond , Zicond , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
#define RV_EXT_FEATURE_FLAGS(decl) \
decl(ext_I , i , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_M , m , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_A , a , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_F , f , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_D , d , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_C , c , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
decl(ext_Q , q , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_H , h , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_V , v , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
decl(ext_Zicbom , Zicbom , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
decl(ext_Zicboz , Zicboz , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
decl(ext_Zicbop , Zicbop , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
decl(ext_Zba , Zba , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
decl(ext_Zbb , Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
decl(ext_Zbc , Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zbs , Zbs , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
decl(ext_Zbkb , Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \
decl(ext_Zcb , Zcb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
decl(ext_Zfa , Zfa , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \
decl(ext_Zfh , Zfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
decl(ext_Zfhmin , Zfhmin , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
decl(ext_Zicsr , Zicsr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zicntr , Zicntr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zifencei , Zifencei , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zic64b , Zic64b , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
decl(ext_Ztso , Ztso , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
decl(ext_Zihintpause , Zihintpause , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
decl(ext_Zacas , Zacas , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
decl(ext_Zvbb , Zvbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, &ext_V, nullptr)) \
decl(ext_Zvbc , Zvbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, &ext_V, nullptr)) \
decl(ext_Zvfh , Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, &ext_V, &ext_Zfh, nullptr)) \
decl(ext_Zvkn , Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, &ext_V, nullptr)) \
decl(ext_Zicond , Zicond , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
#define DECLARE_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
struct NAME##RVExtFeatureValue : public RVExtFeatureValue { \
@@ -251,11 +288,12 @@ class VM_Version : public Abstract_VM_Version {
// Non-extension features
//
#define RV_NON_EXT_FEATURE_FLAGS(decl) \
decl(unaligned_access , Unaligned , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(mvendorid , VendorId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(marchid , ArchId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(mimpid , ImpId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(satp_mode , SATP , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(unaligned_scalar , UnalignedScalar , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(unaligned_vector , UnalignedVector , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(zicboz_block_size, ZicbozBlockSize , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
#define DECLARE_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
@@ -396,12 +434,19 @@ private:
static VM_MODE parse_satp_mode(const char* vm_mode);
// Values from riscv_hwprobe()
enum UNALIGNED_ACCESS : int {
MISALIGNED_UNKNOWN = 0,
MISALIGNED_EMULATED = 1,
MISALIGNED_SLOW = 2,
MISALIGNED_FAST = 3,
MISALIGNED_UNSUPPORTED = 4
enum UNALIGNED_SCALAR_ACCESS : int {
MISALIGNED_SCALAR_UNKNOWN = 0,
MISALIGNED_SCALAR_EMULATED = 1,
MISALIGNED_SCALAR_SLOW = 2,
MISALIGNED_SCALAR_FAST = 3,
MISALIGNED_SCALAR_UNSUPPORTED = 4
};
enum UNALIGNED_VECTOR_ACCESS : int {
MISALIGNED_VECTOR_UNKNOWN = 0,
MISALIGNED_VECTOR_SLOW = 2,
MISALIGNED_VECTOR_FAST = 3,
MISALIGNED_VECTOR_UNSUPPORTED = 4
};
// Null terminated list
@@ -438,6 +483,8 @@ private:
constexpr static bool supports_secondary_supers_table() { return true; }
static bool supports_misaligned_vector_accesses() { return unaligned_vector.value() == MISALIGNED_VECTOR_FAST; }
static bool supports_on_spin_wait() { return UseZihintpause; }
// RISCV64 supports fast class initialization checks
+2
View File
@@ -425,6 +425,8 @@ class VM_Version: public Abstract_VM_Version {
constexpr static bool supports_secondary_supers_table() { return true; }
constexpr static bool supports_misaligned_vector_accesses() { return true; }
constexpr static bool supports_recursive_lightweight_locking() { return true; }
// CPU feature query functions
+152
View File
@@ -2225,6 +2225,44 @@ void Assembler::cvttss2sil(Register dst, XMMRegister src) {
emit_int16(0x2C, (0xC0 | encode));
}
void Assembler::evcvttss2sisl(Register dst, XMMRegister src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttss2sisl(Register dst, Address src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::evcvttss2sisq(Register dst, XMMRegister src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttss2sisq(Register dst, Address src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::cvttpd2dq(XMMRegister dst, XMMRegister src) {
int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit;
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2310,6 +2348,25 @@ void Assembler::vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x5B, (0xC0 | encode));
}
void Assembler::evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttps2dqs(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) {
assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2317,6 +2374,25 @@ void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16((unsigned char)0xE6, (0xC0 | encode));
}
void Assembler::evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttpd2dqs(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len) {
assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2332,6 +2408,25 @@ void Assembler::evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x7A, (0xC0 | encode));
}
void Assembler::evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttps2qqs(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_address_attributes(/* tuple_type */ EVEX_HV, /* input_size_in_bits */ EVEX_32bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512dq(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2356,6 +2451,25 @@ void Assembler::evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x7A, (0xC0 | encode));
}
void Assembler::evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttpd2qqs(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512dq(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -14988,6 +15102,44 @@ void Assembler::cvttsd2siq(Register dst, Address src) {
emit_operand(dst, src, 0);
}
void Assembler::evcvttsd2sisl(Register dst, XMMRegister src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttsd2sisl(Register dst, Address src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::evcvttsd2sisq(Register dst, XMMRegister src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
emit_int16(0x6D, (0xC0 | encode));
}
void Assembler::evcvttsd2sisq(Register dst, Address src) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
attributes.set_is_evex_instruction();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
emit_int8((unsigned char)0x6D);
emit_operand(dst, src, 0);
}
void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
+16
View File
@@ -1316,11 +1316,19 @@ private:
void cvttsd2sil(Register dst, XMMRegister src);
void cvttsd2siq(Register dst, Address src);
void cvttsd2siq(Register dst, XMMRegister src);
void evcvttsd2sisl(Register dst, XMMRegister src);
void evcvttsd2sisl(Register dst, Address src);
void evcvttsd2sisq(Register dst, XMMRegister src);
void evcvttsd2sisq(Register dst, Address src);
// Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer
void cvttss2sil(Register dst, XMMRegister src);
void cvttss2siq(Register dst, XMMRegister src);
void cvtss2sil(Register dst, XMMRegister src);
void evcvttss2sisl(Register dst, XMMRegister src);
void evcvttss2sisl(Register dst, Address src);
void evcvttss2sisq(Register dst, XMMRegister src);
void evcvttss2sisq(Register dst, Address src);
// Convert vector double to int
void cvttpd2dq(XMMRegister dst, XMMRegister src);
@@ -1332,7 +1340,11 @@ private:
// Convert vector float to int/long
void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len);
void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttps2dqs(XMMRegister dst, Address src, int vector_len);
void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttps2qqs(XMMRegister dst, Address src, int vector_len);
// Convert vector long to vector FP
void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len);
@@ -1341,9 +1353,13 @@ private:
// Convert vector double to long
void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttpd2qqs(XMMRegister dst, Address src, int vector_len);
// Convert vector double to int
void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttpd2dqs(XMMRegister dst, Address src, int vector_len);
// Evex casts with truncation
void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len);
+85 -5
View File
@@ -5053,12 +5053,12 @@ void C2_MacroAssembler::vector_cast_int_to_subword(BasicType to_elem_bt, XMMRegi
}
vpackuswb(dst, dst, zero, vec_enc);
break;
default: assert(false, "%s", type2name(to_elem_bt));
default: assert(false, "Unexpected basic type for target of vector cast int to subword: %s", type2name(to_elem_bt));
}
}
/*
* Algorithm for vector D2L and F2I conversions:-
* Algorithm for vector D2L and F2I conversions (AVX 10.2 unsupported):-
* a) Perform vector D2L/F2I cast.
* b) Choose fast path if none of the result vector lane contains 0x80000000 value.
* It signifies that source value could be any of the special floating point
@@ -5096,7 +5096,7 @@ void C2_MacroAssembler::vector_castF2X_evex(BasicType to_elem_bt, XMMRegister ds
case T_BYTE:
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "%s", type2name(to_elem_bt));
default: assert(false, "Unexpected basic type for target of vector castF2X EVEX: %s", type2name(to_elem_bt));
}
}
@@ -5143,7 +5143,7 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds
evpmovsqd(dst, dst, vec_enc);
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "%s", type2name(to_elem_bt));
default: assert(false, "Unexpected basic type for target of vector castD2X AVX512DQ EVEX: %s", type2name(to_elem_bt));
}
} else {
assert(type2aelembytes(to_elem_bt) <= 4, "");
@@ -5158,11 +5158,91 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds
case T_BYTE:
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "%s", type2name(to_elem_bt));
default: assert(false, "Unexpected basic type for target of vector castD2X EVEX: %s", type2name(to_elem_bt));
}
}
}
void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) {
switch(to_elem_bt) {
case T_LONG:
evcvttps2qqs(dst, src, vec_enc);
break;
case T_INT:
evcvttps2dqs(dst, src, vec_enc);
break;
case T_SHORT:
evcvttps2dqs(dst, src, vec_enc);
evpmovdw(dst, dst, vec_enc);
break;
case T_BYTE:
evcvttps2dqs(dst, src, vec_enc);
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (reg src): %s", type2name(to_elem_bt));
}
}
void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) {
switch(to_elem_bt) {
case T_LONG:
evcvttps2qqs(dst, src, vec_enc);
break;
case T_INT:
evcvttps2dqs(dst, src, vec_enc);
break;
case T_SHORT:
evcvttps2dqs(dst, src, vec_enc);
evpmovdw(dst, dst, vec_enc);
break;
case T_BYTE:
evcvttps2dqs(dst, src, vec_enc);
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (mem src): %s", type2name(to_elem_bt));
}
}
void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) {
switch(to_elem_bt) {
case T_LONG:
evcvttpd2qqs(dst, src, vec_enc);
break;
case T_INT:
evcvttpd2dqs(dst, src, vec_enc);
break;
case T_SHORT:
evcvttpd2dqs(dst, src, vec_enc);
evpmovdw(dst, dst, vec_enc);
break;
case T_BYTE:
evcvttpd2dqs(dst, src, vec_enc);
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (reg src): %s", type2name(to_elem_bt));
}
}
void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) {
switch(to_elem_bt) {
case T_LONG:
evcvttpd2qqs(dst, src, vec_enc);
break;
case T_INT:
evcvttpd2dqs(dst, src, vec_enc);
break;
case T_SHORT:
evcvttpd2dqs(dst, src, vec_enc);
evpmovdw(dst, dst, vec_enc);
break;
case T_BYTE:
evcvttpd2dqs(dst, src, vec_enc);
evpmovdb(dst, dst, vec_enc);
break;
default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (mem src): %s", type2name(to_elem_bt));
}
}
void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src,
AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc,
Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) {
@@ -347,6 +347,13 @@ public:
XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5,
AddressLiteral float_sign_flip, Register rscratch, int vec_enc);
void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc);
void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc);
void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc);
void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc);
void vector_cast_double_to_int_special_cases_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2,
XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, Register rscratch,
+4
View File
@@ -991,6 +991,10 @@ public:
return true;
}
constexpr static bool supports_misaligned_vector_accesses() {
return true;
}
constexpr static bool supports_stack_watermark_barrier() {
return true;
}
+66 -5
View File
@@ -7664,8 +7664,11 @@ instruct vcastFtoD_reg(vec dst, vec src) %{
instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4);
predicate(!VM_Version::supports_avx10_2() &&
!VM_Version::supports_avx512vl() &&
Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4 &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastF2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, KILL cr);
format %{ "vector_cast_f2x $dst,$src\t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %}
@@ -7687,7 +7690,8 @@ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec
%}
instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{
predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
predicate(!VM_Version::supports_avx10_2() &&
(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastF2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr);
@@ -7709,6 +7713,33 @@ instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k
ins_pipe( pipe_slow );
%}
instruct castFtoX_reg_avx10(vec dst, vec src) %{
predicate(VM_Version::supports_avx10_2() &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastF2X src));
format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %}
ins_encode %{
BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(this, $src);
__ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct castFtoX_mem_avx10(vec dst, memory src) %{
predicate(VM_Version::supports_avx10_2() &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastF2X (LoadVector src)));
format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %}
ins_encode %{
int vlen = Matcher::vector_length(this);
BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(vlen * sizeof(jfloat));
__ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct vcastDtoF_reg(vec dst, vec src) %{
predicate(Matcher::vector_element_basic_type(n) == T_FLOAT);
match(Set dst (VectorCastD2X src));
@@ -7721,7 +7752,9 @@ instruct vcastDtoF_reg(vec dst, vec src) %{
%}
instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, vec xtmp5, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
predicate(!VM_Version::supports_avx10_2() &&
!VM_Version::supports_avx512vl() &&
Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastD2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, TEMP xtmp5, KILL cr);
@@ -7737,7 +7770,8 @@ instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec
%}
instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{
predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
predicate(!VM_Version::supports_avx10_2() &&
(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastD2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr);
@@ -7753,6 +7787,33 @@ instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k
ins_pipe( pipe_slow );
%}
instruct castDtoX_reg_avx10(vec dst, vec src) %{
predicate(VM_Version::supports_avx10_2() &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastD2X src));
format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %}
ins_encode %{
int vlen_enc = vector_length_encoding(this, $src);
BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
__ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct castDtoX_mem_avx10(vec dst, memory src) %{
predicate(VM_Version::supports_avx10_2() &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastD2X (LoadVector src)));
format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %}
ins_encode %{
int vlen = Matcher::vector_length(this);
int vlen_enc = vector_length_encoding(vlen * sizeof(jdouble));
BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
__ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct vucast(vec dst, vec src) %{
match(Set dst (VectorUCastB2X src));
match(Set dst (VectorUCastS2X src));
+92
View File
@@ -11712,6 +11712,7 @@ instruct convD2F_reg_mem(regF dst, memory src)
// XXX do mem variants
instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr)
%{
predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvF2I src));
effect(KILL cr);
format %{ "convert_f2i $dst, $src" %}
@@ -11721,8 +11722,31 @@ instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
instruct convF2I_reg_reg_avx10(rRegI dst, regF src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvF2I src));
format %{ "evcvttss2sisl $dst, $src" %}
ins_encode %{
__ evcvttss2sisl($dst$$Register, $src$$XMMRegister);
%}
ins_pipe(pipe_slow);
%}
instruct convF2I_reg_mem_avx10(rRegI dst, memory src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvF2I (LoadF src)));
format %{ "evcvttss2sisl $dst, $src" %}
ins_encode %{
__ evcvttss2sisl($dst$$Register, $src$$Address);
%}
ins_pipe(pipe_slow);
%}
instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr)
%{
predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvF2L src));
effect(KILL cr);
format %{ "convert_f2l $dst, $src"%}
@@ -11732,8 +11756,31 @@ instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
instruct convF2L_reg_reg_avx10(rRegL dst, regF src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvF2L src));
format %{ "evcvttss2sisq $dst, $src" %}
ins_encode %{
__ evcvttss2sisq($dst$$Register, $src$$XMMRegister);
%}
ins_pipe(pipe_slow);
%}
instruct convF2L_reg_mem_avx10(rRegL dst, memory src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvF2L (LoadF src)));
format %{ "evcvttss2sisq $dst, $src" %}
ins_encode %{
__ evcvttss2sisq($dst$$Register, $src$$Address);
%}
ins_pipe(pipe_slow);
%}
instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr)
%{
predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvD2I src));
effect(KILL cr);
format %{ "convert_d2i $dst, $src"%}
@@ -11743,8 +11790,31 @@ instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
instruct convD2I_reg_reg_avx10(rRegI dst, regD src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvD2I src));
format %{ "evcvttsd2sisl $dst, $src" %}
ins_encode %{
__ evcvttsd2sisl($dst$$Register, $src$$XMMRegister);
%}
ins_pipe(pipe_slow);
%}
instruct convD2I_reg_mem_avx10(rRegI dst, memory src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvD2I (LoadD src)));
format %{ "evcvttsd2sisl $dst, $src" %}
ins_encode %{
__ evcvttsd2sisl($dst$$Register, $src$$Address);
%}
ins_pipe(pipe_slow);
%}
instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr)
%{
predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvD2L src));
effect(KILL cr);
format %{ "convert_d2l $dst, $src"%}
@@ -11754,6 +11824,28 @@ instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
instruct convD2L_reg_reg_avx10(rRegL dst, regD src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvD2L src));
format %{ "evcvttsd2sisq $dst, $src" %}
ins_encode %{
__ evcvttsd2sisq($dst$$Register, $src$$XMMRegister);
%}
ins_pipe(pipe_slow);
%}
instruct convD2L_reg_mem_avx10(rRegL dst, memory src)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (ConvD2L (LoadD src)));
format %{ "evcvttsd2sisq $dst, $src" %}
ins_encode %{
__ evcvttsd2sisq($dst$$Register, $src$$Address);
%}
ins_pipe(pipe_slow);
%}
instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr)
%{
match(Set dst (RoundD src));
+17 -12
View File
@@ -160,7 +160,6 @@ address os::Linux::_initial_thread_stack_bottom = nullptr;
uintptr_t os::Linux::_initial_thread_stack_size = 0;
int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr;
int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = nullptr;
pthread_t os::Linux::_main_thread;
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_libc_version = nullptr;
@@ -4371,10 +4370,6 @@ void os::init(void) {
// _main_thread points to the thread that created/loaded the JVM.
Linux::_main_thread = pthread_self();
// retrieve entry point for pthread_setname_np
Linux::_pthread_setname_np =
(int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np");
check_pax();
// Check the availability of MADV_POPULATE_WRITE.
@@ -4851,14 +4846,24 @@ uint os::processor_id() {
}
void os::set_native_thread_name(const char *name) {
if (Linux::_pthread_setname_np) {
char buf [16]; // according to glibc manpage, 16 chars incl. '/0'
(void) os::snprintf(buf, sizeof(buf), "%s", name);
buf[sizeof(buf) - 1] = '\0';
const int rc = Linux::_pthread_setname_np(pthread_self(), buf);
// ERANGE should not happen; all other errors should just be ignored.
assert(rc != ERANGE, "pthread_setname_np failed");
char buf[16]; // according to glibc manpage, 16 chars incl. '/0'
// We may need to truncate the thread name. Since a common pattern
// for thread names is to be both longer than 15 chars and have a
// trailing number ("DispatcherWorkerThread21", "C2 CompilerThread#54" etc),
// we preserve the end of the thread name by truncating the middle
// (e.g. "Dispatc..read21").
const size_t len = strlen(name);
if (len < sizeof(buf)) {
strcpy(buf, name);
} else {
(void) os::snprintf(buf, sizeof(buf), "%.7s..%.6s", name, name + len - 6);
}
// Note: we use the system call here instead of calling pthread_setname_np
// since this is the only way to make ASAN aware of our thread names. Even
// though ASAN intercepts both prctl and pthread_setname_np, it only processes
// the thread name given to the former.
int rc = prctl(PR_SET_NAME, buf);
assert(rc == 0, "prctl(PR_SET_NAME) failed");
}
////////////////////////////////////////////////////////////////////////////////
-1
View File
@@ -33,7 +33,6 @@ class os::Linux {
friend class os;
static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
static int (*_pthread_setname_np)(pthread_t, const char*);
static address _initial_thread_stack_bottom;
static uintptr_t _initial_thread_stack_size;
@@ -89,7 +89,24 @@
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7
#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8
#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9
#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0
#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1
#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2
#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3
#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4
#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10
#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0
#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2
#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3
#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4
#ifndef NR_riscv_hwprobe
#ifndef NR_arch_specific_syscall
@@ -117,7 +134,11 @@ static struct riscv_hwprobe query[] = {{RISCV_HWPROBE_KEY_MVENDORID, 0},
{RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0},
{RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
{RISCV_HWPROBE_KEY_CPUPERF_0, 0},
{RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0}};
{RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0},
{RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS, 0},
{RISCV_HWPROBE_KEY_TIME_CSR_FREQ, 0},
{RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF, 0},
{RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, 0}};
bool RiscvHwprobe::probe_features() {
assert(!rw_hwprobe_completed, "Called twice.");
@@ -246,9 +267,20 @@ void RiscvHwprobe::add_features_from_query_result() {
VM_Version::ext_Zicond.enable_feature();
}
#endif
// RISCV_HWPROBE_KEY_CPUPERF_0 is deprecated and returns similar values
// to RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF. Keep it there for backward
// compatibility with old kernels.
if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) {
VM_Version::unaligned_access.enable_feature(
VM_Version::unaligned_scalar.enable_feature(
query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK);
} else if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF)) {
VM_Version::unaligned_scalar.enable_feature(
query[RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF].value);
}
if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF)) {
VM_Version::unaligned_vector.enable_feature(
query[RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF].value);
}
if (is_valid(RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE)) {
VM_Version::zicboz_block_size.enable_feature(query[RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE].value);
@@ -303,7 +303,7 @@ void VM_Version::rivos_features() {
ext_Zvfh.enable_feature();
unaligned_access.enable_feature(MISALIGNED_FAST);
unaligned_scalar.enable_feature(MISALIGNED_SCALAR_FAST);
satp_mode.enable_feature(VM_SV48);
// Features dependent on march/mimpid.
@@ -53,7 +53,7 @@ void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const
assert(k->is_loader_alive(), "must not change");
} else {
if (!SystemDictionaryShared::is_excluded_class(k)) {
SystemDictionaryShared::warn_excluded(k, "Class loader not alive");
SystemDictionaryShared::log_exclusion(k, "Class loader not alive");
SystemDictionaryShared::set_excluded_locked(k);
}
}
@@ -2445,7 +2445,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
cfs->skip_u2_fast(method_parameters_length);
cfs->skip_u2_fast(method_parameters_length);
// ignore this attribute if it cannot be reflected
if (!vmClasses::Parameter_klass_loaded())
if (!vmClasses::reflect_Parameter_klass_is_loaded())
method_parameters_length = -1;
} else if (method_attribute_name == vmSymbols::tag_synthetic()) {
if (method_attribute_length != 0) {
@@ -3979,7 +3979,7 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
#endif
// Check if this klass supports the java.lang.Cloneable interface
if (vmClasses::Cloneable_klass_loaded()) {
if (vmClasses::Cloneable_klass_is_loaded()) {
if (ik->is_subtype_of(vmClasses::Cloneable_klass())) {
ik->set_is_cloneable();
}
+2 -2
View File
@@ -1150,7 +1150,7 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
// Class_klass has to be loaded because it is used to allocate
// the mirror.
if (vmClasses::Class_klass_loaded()) {
if (vmClasses::Class_klass_is_loaded()) {
Handle mirror;
Handle comp_mirror;
@@ -1223,7 +1223,7 @@ bool java_lang_Class::restore_archived_mirror(Klass *k,
Handle protection_domain, TRAPS) {
// Postpone restoring archived mirror until java.lang.Class is loaded. Please
// see more details in vmClasses::resolve_all().
if (!vmClasses::Class_klass_loaded() && !CDSConfig::is_using_aot_linked_classes()) {
if (!vmClasses::Class_klass_is_loaded() && !CDSConfig::is_using_aot_linked_classes()) {
assert(fixup_mirror_list() != nullptr, "fixup_mirror_list not initialized");
fixup_mirror_list()->push(k);
return true;
+1 -1
View File
@@ -456,7 +456,7 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version,
#if COMPILER2_OR_JVMCI
// Special handling of jdk.incubator.vector
if (strcmp(module_name, "jdk.incubator.vector") == 0) {
if (FLAG_IS_DEFAULT(EnableVectorSupport)) {
if (FLAG_IS_DEFAULT(EnableVectorSupport) && VM_Version::supports_misaligned_vector_accesses()) {
FLAG_SET_DEFAULT(EnableVectorSupport, true);
}
if (EnableVectorSupport && FLAG_IS_DEFAULT(EnableVectorReboxing)) {
@@ -354,11 +354,13 @@ void SystemDictionaryShared::check_exclusion_for_self_and_dependencies(InstanceK
});
}
// Returns true so the caller can do: return warn_excluded(".....");
bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) {
void SystemDictionaryShared::log_exclusion(InstanceKlass* k, const char* reason, bool is_warning) {
ResourceMark rm;
aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason);
return true;
if (is_warning) {
aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason);
} else {
aot_log_info(aot)("Skipping %s: %s", k->name()->as_C_string(), reason);
}
}
bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) {
@@ -377,23 +379,35 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) {
}
bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) {
bool log_warning = false;
const char* error = check_self_exclusion_helper(k, log_warning);
if (error != nullptr) {
log_exclusion(k, error, log_warning);
return true; // Should be excluded
} else {
return false; // Should not be excluded
}
}
const char* SystemDictionaryShared::check_self_exclusion_helper(InstanceKlass* k, bool& log_warning) {
assert_lock_strong(DumpTimeTable_lock);
if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders()
&& k->in_aot_cache()) {
return false; // Do not exclude: unregistered classes are passed from preimage to final image.
return nullptr; // Do not exclude: unregistered classes are passed from preimage to final image.
}
if (k->is_in_error_state()) {
return warn_excluded(k, "In error state");
log_warning = true;
return "In error state";
}
if (k->is_scratch_class()) {
return warn_excluded(k, "A scratch class");
return "A scratch class";
}
if (!k->is_loaded()) {
return warn_excluded(k, "Not in loaded state");
return "Not in loaded state";
}
if (has_been_redefined(k)) {
return warn_excluded(k, "Has been redefined");
return "Has been redefined";
}
if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) {
if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) {
@@ -401,43 +415,42 @@ bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) {
if (CDSConfig::is_dumping_method_handles()) {
k->set_shared_classpath_index(0);
} else {
ResourceMark rm;
aot_log_info(aot)("Skipping %s because it is dynamically generated", k->name()->as_C_string());
return true; // exclude without warning
return "dynamically generated";
}
} else {
// These are classes loaded from unsupported locations (such as those loaded by JVMTI native
// agent during dump time).
return warn_excluded(k, "Unsupported location");
return "Unsupported location";
}
}
if (k->signers() != nullptr) {
// We cannot include signed classes in the archive because the certificates
// used during dump time may be different than those used during
// runtime (due to expiration, etc).
return warn_excluded(k, "Signed JAR");
return "Signed JAR";
}
if (is_jfr_event_class(k)) {
// We cannot include JFR event classes because they need runtime-specific
// instrumentation in order to work with -XX:FlightRecorderOptions:retransform=false.
// There are only a small number of these classes, so it's not worthwhile to
// support them and make CDS more complicated.
return warn_excluded(k, "JFR event class");
return "JFR event class";
}
if (!k->is_linked()) {
if (has_class_failed_verification(k)) {
return warn_excluded(k, "Failed verification");
log_warning = true;
return "Failed verification";
} else if (CDSConfig::is_dumping_aot_linked_classes()) {
// Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds().
// Old classes may not be linked if CDSConfig::is_preserving_verification_constraints()==false.
// An unlinked class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(),
// causing the JVM to fail at bootstrap.
return warn_excluded(k, "Unlinked class not supported by AOTClassLinking");
return "Unlinked class not supported by AOTClassLinking";
} else if (CDSConfig::is_dumping_preimage_static_archive()) {
// When dumping the final static archive, we will unconditionally load and link all
// classes from the preimage. We don't want to get a VerifyError when linking this class.
return warn_excluded(k, "Unlinked class not supported by AOTConfiguration");
return "Unlinked class not supported by AOTConfiguration";
}
} else {
if (!k->can_be_verified_at_dumptime()) {
@@ -447,17 +460,15 @@ bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) {
// won't work at runtime.
// As a result, we cannot store this class. It must be loaded and fully verified
// at runtime.
return warn_excluded(k, "Old class has been linked");
return "Old class has been linked";
}
}
if (UnregisteredClasses::check_for_exclusion(k)) {
ResourceMark rm;
aot_log_info(aot)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string());
return true;
return "used only when dumping CDS archive";
}
return false;
return nullptr;
}
// Returns true if DumpTimeClassInfo::is_excluded() is true for at least one of k's exclusion dependencies.
@@ -511,7 +522,7 @@ bool SystemDictionaryShared::is_dependency_excluded(InstanceKlass* k, InstanceKl
DumpTimeClassInfo* dependency_info = get_info_locked(dependency);
if (dependency_info->is_excluded()) {
ResourceMark rm;
aot_log_warning(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string());
aot_log_info(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string());
return true;
}
return false;
@@ -838,7 +849,7 @@ public:
InstanceKlass* k = _list.at(i);
bool i_am_first = SystemDictionaryShared::add_unregistered_class(_thread, k);
if (!i_am_first) {
SystemDictionaryShared::warn_excluded(k, "Duplicated unregistered class");
SystemDictionaryShared::log_exclusion(k, "Duplicated unregistered class");
SystemDictionaryShared::set_excluded_locked(k);
}
}
@@ -967,7 +978,7 @@ bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) {
}
void SystemDictionaryShared::set_from_class_file_load_hook(InstanceKlass* ik) {
warn_excluded(ik, "From ClassFileLoadHook");
log_exclusion(ik, "From ClassFileLoadHook");
set_excluded(ik);
}
@@ -180,6 +180,7 @@ private:
// exclusion checks
static void check_exclusion_for_self_and_dependencies(InstanceKlass *k);
static bool check_self_exclusion(InstanceKlass* k);
static const char* check_self_exclusion_helper(InstanceKlass* k, bool& log_warning);
static bool check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info);
static bool check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name);
static bool is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type);
@@ -277,7 +278,7 @@ public:
static void set_excluded(InstanceKlass* k);
static void set_excluded_locked(InstanceKlass* k);
static void set_from_class_file_load_hook(InstanceKlass* k) NOT_CDS_RETURN;
static bool warn_excluded(InstanceKlass* k, const char* reason);
static void log_exclusion(InstanceKlass* k, const char* reason, bool is_warning = false);
static void dumptime_classes_do(class MetaspaceClosure* it);
static void write_to_archive(bool is_static_archive = true);
static void serialize_dictionary_headers(class SerializeClosure* soc,
+1 -1
View File
@@ -237,7 +237,7 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) {
// Exclude any classes that are verified with the old verifier, as the old verifier
// doesn't call SystemDictionaryShared::add_verification_constraint()
if (CDSConfig::is_dumping_archive()) {
SystemDictionaryShared::warn_excluded(klass, "Verified with old verifier");
SystemDictionaryShared::log_exclusion(klass, "Verified with old verifier");
SystemDictionaryShared::set_excluded(klass);
}
#endif
+1 -1
View File
@@ -113,7 +113,7 @@ void vmClasses::resolve_until(vmClassID limit_id, vmClassID &start_id, TRAPS) {
}
void vmClasses::resolve_all(TRAPS) {
assert(!Object_klass_loaded(), "well-known classes should only be initialized once");
assert(!Object_klass_is_loaded(), "well-known classes should only be initialized once");
// Create the ModuleEntry for java.base. This call needs to be done here,
// after vmSymbols::initialize() is called but before any classes are pre-loaded.
@@ -102,12 +102,6 @@ public:
assert((uint)t < T_VOID+1, "range check");
return check_klass(_box_klasses[t]);
}
static bool Object_klass_loaded() { return is_loaded(VM_CLASS_AT(Object_klass)); }
static bool Class_klass_loaded() { return is_loaded(VM_CLASS_AT(Class_klass)); }
static bool Cloneable_klass_loaded() { return is_loaded(VM_CLASS_AT(Cloneable_klass)); }
static bool Parameter_klass_loaded() { return is_loaded(VM_CLASS_AT(reflect_Parameter_klass)); }
static bool ClassLoader_klass_loaded() { return is_loaded(VM_CLASS_AT(ClassLoader_klass)); }
};
#endif // SHARE_CLASSFILE_VMCLASSES_HPP
+9
View File
@@ -1080,4 +1080,13 @@ public:
static const Vptr _vpntr;
};
struct NMethodMarkingScope : StackObj {
NMethodMarkingScope() {
nmethod::oops_do_marking_prologue();
}
~NMethodMarkingScope() {
nmethod::oops_do_marking_epilogue();
}
};
#endif // SHARE_CODE_NMETHOD_HPP
+1 -3
View File
@@ -203,9 +203,7 @@ uint G1NUMA::index_for_region(G1HeapRegion* hr) const {
// * G1HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-|
// * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----|
void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) {
if (!is_enabled()) {
return;
}
assert(is_enabled(), "must be, check before");
if (size_in_bytes == 0) {
return;
@@ -96,13 +96,15 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper {
const size_t start_page = (size_t)start_idx * _pages_per_region;
const size_t size_in_pages = num_regions * _pages_per_region;
bool zero_filled = _storage.commit(start_page, size_in_pages);
if (_memory_tag == mtJavaHeap) {
if (should_distribute_across_numa_nodes()) {
for (uint region_index = start_idx; region_index < start_idx + num_regions; region_index++ ) {
void* address = _storage.page_start(region_index * _pages_per_region);
size_t size_in_bytes = _storage.page_size() * _pages_per_region;
G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region_index);
}
}
if (AlwaysPreTouch) {
_storage.pretouch(start_page, size_in_pages, pretouch_workers);
}
@@ -122,7 +124,7 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper {
// G1RegionToSpaceMapper implementation where the region granularity is smaller
// than the commit granularity.
// Basically, the contents of one OS page span several regions.
// Basically, the contents of one OS page spans several regions.
class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
size_t _regions_per_page;
// Lock to prevent bitmap updates and the actual underlying
@@ -148,13 +150,18 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
return _region_commit_map.find_first_set_bit(region, region_limit) != region_limit;
}
void numa_request_on_node(size_t page_idx) {
if (_memory_tag == mtJavaHeap) {
uint region = (uint)(page_idx * _regions_per_page);
void* address = _storage.page_start(page_idx);
size_t size_in_bytes = _storage.page_size();
G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region);
bool commit_pages(size_t start_page, size_t size_in_pages) {
bool result = _storage.commit(start_page, size_in_pages);
if (should_distribute_across_numa_nodes()) {
for (size_t page = start_page; page < start_page + size_in_pages; page++) {
uint region = checked_cast<uint>(page * _regions_per_page);
void* address = _storage.page_start(page);
size_t size_in_bytes = _storage.page_size();
G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region);
}
}
return result;
}
public:
@@ -171,6 +178,21 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity");
}
size_t find_first_uncommitted(size_t page, size_t end) {
assert(page < end, "must be");
while (page < end && is_page_committed(page)) {
page++;
}
return page;
}
size_t find_first_committed(size_t page, size_t end) {
while (page < end && !is_page_committed(page)) {
page++;
}
return MIN2(page, end);
}
virtual void commit_regions(uint start_idx, size_t num_regions, WorkerThreads* pretouch_workers) {
uint region_limit = (uint)(start_idx + num_regions);
assert(num_regions > 0, "Must commit at least one region");
@@ -179,11 +201,11 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
size_t const NoPage = SIZE_MAX;
size_t first_committed = NoPage;
size_t num_committed = 0;
size_t first_newly_committed = NoPage;
size_t num_committed_pages = 0;
size_t start_page = region_idx_to_page_idx(start_idx);
size_t end_page = region_idx_to_page_idx(region_limit - 1);
size_t const start_page = region_idx_to_page_idx(start_idx);
size_t const end_page = region_idx_to_page_idx(region_limit - 1) + 1;
bool all_zero_filled = true;
@@ -191,34 +213,27 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
// underlying OS page. See lock declaration for more details.
{
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
for (size_t page = start_page; page <= end_page; page++) {
if (!is_page_committed(page)) {
// Page not committed.
if (num_committed == 0) {
first_committed = page;
}
num_committed++;
if (!_storage.commit(page, 1)) {
// Found dirty region during commit.
all_zero_filled = false;
}
size_t uncommitted_l = find_first_uncommitted(start_page, end_page);
size_t uncommitted_r = find_first_committed(uncommitted_l + 1, end_page);
// Move memory to correct NUMA node for the heap.
numa_request_on_node(page);
} else {
// Page already committed.
all_zero_filled = false;
}
first_newly_committed = uncommitted_l;
num_committed_pages = uncommitted_r - uncommitted_l;
if (num_committed_pages > 0 &&
!commit_pages(first_newly_committed, num_committed_pages)) {
all_zero_filled = false;
}
all_zero_filled &= (uncommitted_l == start_page) && (uncommitted_r == end_page);
// Update the commit map for the given range. Not using the par_set_range
// since updates to _region_commit_map for this mapper is protected by _lock.
_region_commit_map.set_range(start_idx, region_limit, BitMap::unknown_range);
}
if (AlwaysPreTouch && num_committed > 0) {
_storage.pretouch(first_committed, num_committed, pretouch_workers);
if (AlwaysPreTouch && num_committed_pages > 0) {
_storage.pretouch(first_newly_committed, num_committed_pages, pretouch_workers);
}
fire_on_commit(start_idx, num_regions, all_zero_filled);
@@ -230,8 +245,8 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
assert(_region_commit_map.find_first_clear_bit(start_idx, region_limit) == region_limit,
"Should only be committed regions in the range [%u, %u)", start_idx, region_limit);
size_t start_page = region_idx_to_page_idx(start_idx);
size_t end_page = region_idx_to_page_idx(region_limit - 1);
size_t const start_page = region_idx_to_page_idx(start_idx);
size_t const end_page = region_idx_to_page_idx(region_limit - 1) + 1;
// Concurrent operations might operate on regions sharing the same
// underlying OS page. See lock declaration for more details.
@@ -240,13 +255,16 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
// updates to _region_commit_map for this mapper is protected by _lock.
_region_commit_map.clear_range(start_idx, region_limit, BitMap::unknown_range);
for (size_t page = start_page; page <= end_page; page++) {
// We know all pages were committed before clearing the map. If the
// the page is still marked as committed after the clear we should
// not uncommit it.
if (!is_page_committed(page)) {
_storage.uncommit(page, 1);
}
// We know all pages were committed before clearing the map. If the
// the page is still marked as committed after the clear we should
// not uncommit it.
size_t uncommitted_l = find_first_uncommitted(start_page, end_page);
size_t uncommitted_r = find_first_committed(uncommitted_l + 1, end_page);
size_t num_uncommitted_pages_found = uncommitted_r - uncommitted_l;
if (num_uncommitted_pages_found > 0) {
_storage.uncommit(uncommitted_l, num_uncommitted_pages_found);
}
}
};
@@ -257,6 +275,10 @@ void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions, b
}
}
bool G1RegionToSpaceMapper::should_distribute_across_numa_nodes() const {
return _memory_tag == mtJavaHeap && G1NUMA::numa()->is_enabled();
}
G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs,
size_t actual_size,
size_t page_size,
@@ -58,6 +58,8 @@ class G1RegionToSpaceMapper : public CHeapObj<mtGC> {
G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, size_t commit_factor, MemTag mem_tag);
void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled);
bool should_distribute_across_numa_nodes() const;
public:
MemRegion reserved() { return _storage.reserved(); }
@@ -1660,21 +1660,19 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke
}
class FillDensePrefixAndCompactionTask: public WorkerTask {
uint _num_workers;
TaskTerminator _terminator;
public:
FillDensePrefixAndCompactionTask(uint active_workers) :
WorkerTask("FillDensePrefixAndCompactionTask"),
_num_workers(active_workers),
_terminator(active_workers, ParCompactionManager::region_task_queues()) {
}
virtual void work(uint worker_id) {
{
if (worker_id == 0) {
auto start = Ticks::now();
PSParallelCompact::fill_dead_objs_in_dense_prefix(worker_id, _num_workers);
log_trace(gc, phases)("Fill dense prefix by worker %u: %.3f ms", worker_id, (Ticks::now() - start).seconds() * 1000);
PSParallelCompact::fill_dead_objs_in_dense_prefix();
log_trace(gc, phases)("Fill dense prefix by worker 0: %.3f ms", (Ticks::now() - start).seconds() * 1000);
}
compaction_with_stealing_work(&_terminator, worker_id);
}
@@ -1687,9 +1685,10 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en
assert(mark_bitmap()->find_obj_beg(start, end) == end, "precondition");
HeapWord* bottom = _space_info[old_space_id].space()->bottom();
if (start != bottom) {
// The preceding live obj.
HeapWord* obj_start = mark_bitmap()->find_obj_beg_reverse(bottom, start);
HeapWord* after_obj = obj_start + cast_to_oop(obj_start)->size();
assert(after_obj == start, "precondition");
HeapWord* obj_end = obj_start + cast_to_oop(obj_start)->size();
assert(obj_end == start, "precondition");
}
}
#endif
@@ -1703,58 +1702,51 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en
} while (addr < end);
}
void PSParallelCompact::fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers) {
void PSParallelCompact::fill_dead_objs_in_dense_prefix() {
ParMarkBitMap* bitmap = mark_bitmap();
HeapWord* const bottom = _space_info[old_space_id].space()->bottom();
HeapWord* const prefix_end = dense_prefix(old_space_id);
if (bottom == prefix_end) {
return;
}
const size_t region_size = ParallelCompactData::RegionSize;
size_t bottom_region = _summary_data.addr_to_region_idx(bottom);
size_t prefix_end_region = _summary_data.addr_to_region_idx(prefix_end);
// Fill dead space in [start_addr, end_addr)
HeapWord* const start_addr = bottom;
HeapWord* const end_addr = prefix_end;
size_t start_region;
size_t end_region;
split_regions_for_worker(bottom_region, prefix_end_region,
worker_id, num_workers,
&start_region, &end_region);
for (HeapWord* cur_addr = start_addr; cur_addr < end_addr; /* empty */) {
RegionData* cur_region_ptr = _summary_data.addr_to_region_ptr(cur_addr);
if (cur_region_ptr->data_size() == region_size) {
// Full; no dead space. Next region.
if (_summary_data.is_region_aligned(cur_addr)) {
cur_addr += region_size;
} else {
cur_addr = _summary_data.region_align_up(cur_addr);
}
continue;
}
if (start_region == end_region) {
return;
}
// Fill dead space inside cur_region.
if (_summary_data.is_region_aligned(cur_addr)) {
cur_addr += cur_region_ptr->partial_obj_size();
}
HeapWord* const start_addr = _summary_data.region_to_addr(start_region);
HeapWord* const end_addr = _summary_data.region_to_addr(end_region);
// Skip live partial obj (if any) from previous region.
HeapWord* cur_addr;
RegionData* start_region_ptr = _summary_data.region(start_region);
if (start_region_ptr->partial_obj_size() != 0) {
HeapWord* partial_obj_start = start_region_ptr->partial_obj_addr();
assert(bitmap->is_marked(partial_obj_start), "inv");
cur_addr = partial_obj_start + cast_to_oop(partial_obj_start)->size();
} else {
cur_addr = start_addr;
}
// end_addr is inclusive to handle regions starting with dead space.
while (cur_addr <= end_addr) {
// Use prefix_end to handle trailing obj in each worker region-chunk.
HeapWord* live_start = bitmap->find_obj_beg(cur_addr, prefix_end);
if (cur_addr != live_start) {
// Only worker 0 handles proceeding dead space.
if (cur_addr != start_addr || worker_id == 0) {
HeapWord* region_end_addr = _summary_data.region_align_up(cur_addr + 1);
assert(region_end_addr <= end_addr, "inv");
while (cur_addr < region_end_addr) {
// Use end_addr to allow filler-obj to cross region boundary.
HeapWord* live_start = bitmap->find_obj_beg(cur_addr, end_addr);
if (cur_addr != live_start) {
// Found dead space [cur_addr, live_start).
fill_range_in_dense_prefix(cur_addr, live_start);
}
if (live_start >= region_end_addr) {
cur_addr = live_start;
break;
}
assert(bitmap->is_marked(live_start), "inv");
cur_addr = live_start + cast_to_oop(live_start)->size();
}
if (live_start >= end_addr) {
break;
}
assert(bitmap->is_marked(live_start), "inv");
cur_addr = live_start + cast_to_oop(live_start)->size();
}
}
@@ -1787,15 +1779,38 @@ void PSParallelCompact::compact() {
void PSParallelCompact::verify_filler_in_dense_prefix() {
HeapWord* bottom = _space_info[old_space_id].space()->bottom();
HeapWord* dense_prefix_end = dense_prefix(old_space_id);
HeapWord* cur_addr = bottom;
while (cur_addr < dense_prefix_end) {
oop obj = cast_to_oop(cur_addr);
oopDesc::verify(obj);
if (!mark_bitmap()->is_marked(cur_addr)) {
Klass* k = cast_to_oop(cur_addr)->klass();
assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv");
const size_t region_size = ParallelCompactData::RegionSize;
for (HeapWord* cur_addr = bottom; cur_addr < dense_prefix_end; /* empty */) {
RegionData* cur_region_ptr = _summary_data.addr_to_region_ptr(cur_addr);
if (cur_region_ptr->data_size() == region_size) {
// Full; no dead space. Next region.
if (_summary_data.is_region_aligned(cur_addr)) {
cur_addr += region_size;
} else {
cur_addr = _summary_data.region_align_up(cur_addr);
}
continue;
}
// This region contains filler objs.
if (_summary_data.is_region_aligned(cur_addr)) {
cur_addr += cur_region_ptr->partial_obj_size();
}
HeapWord* region_end_addr = _summary_data.region_align_up(cur_addr + 1);
assert(region_end_addr <= dense_prefix_end, "inv");
while (cur_addr < region_end_addr) {
oop obj = cast_to_oop(cur_addr);
oopDesc::verify(obj);
if (!mark_bitmap()->is_marked(cur_addr)) {
Klass* k = cast_to_oop(cur_addr)->klass();
assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv");
}
cur_addr += obj->size();
}
cur_addr += obj->size();
}
}
@@ -755,7 +755,7 @@ private:
static void fill_range_in_dense_prefix(HeapWord* start, HeapWord* end);
public:
static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers);
static void fill_dead_objs_in_dense_prefix();
// This method invokes a full collection.
// clear_all_soft_refs controls whether soft-refs should be cleared or not.
@@ -807,7 +807,7 @@ void DefNewGeneration::reset_scratch() {
}
}
void DefNewGeneration::gc_epilogue(bool full) {
void DefNewGeneration::gc_epilogue() {
assert(!GCLocker::is_active(), "We should not be executing here");
// update the generation and space performance counters
update_counters();
@@ -187,7 +187,7 @@ class DefNewGeneration: public Generation {
HeapWord* allocate(size_t word_size);
HeapWord* par_allocate(size_t word_size);
void gc_epilogue(bool full);
void gc_epilogue();
// For Old collection (part of running Full GC), the DefNewGeneration can
// contribute the free part of "to-space" as the scratch space.
+8 -6
View File
@@ -54,7 +54,6 @@
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
#include "gc/shared/space.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/universe.hpp"
@@ -483,9 +482,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) {
ref_processor()->start_discovery(clear_all_softrefs);
{
StrongRootsScope srs(0);
MarkingNMethodClosure mark_code_closure(&follow_root_closure);
GCTraceTime(Debug, gc, phases) tm_m("Marking From Roots", gc_timer());
// Start tracing from roots, there are 3 kinds of roots in full-gc.
//
@@ -494,8 +491,13 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) {
// strong CLDs.
ClassLoaderDataGraph::always_strong_cld_do(&follow_cld_closure);
// 2. Threads stack frames and active nmethods in them.
Threads::oops_do(&follow_root_closure, &mark_code_closure);
{
// 2. Threads stack frames and active nmethods in them.
NMethodMarkingScope nmethod_marking_scope;
MarkingNMethodClosure mark_code_closure(&follow_root_closure);
Threads::oops_do(&follow_root_closure, &mark_code_closure);
}
// 3. VM internal roots.
OopStorageSet::strong_oops_do(&follow_root_closure);
+1 -1
View File
@@ -779,7 +779,7 @@ void SerialHeap::gc_epilogue(bool full) {
resize_all_tlabs();
_young_gen->gc_epilogue(full);
_young_gen->gc_epilogue();
_old_gen->gc_epilogue();
if (_is_heap_almost_full) {
@@ -43,7 +43,7 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers)
ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge));
}
_global_age_table = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC);
_global_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC);
CENSUS_NOISE(_global_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, MAX_SNAPSHOTS, mtGC);)
_tenuring_threshold = NEW_C_HEAP_ARRAY(uint, MAX_SNAPSHOTS, mtGC);
CENSUS_NOISE(_skipped = 0);
@@ -52,36 +52,40 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers)
for (int i = 0; i < MAX_SNAPSHOTS; i++) {
// Note that we don't now get perfdata from age_table
_global_age_table[i] = new AgeTable(false);
_global_age_tables[i] = new AgeTable(false);
CENSUS_NOISE(_global_noise[i].clear();)
// Sentinel value
_tenuring_threshold[i] = MAX_COHORTS;
}
if (ShenandoahGenerationalAdaptiveTenuring) {
_local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC);
_local_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC);
CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);)
for (uint i = 0; i < _max_workers; i++) {
_local_age_table[i] = new AgeTable(false);
_local_age_tables[i] = new AgeTable(false);
CENSUS_NOISE(_local_noise[i].clear();)
}
} else {
_local_age_table = nullptr;
_local_age_tables = nullptr;
}
_epoch = MAX_SNAPSHOTS - 1; // see prepare_for_census_update()
if (!ShenandoahGenerationalAdaptiveTenuring) {
_tenuring_threshold[_epoch] = InitialTenuringThreshold;
}
_epoch = MAX_SNAPSHOTS - 1; // see update_epoch()
}
ShenandoahAgeCensus::~ShenandoahAgeCensus() {
for (uint i = 0; i < MAX_SNAPSHOTS; i++) {
delete _global_age_table[i];
delete _global_age_tables[i];
}
FREE_C_HEAP_ARRAY(AgeTable*, _global_age_table);
FREE_C_HEAP_ARRAY(AgeTable*, _global_age_tables);
FREE_C_HEAP_ARRAY(uint, _tenuring_threshold);
CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise));
if (_local_age_table) {
if (_local_age_tables) {
for (uint i = 0; i < _max_workers; i++) {
delete _local_age_table[i];
delete _local_age_tables[i];
}
FREE_C_HEAP_ARRAY(AgeTable*, _local_age_table);
FREE_C_HEAP_ARRAY(AgeTable*, _local_age_tables);
CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise));
}
}
@@ -142,37 +146,31 @@ void ShenandoahAgeCensus::prepare_for_census_update() {
if (++_epoch >= MAX_SNAPSHOTS) {
_epoch=0;
}
_global_age_table[_epoch]->clear();
_global_age_tables[_epoch]->clear();
CENSUS_NOISE(_global_noise[_epoch].clear();)
}
// Update the census data from appropriate sources,
// and compute the new tenuring threshold.
void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable* pv2) {
void ShenandoahAgeCensus::update_census(size_t age0_pop) {
prepare_for_census_update();
assert(_global_age_table[_epoch]->is_clear(), "Dirty decks");
assert(ShenandoahGenerationalAdaptiveTenuring, "Only update census when adaptive tenuring is enabled");
assert(_global_age_tables[_epoch]->is_clear(), "Dirty decks");
CENSUS_NOISE(assert(_global_noise[_epoch].is_clear(), "Dirty decks");)
if (ShenandoahGenerationalAdaptiveTenuring) {
assert(pv1 == nullptr && pv2 == nullptr, "Error, check caller");
// Seed cohort 0 with population that may have been missed during
// regular census.
_global_age_table[_epoch]->add(0u, age0_pop);
// Merge data from local age tables into the global age table for the epoch,
// clearing the local tables.
for (uint i = 0; i < _max_workers; i++) {
// age stats
_global_age_table[_epoch]->merge(_local_age_table[i]);
_local_age_table[i]->clear(); // clear for next census
// Merge noise stats
CENSUS_NOISE(_global_noise[_epoch].merge(_local_noise[i]);)
CENSUS_NOISE(_local_noise[i].clear();)
}
} else {
// census during evac
assert(pv1 != nullptr && pv2 != nullptr, "Error, check caller");
_global_age_table[_epoch]->merge(pv1);
_global_age_table[_epoch]->merge(pv2);
// Seed cohort 0 with population that may have been missed during
// regular census.
_global_age_tables[_epoch]->add(0u, age0_pop);
// Merge data from local age tables into the global age table for the epoch,
// clearing the local tables.
for (uint i = 0; i < _max_workers; i++) {
// age stats
_global_age_tables[_epoch]->merge(_local_age_tables[i]);
_local_age_tables[i]->clear(); // clear for next census
// Merge noise stats
CENSUS_NOISE(_global_noise[_epoch].merge(_local_noise[i]);)
CENSUS_NOISE(_local_noise[i].clear();)
}
update_tenuring_threshold();
@@ -188,7 +186,7 @@ void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable
void ShenandoahAgeCensus::reset_global() {
assert(_epoch < MAX_SNAPSHOTS, "Out of bounds");
for (uint i = 0; i < MAX_SNAPSHOTS; i++) {
_global_age_table[i]->clear();
_global_age_tables[i]->clear();
CENSUS_NOISE(_global_noise[i].clear();)
}
_epoch = MAX_SNAPSHOTS;
@@ -198,11 +196,11 @@ void ShenandoahAgeCensus::reset_global() {
// Reset the local age tables, clearing any partial census.
void ShenandoahAgeCensus::reset_local() {
if (!ShenandoahGenerationalAdaptiveTenuring) {
assert(_local_age_table == nullptr, "Error");
assert(_local_age_tables == nullptr, "Error");
return;
}
for (uint i = 0; i < _max_workers; i++) {
_local_age_table[i]->clear();
_local_age_tables[i]->clear();
CENSUS_NOISE(_local_noise[i].clear();)
}
}
@@ -212,7 +210,7 @@ void ShenandoahAgeCensus::reset_local() {
bool ShenandoahAgeCensus::is_clear_global() {
assert(_epoch < MAX_SNAPSHOTS, "Out of bounds");
for (uint i = 0; i < MAX_SNAPSHOTS; i++) {
bool clear = _global_age_table[i]->is_clear();
bool clear = _global_age_tables[i]->is_clear();
CENSUS_NOISE(clear |= _global_noise[i].is_clear();)
if (!clear) {
return false;
@@ -224,11 +222,11 @@ bool ShenandoahAgeCensus::is_clear_global() {
// Is local census information clear?
bool ShenandoahAgeCensus::is_clear_local() {
if (!ShenandoahGenerationalAdaptiveTenuring) {
assert(_local_age_table == nullptr, "Error");
assert(_local_age_tables == nullptr, "Error");
return true;
}
for (uint i = 0; i < _max_workers; i++) {
bool clear = _local_age_table[i]->is_clear();
bool clear = _local_age_tables[i]->is_clear();
CENSUS_NOISE(clear |= _local_noise[i].is_clear();)
if (!clear) {
return false;
@@ -240,7 +238,7 @@ bool ShenandoahAgeCensus::is_clear_local() {
size_t ShenandoahAgeCensus::get_all_ages(uint snap) {
assert(snap < MAX_SNAPSHOTS, "Out of bounds");
size_t pop = 0;
const AgeTable* pv = _global_age_table[snap];
const AgeTable* pv = _global_age_tables[snap];
for (uint i = 0; i < MAX_COHORTS; i++) {
pop += pv->sizes[i];
}
@@ -260,13 +258,11 @@ void ShenandoahAgeCensus::update_total() {
#endif // !PRODUCT
void ShenandoahAgeCensus::update_tenuring_threshold() {
if (!ShenandoahGenerationalAdaptiveTenuring) {
_tenuring_threshold[_epoch] = InitialTenuringThreshold;
} else {
uint tt = compute_tenuring_threshold();
assert(tt <= MAX_COHORTS, "Out of bounds");
_tenuring_threshold[_epoch] = tt;
}
assert(ShenandoahGenerationalAdaptiveTenuring, "Only update when adaptive tenuring is enabled");
uint tt = compute_tenuring_threshold();
assert(tt <= MAX_COHORTS, "Out of bounds");
_tenuring_threshold[_epoch] = tt;
print();
log_info(gc, age)("New tenuring threshold %zu (min %zu, max %zu)",
(uintx) _tenuring_threshold[_epoch], ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge);
@@ -296,8 +292,8 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() {
const uint prev_epoch = cur_epoch > 0 ? cur_epoch - 1 : markWord::max_age;
// Current and previous population vectors in ring
const AgeTable* cur_pv = _global_age_table[cur_epoch];
const AgeTable* prev_pv = _global_age_table[prev_epoch];
const AgeTable* cur_pv = _global_age_tables[cur_epoch];
const AgeTable* prev_pv = _global_age_tables[prev_epoch];
uint upper_bound = ShenandoahGenerationalMaxTenuringAge;
const uint prev_tt = previous_tenuring_threshold();
if (ShenandoahGenerationalCensusIgnoreOlderCohorts && prev_tt > 0) {
@@ -372,8 +368,8 @@ void ShenandoahAgeCensus::print() {
const uint cur_epoch = _epoch;
const uint prev_epoch = cur_epoch > 0 ? cur_epoch - 1: markWord::max_age;
const AgeTable* cur_pv = _global_age_table[cur_epoch];
const AgeTable* prev_pv = _global_age_table[prev_epoch];
const AgeTable* cur_pv = _global_age_tables[cur_epoch];
const AgeTable* prev_pv = _global_age_tables[prev_epoch];
const uint tt = tenuring_threshold();
@@ -97,8 +97,8 @@ struct ShenandoahNoiseStats {
// once the per-worker data is consolidated into the appropriate population vector
// per minor collection. The _local_age_table is thus C x N, for N GC workers.
class ShenandoahAgeCensus: public CHeapObj<mtGC> {
AgeTable** _global_age_table; // Global age table used for adapting tenuring threshold, one per snapshot
AgeTable** _local_age_table; // Local scratch age tables to track object ages, one per worker
AgeTable** _global_age_tables; // Global age tables used for adapting tenuring threshold, one per snapshot
AgeTable** _local_age_tables; // Local scratch age tables to track object ages, one per worker
#ifdef SHENANDOAH_CENSUS_NOISE
ShenandoahNoiseStats* _global_noise; // Noise stats, one per snapshot
@@ -175,7 +175,7 @@ class ShenandoahAgeCensus: public CHeapObj<mtGC> {
// Return the local age table (population vector) for worker_id.
// Only used in the case of ShenandoahGenerationalAdaptiveTenuring
AgeTable* get_local_age_table(uint worker_id) const {
return _local_age_table[worker_id];
return _local_age_tables[worker_id];
}
// Return the most recently computed tenuring threshold.
@@ -209,11 +209,7 @@ class ShenandoahAgeCensus: public CHeapObj<mtGC> {
// age0_pop is the population of Cohort 0 that may have been missed in
// the regular census during the marking cycle, corresponding to objects
// allocated when the concurrent marking was in progress.
// Optional parameters, pv1 and pv2 are population vectors that together
// provide object census data (only) for the case when
// ShenandoahGenerationalCensusAtEvac. In this case, the age0_pop
// is 0, because the evacuated objects have all had their ages incremented.
void update_census(size_t age0_pop, AgeTable* pv1 = nullptr, AgeTable* pv2 = nullptr);
void update_census(size_t age0_pop);
// Reset the epoch, clearing accumulated census history
// Note: this isn't currently used, but reserved for planned
@@ -201,26 +201,8 @@ void ShenandoahControlThread::run_service() {
heuristics->clear_metaspace_oom();
}
// Commit worker statistics to cycle data
heap->phase_timings()->flush_par_workers_to_cycle();
// Print GC stats for current cycle
{
LogTarget(Info, gc, stats) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
heap->phase_timings()->print_cycle_on(&ls);
if (ShenandoahEvacTracking) {
ShenandoahEvacuationTracker* evac_tracker = heap->evac_tracker();
ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global();
evac_tracker->print_evacuations_on(&ls, &evac_stats.workers, &evac_stats.mutators);
}
}
}
// Commit statistics to globals
heap->phase_timings()->flush_cycle_to_global();
// Manage and print gc stats
heap->process_gc_stats();
// Print Metaspace change following GC (if logging is enabled).
MetaspaceUtils::print_metaspace_change(meta_sizes);
@@ -23,7 +23,6 @@
*
*/
#include "gc/shenandoah/shenandoahAgeCensus.hpp"
#include "gc/shenandoah/shenandoahEvacTracker.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
@@ -44,19 +43,6 @@ ShenandoahEvacuationStats::ShenandoahEvacuations* ShenandoahEvacuationStats::get
return &_old;
}
ShenandoahEvacuationStats::ShenandoahEvacuationStats()
: _use_age_table(!ShenandoahGenerationalAdaptiveTenuring),
_age_table(nullptr) {
if (_use_age_table) {
_age_table = new AgeTable(false);
}
}
AgeTable* ShenandoahEvacuationStats::age_table() const {
assert(_use_age_table, "Don't call");
return _age_table;
}
void ShenandoahEvacuationStats::begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
ShenandoahEvacuations* category = get_category(from, to);
category->_evacuations_attempted++;
@@ -70,31 +56,16 @@ void ShenandoahEvacuationStats::end_evacuation(size_t bytes, ShenandoahAffiliati
category->_bytes_completed += bytes;
}
void ShenandoahEvacuationStats::record_age(size_t bytes, uint age) {
assert(_use_age_table, "Don't call!");
if (age <= markWord::max_age) { // Filter age sentinel.
_age_table->add(age, bytes >> LogBytesPerWord);
}
}
void ShenandoahEvacuationStats::accumulate(const ShenandoahEvacuationStats* other) {
_young.accumulate(other->_young);
_old.accumulate(other->_old);
_promotion.accumulate(other->_promotion);
if (_use_age_table) {
_age_table->merge(other->age_table());
}
}
void ShenandoahEvacuationStats::reset() {
_young.reset();
_old.reset();
_promotion.reset();
if (_use_age_table) {
_age_table->clear();
}
}
void ShenandoahEvacuationStats::ShenandoahEvacuations::print_on(outputStream* st) const {
@@ -112,10 +83,6 @@ void ShenandoahEvacuationStats::print_on(outputStream* st) const {
st->print("Promotion: "); _promotion.print_on(st);
st->print("Old: "); _old.print_on(st);
}
if (_use_age_table) {
_age_table->print_on(st);
}
}
void ShenandoahEvacuationTracker::print_global_on(outputStream* st) {
@@ -125,28 +92,13 @@ void ShenandoahEvacuationTracker::print_global_on(outputStream* st) {
void ShenandoahEvacuationTracker::print_evacuations_on(outputStream* st,
ShenandoahEvacuationStats* workers,
ShenandoahEvacuationStats* mutators) {
if (ShenandoahEvacTracking) {
st->print_cr("Workers: ");
workers->print_on(st);
st->cr();
st->print_cr("Mutators: ");
mutators->print_on(st);
st->cr();
}
ShenandoahHeap* heap = ShenandoahHeap::heap();
if (heap->mode()->is_generational()) {
AgeTable young_region_ages(false);
for (uint i = 0; i < heap->num_regions(); ++i) {
ShenandoahHeapRegion* r = heap->get_region(i);
if (r->is_young()) {
young_region_ages.add(r->age(), r->get_live_data_words());
}
}
st->print("Young regions: ");
young_region_ages.print_on(st);
st->cr();
}
assert(ShenandoahEvacTracking, "Only when evac tracking is enabled");
st->print_cr("Workers: ");
workers->print_on(st);
st->cr();
st->print_cr("Mutators: ");
mutators->print_on(st);
st->cr();
}
class ShenandoahStatAggregator : public ThreadClosure {
@@ -173,15 +125,6 @@ ShenandoahCycleStats ShenandoahEvacuationTracker::flush_cycle_to_global() {
_mutators_global.accumulate(&mutators);
_workers_global.accumulate(&workers);
if (!ShenandoahGenerationalAdaptiveTenuring) {
// Ingest mutator & worker collected population vectors into the heap's
// global census data, and use it to compute an appropriate tenuring threshold
// for use in the next cycle.
// The first argument is used for any age 0 cohort population that we may otherwise have
// missed during the census. This is non-zero only when census happens at marking.
ShenandoahGenerationalHeap::heap()->age_census()->update_census(0, mutators.age_table(), workers.age_table());
}
return {workers, mutators};
}
@@ -192,7 +135,3 @@ void ShenandoahEvacuationTracker::begin_evacuation(Thread* thread, size_t bytes,
void ShenandoahEvacuationTracker::end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
ShenandoahThreadLocalData::end_evacuation(thread, bytes, from, to);
}
void ShenandoahEvacuationTracker::record_age(Thread* thread, size_t bytes, uint age) {
ShenandoahThreadLocalData::record_age(thread, bytes, age);
}
@@ -66,20 +66,12 @@ private:
ShenandoahEvacuations _old;
ShenandoahEvacuations _promotion;
bool _use_age_table;
AgeTable* _age_table;
public:
ShenandoahEvacuationStats();
AgeTable* age_table() const;
// Record that the current thread is attempting to copy this many bytes.
void begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);
// Record that the current thread has completed copying this many bytes.
void end_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);
void record_age(size_t bytes, uint age);
void print_on(outputStream* st) const;
void accumulate(const ShenandoahEvacuationStats* other);
@@ -106,7 +98,6 @@ public:
// Multiple threads may attempt to evacuate the same object, but only the successful thread will end the evacuation.
// Evacuations that were begun, but not ended are considered 'abandoned'.
void end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);
void record_age(Thread* thread, size_t bytes, uint age);
void print_global_on(outputStream* st);
void print_evacuations_on(outputStream* st,
@@ -201,6 +201,24 @@ ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread:
return request.generation->is_old() ? servicing_old : concurrent_normal;
}
void ShenandoahGenerationalControlThread::maybe_print_young_region_ages() const {
LogTarget(Debug, gc, age) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
AgeTable young_region_ages(false);
for (uint i = 0; i < _heap->num_regions(); ++i) {
const ShenandoahHeapRegion* r = _heap->get_region(i);
if (r->is_young()) {
young_region_ages.add(r->age(), r->get_live_data_words());
}
}
ls.print("Young regions: ");
young_region_ages.print_on(&ls);
ls.cr();
}
}
void ShenandoahGenerationalControlThread::maybe_set_aging_cycle() {
if (_age_period-- == 0) {
_heap->set_aging_cycle(true);
@@ -298,7 +316,11 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest
_heap->global_generation()->heuristics()->clear_metaspace_oom();
}
process_phase_timings();
// Manage and print gc stats
_heap->process_gc_stats();
// Print table for young region ages if log is enabled
maybe_print_young_region_ages();
// Print Metaspace change following GC (if logging is enabled).
MetaspaceUtils::print_metaspace_change(meta_sizes);
@@ -317,29 +339,6 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest
gc_mode_name(gc_mode()), GCCause::to_string(request.cause), request.generation->name(), GCCause::to_string(_heap->cancelled_cause()));
}
void ShenandoahGenerationalControlThread::process_phase_timings() const {
// Commit worker statistics to cycle data
_heap->phase_timings()->flush_par_workers_to_cycle();
ShenandoahEvacuationTracker* evac_tracker = _heap->evac_tracker();
ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global();
// Print GC stats for current cycle
{
LogTarget(Info, gc, stats) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
_heap->phase_timings()->print_cycle_on(&ls);
evac_tracker->print_evacuations_on(&ls, &evac_stats.workers,
&evac_stats.mutators);
}
}
// Commit statistics to globals
_heap->phase_timings()->flush_cycle_to_global();
}
// Young and old concurrent cycles are initiated by the regulator. Implicit
// and explicit GC requests are handled by the controller thread and always
// run a global cycle (which is concurrent by default, but may be overridden
@@ -417,7 +416,7 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She
set_gc_mode(bootstrapping_old);
young_generation->set_old_gen_task_queues(old_generation->task_queues());
service_concurrent_cycle(young_generation, request.cause, true);
process_phase_timings();
_heap->process_gc_stats();
if (_heap->cancelled_gc()) {
// Young generation bootstrap cycle has failed. Concurrent mark for old generation
// is going to resume after degenerated bootstrap cycle completes.
@@ -129,9 +129,6 @@ private:
// Returns true if the old generation marking was interrupted to allow a young cycle.
bool preempt_old_marking(ShenandoahGeneration* generation);
// Flushes cycle timings to global timings and prints the phase timings for the last completed cycle.
void process_phase_timings() const;
// Set the gc mode and post a notification if it has changed. The overloaded variant should be used
// when the _control_lock is already held.
void set_gc_mode(GCMode new_mode);
@@ -160,6 +157,9 @@ private:
GCMode prepare_for_allocation_failure_gc(ShenandoahGCRequest &request);
GCMode prepare_for_explicit_gc(ShenandoahGCRequest &request) const;
GCMode prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const;
// Print table for young region ages if log is enabled
void maybe_print_young_region_ages() const;
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP
@@ -360,11 +360,6 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
// When copying to the old generation above, we don't care
// about recording object age in the census stats.
assert(target_gen == YOUNG_GENERATION, "Error");
// We record this census only when simulating pre-adaptive tenuring behavior, or
// when we have been asked to record the census at evacuation rather than at mark
if (!ShenandoahGenerationalAdaptiveTenuring) {
evac_tracker()->record_age(thread, size * HeapWordSize, ShenandoahHeap::get_object_age(copy_val));
}
}
shenandoah_assert_correct(nullptr, copy_val);
return copy_val;
@@ -1441,6 +1441,27 @@ void ShenandoahHeap::print_heap_regions_on(outputStream* st) const {
}
}
void ShenandoahHeap::process_gc_stats() const {
// Commit worker statistics to cycle data
phase_timings()->flush_par_workers_to_cycle();
// Print GC stats for current cycle
LogTarget(Info, gc, stats) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
phase_timings()->print_cycle_on(&ls);
if (ShenandoahEvacTracking) {
ShenandoahCycleStats evac_stats = evac_tracker()->flush_cycle_to_global();
evac_tracker()->print_evacuations_on(&ls, &evac_stats.workers,
&evac_stats.mutators);
}
}
// Commit statistics to globals
phase_timings()->flush_cycle_to_global();
}
size_t ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) const {
assert(start->is_humongous_start(), "reclaim regions starting with the first one");
assert(!start->has_live(), "liveness must be zero");
@@ -206,9 +206,12 @@ public:
void initialize_serviceability() override;
void print_heap_on(outputStream* st) const override;
void print_gc_on(outputStream *st) const override;
void print_gc_on(outputStream* st) const override;
void print_heap_regions_on(outputStream* st) const;
// Flushes cycle timings to global timings and prints the phase timings for the last completed cycle.
void process_gc_stats() const;
void prepare_for_verify() override;
void verify(VerifyOption vo) override;
@@ -135,14 +135,12 @@ inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_next_bit_impl(idx_t
// Get the word containing l_index, and shift out low bits.
idx_t index = to_words_align_down(l_index);
bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index);
if ((cword & 1) != 0) {
// The first bit is similarly often interesting. When it matters
// (density or features of the calling algorithm make it likely
// the first bit is set), going straight to the next clause compares
// poorly with doing this check first; count_trailing_zeros can be
// relatively expensive, plus there is the additional range check.
// But when the first bit isn't set, the cost of having tested for
// it is relatively small compared to the rest of the search.
if ((cword & 0x03) != 0) {
// The first bits (representing weak mark or strong mark) are similarly often interesting. When it matters
// (density or features of the calling algorithm make it likely the first bits are set), going straight to
// the next clause compares poorly with doing this check first; count_trailing_zeros can be relatively expensive,
// plus there is the additional range check. But when the first bits are not set, the cost of having tested for
// them is relatively small compared to the rest of the search.
return l_index;
} else if (cword != 0) {
// Flipped and shifted first word is non-zero.
@@ -166,10 +166,6 @@ public:
data(thread)->_evacuation_stats->end_evacuation(bytes, from, to);
}
static void record_age(Thread* thread, size_t bytes, uint age) {
data(thread)->_evacuation_stats->record_age(bytes, age);
}
static ShenandoahEvacuationStats* evacuation_stats(Thread* thread) {
return data(thread)->_evacuation_stats;
}
+2 -2
View File
@@ -504,7 +504,7 @@ void Universe::genesis(TRAPS) {
// Since some of the old system object arrays have been converted to
// ordinary object arrays, _objectArrayKlass will be loaded when
// SystemDictionary::initialize(CHECK); is run. See the extra check
// for Object_klass_loaded in objArrayKlassKlass::allocate_objArray_klass_impl.
// for Object_klass_is_loaded in ObjArrayKlass::allocate_objArray_klass.
{
Klass* oak = vmClasses::Object_klass()->array_klass(CHECK);
_objectArrayKlass = ObjArrayKlass::cast(oak);
@@ -593,7 +593,7 @@ void Universe::fixup_mirrors(TRAPS) {
// but we cannot do that for classes created before java.lang.Class is loaded. Here we simply
// walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note
// that the number of objects allocated at this point is very small.
assert(vmClasses::Class_klass_loaded(), "java.lang.Class should be loaded");
assert(vmClasses::Class_klass_is_loaded(), "java.lang.Class should be loaded");
HandleMark hm(THREAD);
if (!CDSConfig::is_using_archive()) {
+1 -1
View File
@@ -110,7 +110,7 @@ void CompressedKlassPointers::sanity_check_after_initialization() {
// Check that Klass range is fully engulfed in the encoding range
const address encoding_start = _base;
const address encoding_end = (address)
LP64_ONLY(p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift))
LP64_ONLY((p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift)))
NOT_LP64(max_klass_range_size());
ASSERT_HERE_2(_klass_range_start >= _base && _klass_range_end <= encoding_end,
"Resulting encoding range does not fully cover the class range");
+1 -1
View File
@@ -395,7 +395,7 @@ void ConstantPool::restore_unshareable_info(TRAPS) {
// Only create the new resolved references array if it hasn't been attempted before
if (resolved_references() != nullptr) return;
if (vmClasses::Object_klass_loaded()) {
if (vmClasses::Object_klass_is_loaded()) {
ClassLoaderData* loader_data = pool_holder()->class_loader_data();
#if INCLUDE_CDS_JAVA_HEAP
if (ArchiveHeapLoader::is_in_use() &&
+1 -1
View File
@@ -159,7 +159,7 @@ static inline bool is_class_loader(const Symbol* class_name,
return true;
}
if (vmClasses::ClassLoader_klass_loaded()) {
if (vmClasses::ClassLoader_klass_is_loaded()) {
const Klass* const super_klass = parser.super_klass();
if (super_klass != nullptr) {
if (super_klass->is_subtype_of(vmClasses::ClassLoader_klass())) {
+1 -1
View File
@@ -78,7 +78,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da
// Eagerly allocate the direct array supertype.
Klass* super_klass = nullptr;
if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
if (!Universe::is_bootstrapping() || vmClasses::Object_klass_is_loaded()) {
assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
Klass* element_super = element_klass->super();
if (element_super != nullptr) {
+1 -1
View File
@@ -618,7 +618,7 @@ void CompileTrainingData::verify(bool verify_dep_counter) {
for (int i = 0; i < init_dep_count(); i++) {
KlassTrainingData* ktd = init_dep(i);
if (ktd->has_holder() && ktd->holder()->defined_by_other_loaders()) {
LogStreamHandle(Warning, training) log;
LogStreamHandle(Info, training) log;
if (log.is_enabled()) {
ResourceMark rm;
log.print("CTD "); print_value_on(&log);
+5 -5
View File
@@ -1206,6 +1206,11 @@ static const Type* mod_value(const PhaseGVN* phase, const Node* in1, const Node*
if (t1 == Type::TOP) { return Type::TOP; }
if (t2 == Type::TOP) { return Type::TOP; }
// Mod by zero? Throw exception at runtime!
if (t2 == TypeInteger::zero(bt)) {
return Type::TOP;
}
// We always generate the dynamic check for 0.
// 0 MOD X is 0
if (t1 == TypeInteger::zero(bt)) { return t1; }
@@ -1215,11 +1220,6 @@ static const Type* mod_value(const PhaseGVN* phase, const Node* in1, const Node*
return TypeInteger::zero(bt);
}
// Mod by zero? Throw exception at runtime!
if (t2 == TypeInteger::zero(bt)) {
return Type::TOP;
}
const TypeInteger* i1 = t1->is_integer(bt);
const TypeInteger* i2 = t2->is_integer(bt);
if (i1->is_con() && i2->is_con()) {
@@ -197,6 +197,9 @@ class Abstract_VM_Version: AllStatic {
// Does platform support secondary supers table lookup?
constexpr static bool supports_secondary_supers_table() { return false; }
// Does platform support misaligned vector accesses?
constexpr static bool supports_misaligned_vector_accesses() { return true; }
// Does platform support float16 instructions?
static bool supports_float16() { return false; }
+19 -4
View File
@@ -1161,9 +1161,11 @@ public:
Type _type;
// park blocker or an object the thread waiting on/trying to lock
OopHandle _obj;
// thread that owns park blocker object when park blocker is AbstractOwnableSynchronizer
OopHandle _owner;
Blocker(Type type, OopHandle obj): _type(type), _obj(obj) {}
Blocker(): _type(NOTHING), _obj(nullptr) {}
Blocker(Type type, OopHandle obj): _type(type), _obj(obj), _owner() {}
Blocker(): _type(NOTHING), _obj(), _owner() {}
bool is_empty() const {
return _type == NOTHING;
@@ -1198,6 +1200,7 @@ public:
delete _locks;
}
_blocker._obj.release(oop_storage());
_blocker._owner.release(oop_storage());
}
private:
@@ -1300,6 +1303,13 @@ public:
oop park_blocker = java_lang_Thread::park_blocker(_thread_h());
if (park_blocker != nullptr) {
_blocker = Blocker(Blocker::PARK_BLOCKER, OopHandle(oop_storage(), park_blocker));
if (park_blocker->is_a(vmClasses::java_util_concurrent_locks_AbstractOwnableSynchronizer_klass())) {
// could be stale (unlikely in practice), but it's good enough to see deadlocks
oop ownerObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(park_blocker);
if (ownerObj != nullptr) {
_blocker._owner = OopHandle(oop_storage(), ownerObj);
}
}
}
ResourceMark rm(current);
@@ -1381,6 +1391,7 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic {
static int _locks_offset;
static int _blockerTypeOrdinal_offset;
static int _blockerObject_offset;
static int _parkBlockerOwner_offset;
static void compute_offsets(InstanceKlass* klass, TRAPS) {
JavaClasses::compute_offset(_name_offset, klass, "name", vmSymbols::string_signature(), false);
@@ -1390,6 +1401,7 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic {
JavaClasses::compute_offset(_locks_offset, klass, "locks", vmSymbols::jdk_internal_vm_ThreadLock_array(), false);
JavaClasses::compute_offset(_blockerTypeOrdinal_offset, klass, "blockerTypeOrdinal", vmSymbols::int_signature(), false);
JavaClasses::compute_offset(_blockerObject_offset, klass, "blockerObject", vmSymbols::object_signature(), false);
JavaClasses::compute_offset(_parkBlockerOwner_offset, klass, "parkBlockerOwner", vmSymbols::thread_signature(), false);
}
public:
static void init(InstanceKlass* klass, TRAPS) {
@@ -1420,9 +1432,10 @@ public:
static void set_locks(oop snapshot, oop locks) {
snapshot->obj_field_put(_locks_offset, locks);
}
static void set_blocker(oop snapshot, int type_ordinal, oop lock) {
static void set_blocker(oop snapshot, int type_ordinal, oop lock, oop owner) {
snapshot->int_field_put(_blockerTypeOrdinal_offset, type_ordinal);
snapshot->obj_field_put(_blockerObject_offset, lock);
snapshot->obj_field_put(_parkBlockerOwner_offset, owner);
}
};
@@ -1434,6 +1447,7 @@ int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset;
int jdk_internal_vm_ThreadSnapshot::_locks_offset;
int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset;
int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset;
int jdk_internal_vm_ThreadSnapshot::_parkBlockerOwner_offset;
oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) {
ThreadsListHandle tlh(THREAD);
@@ -1559,7 +1573,8 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) {
jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace());
jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks());
if (!cl._blocker.is_empty()) {
jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve());
jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(),
cl._blocker._type, cl._blocker._obj.resolve(), cl._blocker._owner.resolve());
}
return snapshot();
}
@@ -24,6 +24,7 @@
#include "jvm_io.h"
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
#include "utilities/stringUtils.hpp"
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2025, 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
@@ -84,12 +84,11 @@ import jdk.internal.vm.annotation.AOTSafeClassInitializer;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.BytecodeDescriptor;
import sun.invoke.util.Wrapper;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.repository.ClassRepository;
import sun.reflect.generics.repository.MethodRepository;
import sun.reflect.generics.repository.ConstructorRepository;
import sun.reflect.generics.scope.ClassScope;
import sun.reflect.annotation.*;
@@ -1447,17 +1446,10 @@ public final class Class<T> implements java.io.Serializable,
if (!enclosingInfo.isMethod())
return null;
MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(),
getFactory());
Class<?> returnType = toClass(typeInfo.getReturnType());
Type [] parameterTypes = typeInfo.getParameterTypes();
Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];
// Convert Types to Classes; returned types *should*
// be class objects since the methodDescriptor's used
// don't have generics information
for(int i = 0; i < parameterClasses.length; i++)
parameterClasses[i] = toClass(parameterTypes[i]);
// Descriptor already validated by VM
List<Class<?>> types = BytecodeDescriptor.parseMethod(enclosingInfo.getDescriptor(), getClassLoader());
Class<?> returnType = types.removeLast();
Class<?>[] parameterClasses = types.toArray(EMPTY_CLASS_ARRAY);
final Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
Method[] candidates = enclosingCandidate.privateGetDeclaredMethods(false);
@@ -1576,17 +1568,10 @@ public final class Class<T> implements java.io.Serializable,
if (!enclosingInfo.isConstructor())
return null;
ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
getFactory());
Type [] parameterTypes = typeInfo.getParameterTypes();
Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];
// Convert Types to Classes; returned types *should*
// be class objects since the methodDescriptor's used
// don't have generics information
for (int i = 0; i < parameterClasses.length; i++)
parameterClasses[i] = toClass(parameterTypes[i]);
// Descriptor already validated by VM
List<Class<?>> types = BytecodeDescriptor.parseMethod(enclosingInfo.getDescriptor(), getClassLoader());
types.removeLast();
Class<?>[] parameterClasses = types.toArray(EMPTY_CLASS_ARRAY);
final Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
Constructor<?>[] candidates = enclosingCandidate
@@ -1892,7 +1877,7 @@ public final class Class<T> implements java.io.Serializable,
}
currentClass = currentClass.getSuperclass();
}
return list.toArray(new Class<?>[0]);
return list.toArray(EMPTY_CLASS_ARRAY);
}
@@ -4180,6 +4180,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
if (fitsIntoLong()) {
return Long.toString(longValue(), radix);
}
BigInteger abs = this.abs();
// Ensure buffer capacity sufficient to contain string representation
@@ -5121,12 +5125,16 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @since 1.8
*/
public long longValueExact() {
if (mag.length <= 2 && bitLength() < Long.SIZE)
if (fitsIntoLong())
return longValue();
throw new ArithmeticException("BigInteger out of long range");
}
private boolean fitsIntoLong() {
return mag.length <= 2 && bitLength() < Long.SIZE;
}
/**
* Converts this {@code BigInteger} to an {@code int}, checking
* for lost information. If the value of this {@code BigInteger}
@@ -250,38 +250,43 @@ public final class CompactNumberFormat extends NumberFormat {
/**
* List of positive prefix patterns of this formatter's
* compact number patterns.
* compact number patterns. This field is a read-only
* constant once initialized.
*/
private transient List<Patterns> positivePrefixPatterns;
/**
* List of negative prefix patterns of this formatter's
* compact number patterns.
* compact number patterns. This field is a read-only
* constant once initialized.
*/
private transient List<Patterns> negativePrefixPatterns;
/**
* List of positive suffix patterns of this formatter's
* compact number patterns.
* compact number patterns. This field is a read-only
* constant once initialized.
*/
private transient List<Patterns> positiveSuffixPatterns;
/**
* List of negative suffix patterns of this formatter's
* compact number patterns.
* compact number patterns. This field is a read-only
* constant once initialized.
*/
private transient List<Patterns> negativeSuffixPatterns;
/**
* List of divisors of this formatter's compact number patterns.
* Divisor can be either Long or BigInteger (if the divisor value goes
* beyond long boundary)
* beyond long boundary). This field is a read-only constant
* once initialized.
*/
private transient List<Number> divisors;
/**
* List of place holders that represent minimum integer digits at each index
* for each count.
* for each count. This field is a read-only constant once initialized.
*/
private transient List<Patterns> placeHolderPatterns;
@@ -374,7 +379,7 @@ public final class CompactNumberFormat extends NumberFormat {
/**
* The map for plural rules that maps LDML defined tags (e.g. "one") to
* its rule.
* its rule. This field is a read-only constant once initialized.
*/
private transient Map<String, String> rulesMap;
@@ -1515,7 +1520,7 @@ public final class CompactNumberFormat extends NumberFormat {
}
}
private final transient DigitList digitList = new DigitList();
private transient DigitList digitList = new DigitList();
private static final int STATUS_INFINITE = 0;
private static final int STATUS_POSITIVE = 1;
private static final int STATUS_LENGTH = 2;
@@ -2506,8 +2511,14 @@ public final class CompactNumberFormat extends NumberFormat {
@Override
public CompactNumberFormat clone() {
CompactNumberFormat other = (CompactNumberFormat) super.clone();
// Cloning reference fields. Other fields (e.g., "positivePrefixPatterns")
// are not cloned since they are read-only constants after initialization.
other.compactPatterns = compactPatterns.clone();
other.symbols = (DecimalFormatSymbols) symbols.clone();
other.decimalFormat = (DecimalFormat) decimalFormat.clone();
other.defaultDecimalFormat = (DecimalFormat) defaultDecimalFormat.clone();
other.digitList = (DigitList) digitList.clone();
return other;
}
@@ -46,6 +46,7 @@ import java.nio.charset.StandardCharsets;
import jdk.internal.access.SharedSecrets;
import jdk.internal.math.FloatingDecimal;
import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.Stable;
/**
* Digit List. Private to DecimalFormat.
@@ -108,7 +109,6 @@ final class DigitList implements Cloneable {
public int count = 0;
public byte[] digits = new byte[MAX_COUNT];
private byte[] data;
private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
private boolean isNegative = false;
@@ -320,15 +320,18 @@ final class DigitList implements Cloneable {
* fractional digits to be converted. If false, total digits.
*/
void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
assert Double.isFinite(source);
FloatingDecimal.BinaryToASCIIConverter fdConverter =
FloatingDecimal.getBinaryToASCIIConverter(source, COMPAT);
boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
boolean valueExactAsDecimal = fdConverter.decimalDigitsExact();
assert !fdConverter.isExceptional();
byte[] chars = getDataChars(26);
int len = fdConverter.getChars(chars);
set(isNegative, chars, len,
count = fdConverter.getDigits(digits);
int exp = fdConverter.getDecimalExponent() - count;
set(isNegative, exp,
hasBeenRoundedUp, valueExactAsDecimal,
maximumDigits, fixedPoint);
}
@@ -340,44 +343,18 @@ final class DigitList implements Cloneable {
* @param valueExactAsDecimal whether or not collected digits provide
* an exact decimal representation of the value.
*/
private void set(boolean isNegative, byte[] source, int len,
private void set(boolean isNegative, int exp,
boolean roundedUp, boolean valueExactAsDecimal,
int maximumDigits, boolean fixedPoint) {
this.isNegative = isNegative;
decimalAt = -1;
count = 0;
int exponent = 0;
// Number of zeros between decimal point and first non-zero digit after
// decimal point, for numbers < 1.
int leadingZerosAfterDecimal = 0;
boolean nonZeroDigitSeen = false;
for (int i = 0; i < len; ) {
byte c = source[i++];
if (c == '.') {
decimalAt = count;
} else if (c == 'e' || c == 'E') {
exponent = parseInt(source, i, len);
break;
} else {
if (!nonZeroDigitSeen) {
nonZeroDigitSeen = (c != '0');
if (!nonZeroDigitSeen && decimalAt != -1)
++leadingZerosAfterDecimal;
}
if (nonZeroDigitSeen) {
digits[count++] = c;
}
}
}
if (decimalAt == -1) {
decimalAt = count;
}
if (nonZeroDigitSeen) {
decimalAt += exponent - leadingZerosAfterDecimal;
if (!nonZeroAfterIndex(0)) {
count = 0;
decimalAt = 0;
return;
}
decimalAt = count + exp;
if (fixedPoint) {
// The negative of the exponent represents the number of leading
@@ -669,13 +646,13 @@ final class DigitList implements Cloneable {
*/
@SuppressWarnings("deprecation")
void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
String s = source.toString();
extendDigits(s.length());
String s = source.unscaledValue().toString();
int len = s.length();
byte[] chars = getDataChars(len);
s.getBytes(0, len, chars, 0);
set(isNegative, chars, len,
extendDigits(len);
s.getBytes(0, len, digits, 0);
count = len;
set(isNegative, -source.scale(),
false, true,
maximumDigits, fixedPoint);
}
@@ -745,14 +722,7 @@ final class DigitList implements Cloneable {
public Object clone() {
try {
DigitList other = (DigitList) super.clone();
byte[] newDigits = new byte[digits.length];
System.arraycopy(digits, 0, newDigits, 0, digits.length);
other.digits = newDigits;
// Data does not need to be copied because it does
// not carry significant information. It will be recreated on demand.
// Setting it to null is needed to avoid sharing across clones.
other.data = null;
other.digits = digits.clone();
return other;
} catch (CloneNotSupportedException e) {
@@ -760,29 +730,8 @@ final class DigitList implements Cloneable {
}
}
private static int parseInt(byte[] str, int offset, int strLen) {
byte c;
boolean positive = true;
if ((c = str[offset]) == '-') {
positive = false;
offset++;
} else if (c == '+') {
offset++;
}
int value = 0;
while (offset < strLen) {
c = str[offset++];
if (c >= '0' && c <= '9') {
value = value * 10 + (c - '0');
} else {
break;
}
}
return positive ? value : -value;
}
// The digit part of -9223372036854775808L
@Stable
private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1);
public String toString() {
@@ -798,11 +747,4 @@ final class DigitList implements Cloneable {
digits = new byte[len];
}
}
private byte[] getDataChars(int length) {
if (data == null || data.length < length) {
data = new byte[length];
}
return data;
}
}
@@ -515,12 +515,12 @@ public class Cipher {
* transformation
*
* @throws NoSuchAlgorithmException if {@code transformation}
* is {@code null}, empty, in an invalid format,
* or if no provider supports a {@code CipherSpi}
* implementation for the specified algorithm
* is {@code null}, empty or in an invalid format;
* or if a {@code CipherSpi} implementation is not found or
* is found but does not support the mode
*
* @throws NoSuchPaddingException if {@code transformation}
* contains a padding scheme that is not available
* @throws NoSuchPaddingException if a {@code CipherSpi} implementation
* is found but does not support the padding scheme
*
* @see java.security.Provider
*/
@@ -573,8 +573,12 @@ public class Cipher {
failure = e;
}
}
if (failure instanceof NoSuchPaddingException nspe) {
throw nspe;
}
throw new NoSuchAlgorithmException
("Cannot find any provider supporting " + transformation, failure);
("Cannot find any provider supporting " + transformation,
failure);
}
/**
@@ -582,8 +586,8 @@ public class Cipher {
* transformation.
*
* <p> A new {@code Cipher} object encapsulating the
* {@code CipherSpi} implementation from the specified provider
* is returned. The specified provider must be registered
* {@code CipherSpi} implementation from the specified {@code provider}
* is returned. The specified {@code provider} must be registered
* in the security provider list.
*
* <p> Note that the list of registered providers may be retrieved via
@@ -625,15 +629,16 @@ public class Cipher {
* is {@code null} or empty
*
* @throws NoSuchAlgorithmException if {@code transformation}
* is {@code null}, empty, in an invalid format,
* or if a {@code CipherSpi} implementation for the
* specified algorithm is not available from the specified
* provider
* is {@code null}, empty or in an invalid format;
* or if a {@code CipherSpi} implementation from the specified
* {@code provider} is not found or is found but does not support
* the mode
*
* @throws NoSuchPaddingException if {@code transformation}
* contains a padding scheme that is not available
* @throws NoSuchPaddingException if a {@code CipherSpi} implementation
* from the specified {@code provider} is found but does not
* support the padding scheme
*
* @throws NoSuchProviderException if the specified provider is not
* @throws NoSuchProviderException if the specified {@code provider} is not
* registered in the security provider list
*
* @see java.security.Provider
@@ -706,13 +711,14 @@ public class Cipher {
* is {@code null}
*
* @throws NoSuchAlgorithmException if {@code transformation}
* is {@code null}, empty, in an invalid format,
* or if a {@code CipherSpi} implementation for the
* specified algorithm is not available from the specified
* {@code provider} object
* is {@code null}, empty or in an invalid format;
* or if a {@code CipherSpi} implementation from the specified
* {@code provider} is not found or is found but does not support
* the mode
*
* @throws NoSuchPaddingException if {@code transformation}
* contains a padding scheme that is not available
* @throws NoSuchPaddingException if a {@code CipherSpi} implementation
* from the specified {@code provider} is found but does not
* support the padding scheme
*
* @see java.security.Provider
*/
@@ -115,7 +115,7 @@ public class FloatingDecimal{
* @param digits The digit array.
* @return The number of valid digits copied into the array.
*/
int getDigits(char[] digits);
int getDigits(byte[] digits);
/**
* Indicates the sign of the value.
@@ -173,7 +173,7 @@ public class FloatingDecimal{
}
@Override
public int getDigits(char[] digits) {
public int getDigits(byte[] digits) {
throw new IllegalArgumentException("Exceptional value does not have digits");
}
@@ -255,7 +255,7 @@ public class FloatingDecimal{
}
@Override
public int getDigits(char[] digits) {
public int getDigits(byte[] digits) {
System.arraycopy(this.digits, firstDigitIndex, digits, 0, this.nDigits);
return this.nDigits;
}
@@ -205,7 +205,10 @@ public class ThreadDumper {
// park blocker
Object parkBlocker = snapshot.parkBlocker();
if (parkBlocker != null) {
writer.println(" - parking to wait for " + decorateObject(parkBlocker));
String suffix = (snapshot.parkBlockerOwner() instanceof Thread owner)
? ", owner #" + owner.threadId()
: "";
writer.println(" - parking to wait for " + decorateObject(parkBlocker) + suffix);
}
// blocked on monitor enter or Object.wait
@@ -335,6 +338,9 @@ public class ThreadDumper {
// parkBlocker is an object to allow for exclusiveOwnerThread in the future
jsonWriter.startObject("parkBlocker");
jsonWriter.writeProperty("object", Objects.toIdentityString(parkBlocker));
if (snapshot.parkBlockerOwner() instanceof Thread owner) {
jsonWriter.writeProperty("owner", owner.threadId());
}
jsonWriter.endObject();
}
@@ -44,6 +44,8 @@ class ThreadSnapshot {
// an object the thread is blocked/waiting on, converted to ThreadBlocker by ThreadSnapshot.of()
private int blockerTypeOrdinal;
private Object blockerObject;
// the owner of the blockerObject when the object is park blocker and is AbstractOwnableSynchronizer
private Thread parkBlockerOwner;
// set by ThreadSnapshot.of()
private ThreadBlocker blocker;
@@ -70,8 +72,11 @@ class ThreadSnapshot {
snapshot.locks = EMPTY_LOCKS;
}
if (snapshot.blockerObject != null) {
snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal, snapshot.blockerObject);
snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal,
snapshot.blockerObject,
snapshot.parkBlockerOwner);
snapshot.blockerObject = null; // release
snapshot.parkBlockerOwner = null;
}
return snapshot;
}
@@ -104,6 +109,13 @@ class ThreadSnapshot {
return getBlocker(BlockerLockType.PARK_BLOCKER);
}
/**
* Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer.
*/
Thread parkBlockerOwner() {
return (blocker != null && blocker.type == BlockerLockType.PARK_BLOCKER) ? blocker.owner : null;
}
/**
* Returns the object that the thread is blocked on.
* @throws IllegalStateException if not in the blocked state
@@ -211,11 +223,11 @@ class ThreadSnapshot {
}
}
private record ThreadBlocker(BlockerLockType type, Object obj) {
private record ThreadBlocker(BlockerLockType type, Object obj, Thread owner) {
private static final BlockerLockType[] lockTypeValues = BlockerLockType.values(); // cache
ThreadBlocker(int typeOrdinal, Object obj) {
this(lockTypeValues[typeOrdinal], obj);
ThreadBlocker(int typeOrdinal, Object obj, Thread owner) {
this(lockTypeValues[typeOrdinal], obj, owner);
}
}
@@ -37,12 +37,33 @@ public class BytecodeDescriptor {
private BytecodeDescriptor() { } // cannot instantiate
/**
* @param loader the class loader in which to look up the types (null means
* bootstrap class loader)
*/
public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
/// Parses and validates a field descriptor string in the {@code loader} context.
///
/// @param descriptor a field descriptor string
/// @param loader the class loader in which to look up the types (null means
/// bootstrap class loader)
/// @throws IllegalArgumentException if the descriptor is invalid
/// @throws TypeNotPresentException if the descriptor is valid, but
/// the class cannot be found by the loader
public static Class<?> parseClass(String descriptor, ClassLoader loader) {
int[] i = {0};
var ret = parseSig(descriptor, i, descriptor.length(), loader);
if (i[0] != descriptor.length() || ret == null) {
parseError("not a class descriptor", descriptor);
}
return ret;
}
/// Parses and validates a method descriptor string in the {@code loader} context.
///
/// @param descriptor a method descriptor string
/// @param loader the class loader in which to look up the types (null means
/// bootstrap class loader)
/// @throws IllegalArgumentException if the descriptor is invalid
/// @throws TypeNotPresentException if a reference type cannot be found by
/// the loader (before the descriptor is found invalid)
public static List<Class<?>> parseMethod(String descriptor, ClassLoader loader) {
return parseMethod(descriptor, 0, descriptor.length(), loader);
}
/**
@@ -77,10 +98,19 @@ public class BytecodeDescriptor {
throw new IllegalArgumentException("bad signature: "+str+": "+msg);
}
/**
* @param loader the class loader in which to look up the types (null means
* bootstrap class loader)
*/
/// Parse a single type in a descriptor. Results can be:
///
/// - A `Class` for successful parsing
/// - `null` for malformed descriptor format
/// - Throwing a [TypeNotPresentException] for valid class name,
/// but class cannot be found
///
/// @param str contains the string to parse
/// @param i cursor for the next token in the string, modified in-place
/// @param end the limit for parsing
/// @param loader the class loader in which to look up the types (null means
/// bootstrap class loader)
///
private static Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
if (i[0] == end) return null;
char c = str.charAt(i[0]++);
@@ -107,7 +137,14 @@ public class BytecodeDescriptor {
}
return t;
} else {
return Wrapper.forBasicType(c).primitiveType();
Wrapper w;
try {
w = Wrapper.forBasicType(c);
} catch (IllegalArgumentException ex) {
// Our reporting has better error message
return null;
}
return w.primitiveType();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, 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
@@ -34,12 +34,7 @@ import java.util.function.Supplier;
import jdk.internal.reflect.ConstantPool;
import sun.reflect.generics.parser.SignatureParser;
import sun.reflect.generics.tree.TypeSignature;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.visitor.Reifier;
import sun.reflect.generics.scope.ClassScope;
import sun.invoke.util.BytecodeDescriptor;
/**
* Parser for Java programming language annotations. Translates
@@ -429,19 +424,11 @@ public class AnnotationParser {
}
private static Class<?> parseSig(String sig, Class<?> container) {
if (sig.equals("V")) return void.class;
SignatureParser parser = SignatureParser.make();
TypeSignature typeSig = parser.parseTypeSig(sig);
GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
Reifier reify = Reifier.make(factory);
typeSig.accept(reify);
Type result = reify.getResult();
return toClass(result);
}
static Class<?> toClass(Type o) {
if (o instanceof GenericArrayType gat)
return toClass(gat.getGenericComponentType()).arrayType();
return (Class<?>) o;
try {
return BytecodeDescriptor.parseClass(sig, container.getClassLoader());
} catch (IllegalArgumentException ex) {
throw new GenericSignatureFormatError(ex.getMessage());
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, 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
@@ -801,8 +801,11 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
// buffer this fragment
if (hsf.handshakeType == SSLHandshake.FINISHED.id) {
// Need no status update.
bufferedFragments.add(hsf);
// Make sure it's not a retransmitted message
if (hsf.recordEpoch > handshakeEpoch) {
bufferedFragments.add(hsf);
flightIsReady = holes.isEmpty();
}
} else {
bufferFragment(hsf);
}
@@ -278,8 +278,10 @@ final class SessionTicketExtension {
aad.putInt(keyID).put(compressed);
c.updateAAD(aad);
// use getOutputSize to avoid a ShortBufferException
// from providers that require oversized buffers. See JDK-8368514.
ByteBuffer out = ByteBuffer.allocate(
data.remaining() - GCM_TAG_LEN / 8);
c.getOutputSize(data.remaining()));
c.doFinal(data, out);
out.flip();
@@ -291,7 +293,7 @@ final class SessionTicketExtension {
return out;
} catch (Exception e) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine("Decryption failed." + e.getMessage());
SSLLogger.fine("Decryption failed." + e);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, 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
@@ -41,7 +41,7 @@
/* We should also include jdk_util.h here, for the prototype of JDK_Canonicalize.
This isn't possible though because canonicalize_md.c is as well used in
different contexts within Oracle.
*/
*/
#include "io_util_md.h"
/* Copy bytes to dst, not going past dend; return dst + number of bytes copied,
@@ -139,7 +139,8 @@ lastErrorReportable()
|| (errval == ERROR_ACCESS_DENIED)
|| (errval == ERROR_NETWORK_UNREACHABLE)
|| (errval == ERROR_NETWORK_ACCESS_DENIED)
|| (errval == ERROR_NO_MORE_FILES)) {
|| (errval == ERROR_NO_MORE_FILES)
|| (errval == ERROR_NETNAME_DELETED)) {
return 0;
}
return 1;
@@ -183,7 +184,7 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size)
/* Copy prefix, assuming path is absolute */
c = src[0];
if (((c <= L'z' && c >= L'a') || (c <= L'Z' && c >= L'A'))
&& (src[1] == L':') && (src[2] == L'\\')) {
&& (src[1] == L':') && (src[2] == L'\\')) {
/* Drive specifier */
*src = towupper(*src); /* Canonicalize drive letter */
if (!(dst = wcp(dst, dend, L'\0', src, src + 2))) {
@@ -244,9 +245,9 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size)
continue;
} else {
if (!lastErrorReportable()) {
if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){
goto err;
}
if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){
goto err;
}
break;
} else {
goto err;
@@ -255,7 +256,7 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size)
}
if (dst >= dend) {
errno = ENAMETOOLONG;
errno = ENAMETOOLONG;
goto err;
}
*dst = L'\0';
@@ -366,7 +367,7 @@ JDK_Canonicalize(const char *orig, char *out, int len) {
// Change return value to success.
ret = 0;
finish:
finish:
free(wresult);
free(wpath);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, 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
@@ -457,15 +457,17 @@ static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
}
}
if (positions != NULL) {
CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
CGPoint prev;
prev.x = positions[0];
prev.y = positions[1];
prev = CGPointApplyAffineTransform(prev, invTx);
// <rdar://problem/4294061> take the first point, and move the context to that location
CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);
CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
// for each position, figure out the advance (since CG won't take positions directly)
size_t i;
for (i = 0; i < length - 1; i++)
@@ -476,7 +478,7 @@ static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
pt.y = positions[i2+1];
pt = CGPointApplyAffineTransform(pt, invTx);
advances[i].width = pt.x - prev.x;
advances[i].height = -(pt.y - prev.y); // negative to translate to device space
advances[i].height = pt.y - prev.y;
prev.x = pt.x;
prev.y = pt.y;
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2025, 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
@@ -73,8 +73,8 @@ public class OutlineTextRenderer implements TextPipe {
public void drawString(SunGraphics2D g2d, String str, double x, double y) {
if ("".equals(str)) {
return; // TextLayout constructor throws IAE on "".
if (str.length() == 0) {
return;
}
TextLayout tl = new TextLayout(str, g2d.getFont(),
g2d.getFontRenderContext());
@@ -161,24 +161,7 @@ public class Lint {
values = LintCategory.newEmptySet();
} else {
// otherwise, enable on-by-default categories
values = LintCategory.newEmptySet();
Source source = Source.instance(context);
if (source.compareTo(Source.JDK9) >= 0) {
values.add(LintCategory.DEP_ANN);
}
if (Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source)) {
values.add(LintCategory.STRICTFP);
}
values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC);
values.add(LintCategory.OPENS);
values.add(LintCategory.MODULE);
values.add(LintCategory.REMOVAL);
if (!options.isSet(Option.PREVIEW)) {
values.add(LintCategory.PREVIEW);
}
values.add(LintCategory.IDENTITY);
values.add(LintCategory.INCUBATING);
values = getDefaults();
}
// Look for specific overrides
@@ -193,6 +176,23 @@ public class Lint {
suppressedValues = LintCategory.newEmptySet();
}
// Obtain the set of on-by-default categories. Note that for a few categories,
// whether the category is on-by-default depends on other compiler options.
private EnumSet<LintCategory> getDefaults() {
EnumSet<LintCategory> defaults = LintCategory.newEmptySet();
Source source = Source.instance(context);
Stream.of(LintCategory.values())
.filter(lc ->
switch (lc) {
case DEP_ANN -> source.compareTo(Source.JDK9) >= 0;
case STRICTFP -> Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source);
case PREVIEW -> !options.isSet(Option.PREVIEW);
default -> lc.enabledByDefault;
})
.forEach(defaults::add);
return defaults;
}
@Override
public String toString() {
initializeRootIfNeeded();
@@ -221,7 +221,7 @@ public class Lint {
* <p>
* This category is not supported by {@code @SuppressWarnings}.
*/
CLASSFILE("classfile", false),
CLASSFILE("classfile", false, false),
/**
* Warn about "dangling" documentation comments,
@@ -238,7 +238,7 @@ public class Lint {
* Warn about items which are documented with an {@code @deprecated} JavaDoc
* comment, but which do not have {@code @Deprecated} annotation.
*/
DEP_ANN("dep-ann"),
DEP_ANN("dep-ann", true, true),
/**
* Warn about division by constant integer 0.
@@ -268,7 +268,7 @@ public class Lint {
/**
* Warn about uses of @ValueBased classes where an identity class is expected.
*/
IDENTITY("identity", true, "synchronization"),
IDENTITY("identity", true, true, "synchronization"),
/**
* Warn about use of incubating modules.
@@ -276,7 +276,7 @@ public class Lint {
* <p>
* This category is not supported by {@code @SuppressWarnings}.
*/
INCUBATING("incubating", false),
INCUBATING("incubating", false, true),
/**
* Warn about compiler possible lossy conversions.
@@ -291,12 +291,12 @@ public class Lint {
/**
* Warn about module system related issues.
*/
MODULE("module"),
MODULE("module", true, true),
/**
* Warn about issues regarding module opens.
*/
OPENS("opens"),
OPENS("opens", true, true),
/**
* Warn about issues relating to use of command line options.
@@ -304,7 +304,7 @@ public class Lint {
* <p>
* This category is not supported by {@code @SuppressWarnings}.
*/
OPTIONS("options", false),
OPTIONS("options", false, false),
/**
* Warn when any output file is written to more than once.
@@ -312,7 +312,7 @@ public class Lint {
* <p>
* This category is not supported by {@code @SuppressWarnings}.
*/
OUTPUT_FILE_CLASH("output-file-clash", false),
OUTPUT_FILE_CLASH("output-file-clash", false, false),
/**
* Warn about issues regarding method overloads.
@@ -330,12 +330,15 @@ public class Lint {
* <p>
* This category is not supported by {@code @SuppressWarnings}.
*/
PATH("path", false),
PATH("path", false, false),
/**
* Warn about issues regarding annotation processing.
*
* <p>
* This category is not supported by {@code @SuppressWarnings}.
*/
PROCESSING("processing"),
PROCESSING("processing", false, false),
/**
* Warn about unchecked operations on raw types.
@@ -345,7 +348,7 @@ public class Lint {
/**
* Warn about use of deprecated-for-removal items.
*/
REMOVAL("removal"),
REMOVAL("removal", true, true),
/**
* Warn about use of automatic modules in the requires clauses.
@@ -355,7 +358,7 @@ public class Lint {
/**
* Warn about automatic modules in requires transitive.
*/
REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic"),
REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic", true, true),
/**
* Warn about Serializable classes that do not provide a serial version ID.
@@ -370,7 +373,7 @@ public class Lint {
/**
* Warn about unnecessary uses of the strictfp modifier
*/
STRICTFP("strictfp"),
STRICTFP("strictfp", true, true),
/**
* Warn about issues relating to use of text blocks
@@ -400,7 +403,7 @@ public class Lint {
/**
* Warn about use of preview features.
*/
PREVIEW("preview"),
PREVIEW("preview", true, true),
/**
* Warn about use of restricted methods.
@@ -408,12 +411,13 @@ public class Lint {
RESTRICTED("restricted");
LintCategory(String option) {
this(option, true);
this(option, true, false);
}
LintCategory(String option, boolean annotationSuppression, String... aliases) {
LintCategory(String option, boolean annotationSuppression, boolean enabledByDefault, String... aliases) {
this.option = option;
this.annotationSuppression = annotationSuppression;
this.enabledByDefault = enabledByDefault;
ArrayList<String> optionList = new ArrayList<>(1 + aliases.length);
optionList.add(option);
Collections.addAll(optionList, aliases);
@@ -450,6 +454,12 @@ public class Lint {
/** Does this category support being suppressed by the {@code @SuppressWarnings} annotation? */
public final boolean annotationSuppression;
/**
* Is this category included in the default set of enabled lint categories?
* Note that for some categories, command line options can alter this at runtime.
*/
public final boolean enabledByDefault;
}
/**
@@ -39,10 +39,12 @@ import java.util.Comparator;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -484,24 +486,54 @@ public enum Option {
},
HELP_LINT("--help-lint", "opt.help.lint", EXTENDED, INFO) {
private final String LINT_KEY_FORMAT = SMALL_INDENT + SMALL_INDENT + "%-" +
private final String HELP_INDENT = SMALL_INDENT + SMALL_INDENT;
private final String LINT_KEY_FORMAT = HELP_INDENT + "%-" +
(DEFAULT_SYNOPSIS_WIDTH - LARGE_INDENT.length()) + "s %s";
@Override
public void process(OptionHelper helper, String option) throws InvalidValueException {
Log log = helper.getLog();
// Print header
log.printRawLines(WriterKind.STDOUT, log.localize(PrefixKind.JAVAC, "opt.help.lint.header"));
// Print "all" option
log.printRawLines(WriterKind.STDOUT,
String.format(LINT_KEY_FORMAT,
LINT_CUSTOM_ALL,
log.localize(PrefixKind.JAVAC, "opt.Xlint.all")));
LintCategory.options().forEach(ident -> log.printRawLines(WriterKind.STDOUT,
String.format(LINT_KEY_FORMAT,
ident,
log.localize(PrefixKind.JAVAC, "opt.Xlint.desc." + ident))));
// Alphabetize all the category names and their aliases together, and then list them with their descriptions
TreeMap<String, String> keyMap = new TreeMap<>();
Stream.of(LintCategory.values()).forEach(lc ->
lc.optionList.stream()
.forEach(key -> keyMap.put(key,
String.format(LINT_KEY_FORMAT,
key,
key.equals(lc.option) ?
log.localize(PrefixKind.JAVAC, "opt.Xlint.desc." + key) :
log.localize(PrefixKind.JAVAC, "opt.Xlint.alias.of", lc.option, key)))));
keyMap.values().forEach(desc -> log.printRawLines(WriterKind.STDOUT, desc));
// Print "none" option
log.printRawLines(WriterKind.STDOUT,
String.format(LINT_KEY_FORMAT,
LINT_CUSTOM_NONE,
log.localize(PrefixKind.JAVAC, "opt.Xlint.none")));
// Show which lint categories are enabled by default
log.printRawLines(WriterKind.STDOUT, log.localize(PrefixKind.JAVAC, "opt.help.lint.enabled.by.default"));
String defaults = Stream.of(LintCategory.values())
.filter(lc -> lc.enabledByDefault)
.map(lc -> lc.option)
.sorted()
.collect(Collectors.joining(", "));
log.printRawLines(WriterKind.STDOUT,
String.format("%s%s.", HELP_INDENT, defaults));
// Add trailing blurb about aliases
List<String> aliasExample = LintCategory.IDENTITY.optionList;
log.printRawLines(WriterKind.STDOUT,
log.localize(PrefixKind.JAVAC, "opt.help.lint.footer", aliasExample.get(0), aliasExample.get(1)));
super.process(helper, option);
}
},
@@ -168,18 +168,20 @@ javac.opt.Xbootclasspath.p=\
javac.opt.Xbootclasspath.a=\
Append to the bootstrap class path
javac.opt.Xlint=\
Enable recommended warning categories
Enable recommended lint warning categories. In this release, all\n\
available lint warning categories are recommended.
javac.opt.Xlint.all=\
Enable all warning categories
Enable all lint warning categories
javac.opt.Xlint.none=\
Disable all warning categories
Disable all lint warning categories
#L10N: do not localize: -Xlint
javac.opt.arg.Xlint=\
<key>(,<key>)*
javac.opt.Xlint.custom=\
Warning categories to enable or disable, separated by comma.\n\
Precede a key by ''-'' to disable the specified warning.\n\
Use --help-lint to see the supported keys.
Lint warning categories to enable or disable, separated by comma.\n\
Precede a key by ''-'' to disable the specified category. Use\n\
''--help-lint'' to show supported keys and which categories are\n\
enabled by default.
javac.opt.Xlint.desc.auxiliaryclass=\
Warn about an auxiliary class that is hidden in a source file, and is used from other files.
@@ -291,16 +293,13 @@ javac.opt.Xlint.desc.preview=\
javac.opt.Xlint.desc.restricted=\
Warn about use of restricted methods.
# L10N: do not localize: identity synchronization
javac.opt.Xlint.desc.synchronization=\
Warn about synchronization attempts on instances of value-based classes.\n\
\ This key is a deprecated alias for ''identity'', which has the same uses and\n\
\ effects. Users are encouraged to use the ''identity'' category for all future\n\
\ and existing uses of ''synchronization''.
javac.opt.Xlint.desc.identity=\
Warn about uses of value-based classes where an identity class is expected.
javac.opt.Xlint.alias.of=\
Deprecated alias for ''{0}'' with an identical effect. Users are encouraged to use\n\
\ ''{0}'' instead of ''{1}'' for all current and future uses.
javac.opt.Xdoclint=\
Enable recommended checks for problems in javadoc comments
# L10N: do not localize: all none
@@ -334,6 +333,11 @@ javac.opt.help.lint=\
Print the supported keys for -Xlint
javac.opt.help.lint.header=\
The supported keys for -Xlint are:
javac.opt.help.lint.enabled.by.default=\
The following lint warning categories are enabled by default:
javac.opt.help.lint.footer=\
Categories and their aliases can be used interchangeably; for example, the flag\n\
''-Xlint:{0},{1}'' would be redundant.
javac.opt.print=\
Print out a textual representation of specified types
javac.opt.printRounds=\
@@ -346,8 +350,9 @@ javac.opt.userpathsfirst=\
javac.opt.prefer=\
Specify which file to read when both a source file and class file\n\
are found for an implicitly compiled class
# L10N: do not localize: ''preview''
javac.opt.preview=\
Enable preview language features.\n\
Enable preview language features. Also disables the ''preview'' lint category.\n\
To be used in conjunction with either -source or --release.
javac.opt.AT=\
Read options and filenames from file
+25 -10
View File
@@ -141,7 +141,8 @@ import javax.tools.StandardLocation;
*
* In addition, <em>javac</em> also supports other strings that can be used
* to suppress other kinds of warnings. The following table lists all the
* strings that can be used with {@code @SuppressWarnings}.
* strings that are recognized by <em>javac</em> in {@code @SuppressWarnings}
* annotations. Unrecognized strings are ignored.
*
* <table class="striped">
* <caption>Strings supported by {@code SuppressWarnings}</caption>
@@ -152,7 +153,6 @@ import javax.tools.StandardLocation;
* <tr><th scope="row">{@code auxiliaryclass} <td>an auxiliary class that is hidden in a source file, and is used
* from other files
* <tr><th scope="row">{@code cast} <td>use of unnecessary casts
* <tr><th scope="row">{@code classfile} <td>issues related to classfile contents
* <tr><th scope="row">{@code dangling-doc-comments} <td>issues related to "dangling" documentation comments,
* not attached to a declaration
* <tr><th scope="row">{@code deprecation} <td>use of deprecated items
@@ -165,7 +165,6 @@ import javax.tools.StandardLocation;
* the next
* <tr><th scope="row">{@code finally} <td>{@code finally} clauses that do not terminate normally
* <tr><th scope="row">{@code identity} <td>use of a value-based class where an identity class is expected
* <tr><th scope="row">{@code incubating} <td>use of incubating modules
* <tr><th scope="row">{@code lossy-conversions} <td>possible lossy conversions in compound assignment
* <tr><th scope="row">{@code missing-explicit-ctor} <td>missing explicit constructors in public and protected classes
* in exported packages
@@ -173,13 +172,12 @@ import javax.tools.StandardLocation;
* <tr><th scope="row">{@code opens} <td>issues regarding module opens
* <tr><th scope="row">{@code overloads} <td>issues regarding method overloads
* <tr><th scope="row">{@code overrides} <td>issues regarding method overrides
* <tr><th scope="row">{@code path} <td>invalid path elements on the command line
* <tr><th scope="row">{@code preview} <td>use of preview language features
* <tr><th scope="row">{@code rawtypes} <td>use of raw types
* <tr><th scope="row">{@code removal} <td>use of API that has been marked for removal
* <tr><th scope="row">{@code restricted} <td>use of restricted methods
* <tr><th scope="row">{@code requires-automatic} <td>use of automatic modules in the {@code requires} clauses
* <tr><th scope="row">{@code requires-transitive-automatic} <td>automatic modules in {@code requires transitive}
* <tr><th scope="row">{@code restricted} <td>use of restricted methods
* <tr><th scope="row">{@code serial} <td>{@link java.base/java.io.Serializable Serializable} classes
* that do not have a {@code serialVersionUID} field, or other
* suspect declarations in {@code Serializable} and
@@ -187,11 +185,9 @@ import javax.tools.StandardLocation;
* and interfaces
* <tr><th scope="row">{@code static} <td>accessing a static member using an instance
* <tr><th scope="row">{@code strictfp} <td>unnecessary use of the {@code strictfp} modifier
* <tr><th scope="row">{@code synchronization} <td>synchronization attempts on instances of value-based classes;
* this key is a deprecated alias for {@code identity}, which has
* the same uses and effects. Users are encouraged to use the
* {@code identity} category for all future and existing uses of
* {@code synchronization}
* <tr><th scope="row">{@code synchronization} <td>deprecated alias for {@code identity} with an identical effect.
* Users are encouraged to use {@code identity} instead of
* {@code synchronization} for all current and future uses.
* <tr><th scope="row">{@code text-blocks} <td>inconsistent white space characters in text block indentation
* <tr><th scope="row">{@code this-escape} <td>superclass constructor leaking {@code this} before subclass initialized
* <tr><th scope="row">{@code try} <td>issues relating to use of {@code try} blocks
@@ -207,6 +203,25 @@ import javax.tools.StandardLocation;
* </tbody>
* </table>
*
* All of the non-{@code docllint:} strings listed above may also be used with the {@code -Xlint} command line flag.
* The {@code -Xlint} flag also supports these strings not supported by {@code @SuppressWarnings}:
*
* <table class="striped">
* <caption>Strings supported by {@code -Xlint} but not {@code SuppressWarnings}</caption>
* <thead>
* <tr><th>String<th>Warnings Related To ...
* </thead>
* <tbody>
* <tr><th scope="row">{@code classfile} <td>issues related to classfile contents
* <tr><th scope="row">{@code incubating} <td>use of incubating modules
* <tr><th scope="row">{@code options} <td>issues relating to use of command line options
* <tr><th scope="row">{@code output-file-clash} <td>output files being overwritten due to filename clashes
* <tr><th scope="row">{@code path} <td>invalid path elements on the command line
* <tr><th scope="row">{@code processing} <td>issues regarding annotation processing
* <tr><th scope="row">{@code restricted} <td>use of restricted methods
* </tbody>
* </table>
*
* @toolGuide javac
*
* @provides java.util.spi.ToolProvider
+15 -12
View File
@@ -208,8 +208,8 @@ file system locations may be directories, JAR files or JMOD files.
`-deprecation` option is shorthand for `-Xlint:deprecation`.
<a id="option-enable-preview">`--enable-preview`</a>
: Enables preview language features. Used in conjunction with either
[`-source`](#option-source) or [`--release`](#option-release).
: Enables preview language features. Also disables the `preview` lint category.
Used in conjunction with either [`-source`](#option-source) or [`--release`](#option-release).
<a id="option-encoding">`-encoding` *encoding*</a>
: Specifies character encoding used by source files, such as EUC-JP and
@@ -557,11 +557,11 @@ file system locations may be directories, JAR files or JMOD files.
section of the `javadoc` command documentation.
<a id="option-Xlint">`-Xlint`</a>
: Enables all recommended warnings. In this release, enabling all available
warnings is recommended.
: Enables recommended lint warning categories. In this release, all available
lint warning categories are recommended.
<a id="option-Xlint-custom">`-Xlint:`\[`-`\]*key*(`,`\[`-`\]*key*)\*</a>
: Enables and/or disables warning categories using the one or more of the keys described
: Enables and/or disables lint warning categories using the one or more of the keys described
below separated by commas. The keys `all` and `none` enable or disable all categories
(respectively); other keys enable the corresponding category, or disable it if preceded
by a hyphen (`-`).
@@ -648,10 +648,9 @@ file system locations may be directories, JAR files or JMOD files.
- `strictfp`: Warns about unnecessary use of the `strictfp` modifier.
- `synchronization`: Warns about synchronization attempts on instances
of value-based classes. This key is a deprecated alias for `identity`,
which has the same uses and effects. Users are encouraged to use the
`identity` category for all future and existing uses of `synchronization`.
- `synchronization`: Deprecated alias for `identity` with an identical
effect. Users are encouraged to use `identity` instead of `synchronization`
for all current and future uses.
- `text-blocks`: Warns about inconsistent white space characters in text
block indentation.
@@ -667,9 +666,13 @@ file system locations may be directories, JAR files or JMOD files.
- `none`: Disables all warning categories.
With the exception of `all` and `none`, the keys can be used with
the `@SuppressWarnings` annotation to suppress warnings in a part
of the source code being compiled.
The keys listed above may be used in `@SuppressWarnings` annotations to suppress
warnings within the annotated declaration, with the exception of: `all`, `none`,
`classfile`, `incubating`, `options`, `output-file-clash`, `processing`, and `path`.
By default, the following lint warning categories are enabled: `dep-ann`, `identity`,
`incubating`, `module`, `opens`, `preview`, `removal`, `requires-transitive-automatic`,
and `strictfp`.
See [Examples of Using -Xlint keys].
@@ -1,164 +0,0 @@
/*
* Copyright (c) 2003, 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.
*
*/
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.tools.*;
import sun.jvm.hotspot.utilities.*;
/**
We don't run any of the "standard" SA command line tools for sanity
check. This is because the standard tools print addresses in hex
which could change legally. Also, textual comparison of output may
not match because of other reasons as well. This tool checks
validity of threads and frames logically. This class has reference
frame names from "known" threads. The debuggee is assumed to run
"LibprocTest.java".
*/
public class LibprocClient extends Tool {
public void run() {
// try to get VM version and check
String version = VM.getVM().getVMRelease();
Assert.that(version.startsWith("1.5"), "1.5 expected");
// try getting threads
Threads threads = VM.getVM().getThreads();
boolean mainTested = false;
// check frames of each thread
for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) {
if (cur.isJavaThread()) {
String name = cur.getThreadName();
// testing of basic frame walking for all threads
for (JavaVFrame vf = getLastJavaVFrame(cur); vf != null; vf = vf.javaSender()) {
checkFrame(vf);
}
// special testing for "known" threads. For now, only "main" thread.
if (name.equals("main")) {
checkMainThread(cur);
mainTested = true;
}
}
}
Assert.that(mainTested, "main thread missing");
}
public static void main(String[] args) {
try {
LibprocClient lc = new LibprocClient();
lc.start(args);
lc.getAgent().detach();
System.out.println("\nPASSED\n");
} catch (Exception exp) {
System.out.println("\nFAILED\n");
exp.printStackTrace();
}
}
// -- Internals only below this point
private static JavaVFrame getLastJavaVFrame(JavaThread cur) {
RegisterMap regMap = cur.newRegisterMap(true);
Frame f = cur.getCurrentFrameGuess();
if (f == null) {
System.err.println(" (Unable to get a top most frame)");
return null;
}
VFrame vf = VFrame.newVFrame(f, regMap, cur, true, true);
if (vf == null) {
System.err.println(" (Unable to create vframe for topmost frame guess)");
return null;
}
if (vf.isJavaFrame()) {
return (JavaVFrame) vf;
}
return (JavaVFrame) vf.javaSender();
}
private void checkMethodSignature(Symbol sig) {
SignatureIterator itr = new SignatureIterator(sig) {
public void doBool () {}
public void doChar () {}
public void doFloat () {}
public void doDouble() {}
public void doByte () {}
public void doShort () {}
public void doInt () {}
public void doLong () {}
public void doVoid () {}
public void doObject(int begin, int end) {}
public void doArray (int begin, int end) {}
};
// this will throw RuntimeException for any invalid item in signature.
itr.iterate();
}
private void checkBCI(Method m, int bci) {
if (! m.isNative()) {
byte[] buf = m.getByteCode();
Assert.that(bci >= 0 && bci < buf.length, "invalid bci, not in code range");
if (m.hasLineNumberTable()) {
int lineNum = m.getLineNumberFromBCI(bci);
Assert.that(lineNum >= 0, "expecting non-negative line number");
}
}
}
private void checkMethodHolder(Method method) {
Klass klass = method.getMethodHolder();
Assert.that(klass != null, "expecting non-null instance klass");
}
private void checkFrame(JavaVFrame vf) {
Method method = vf.getMethod();
Assert.that(method != null, "expecting a non-null method here");
Assert.that(method.getName() != null, "expecting non-null method name");
checkMethodHolder(method);
checkMethodSignature(method.getSignature());
checkBCI(method, vf.getBCI());
}
// from the test case LibprocTest.java - in the main thread we
// should see frames as below
private static String[] mainThreadMethods = new String[] {
"java.lang.Object.wait(long)",
"java.lang.Object.wait()",
"LibprocTest.main(java.lang.String[])"
};
private void checkMainThread(JavaThread thread) {
checkFrames(thread, mainThreadMethods);
}
private void checkFrames(JavaThread thread, String[] expectedMethodNames) {
int i = 0;
for (JavaVFrame vf = getLastJavaVFrame(thread); vf != null; vf = vf.javaSender(), i++) {
Method m = vf.getMethod();
Assert.that(m.externalNameAndSignature().equals(expectedMethodNames[i]),
"expected frame missing");
}
}
}
@@ -1,30 +0,0 @@
#
# 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
# 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.
#
#
all:
javac LibprocTest.java
javac -classpath ../../build/classes LibprocClient.java
clean:
rm -rf *.class
-42
View File
@@ -1,42 +0,0 @@
#
# Copyright (c) 2007, 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.
#
#
After making any changes to libproc.so, the shell scripts described
below can be run to verify that it does not break Java Serviceability
Agent.
Setup:
You need to have jdk 1.5 installed to run this test. Set environment
variable SA_JAVA to point to the java executable of jdk
1.5. Otherwise, the script picks-up 'java' from PATH.
Running the tests:
run libproctest.sh (32-bit debuggee) and libproctest64.sh (64-bit
debuggee)
Interpreting result:
"PASSED" or "FAILED" is printed in standard output.
@@ -1,66 +0,0 @@
#!/bin/ksh
#
# Copyright (c) 2003, 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.
#
#
# This script is used to run consistency check of Serviceabilty Agent
# after making any libproc.so changes. Prints "PASSED" or "FAILED" in
# standard output.
usage() {
echo "usage: $0"
echo " set SA_JAVA to be java executable from JDK 1.5"
exit 1
}
STARTDIR=`dirname $0`
if [ "$1" == "-help" ]; then
usage
fi
if [ "x$SA_JAVA" = "x" ]; then
SA_JAVA=java
fi
# create java process with test case
tmp=/tmp/libproctest
rm -f $tmp
$SA_JAVA -classpath $STARTDIR LibprocTest > $tmp &
pid=$!
while [ ! -s $tmp ] ; do
# Kludge alert!
sleep 2
done
# dump core
gcore $pid
kill -9 $pid
# run libproc client
$SA_JAVA -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid
# delete core
rm -f core.$pid
@@ -1,65 +0,0 @@
#!/bin/ksh
#
# Copyright (c) 2003, 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.
#
#
# This script is used to run consistency check of Serviceabilty Agent
# after making any libproc.so changes. Prints "PASSED" or "FAILED" in
# standard output.
usage() {
echo "usage: $0"
echo " set SA_JAVA to be the java executable from JDK 1.5"
exit 1
}
if [ "$1" == "-help" ]; then
usage
fi
if [ "x$SA_JAVA" = "x" ]; then
SA_JAVA=java
fi
STARTDIR=`dirname $0`
# create java process with test case
tmp=/tmp/libproctest
rm -f $tmp
$SA_JAVA -d64 -classpath $STARTDIR LibprocTest > $tmp &
pid=$!
while [ ! -s $tmp ] ; do
# Kludge alert!
sleep 2
done
# dump core
gcore $pid
kill -9 $pid
# run libproc client
$SA_JAVA -d64 -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid
# delete core
rm -f core.$pid
@@ -222,6 +222,16 @@ public final class Float16
*/
public static final int BYTES = SIZE / Byte.SIZE;
/**
* The overflow threshold (for round to nearest) is MAX_VALUE + 1/2 ulp.
*/
private static final double OVERFLOW_THRESH = 0x1.ffcp15 + 0x0.002p15;
/**
* The underflow threshold (for round to nearest) is MIN_VALUE * 0.5.
*/
private static final double UNDERFLOW_THRESH = 0x1.0p-24d * 0.5d;
/**
* Returns a string representation of the {@code Float16}
* argument.
@@ -340,51 +350,51 @@ public final class Float16
* @param d a {@code double}
*/
public static Float16 valueOf(double d) {
long doppel = Double.doubleToRawLongBits(d);
short sign_bit = (short)((doppel & 0x8000_0000_0000_0000L) >> 48);
if (Double.isNaN(d)) {
// Have existing float code handle any attempts to
// preserve NaN bits.
return valueOf((float)d);
}
long doppel = Double.doubleToRawLongBits(d);
short sign_bit = (short)((doppel & 0x8000_0000_0000_0000L) >> (64 - 16));
double abs_d = Math.abs(d);
// The overflow threshold is binary16 MAX_VALUE + 1/2 ulp
if (abs_d >= (0x1.ffcp15 + 0x0.002p15) ) {
if (abs_d >= OVERFLOW_THRESH) {
// correctly signed infinity
return new Float16((short)(sign_bit | 0x7c00));
}
// Smallest magnitude nonzero representable binary16 value
// is equal to 0x1.0p-24; half-way and smaller rounds to zero.
if (abs_d <= 0x1.0p-24d * 0.5d) { // Covers double zeros and subnormals.
return new Float16(sign_bit); // Positive or negative zero
if (abs_d <= UNDERFLOW_THRESH) { // Covers double zeros and subnormals.
// positive or negative zero
return new Float16(sign_bit);
}
// Dealing with finite values in exponent range of binary16
// (when rounding is done, could still round up)
int exp = Math.getExponent(d);
assert -25 <= exp && exp <= 15;
assert
(MIN_EXPONENT - PRECISION) <= exp &&
exp <= MAX_EXPONENT;
// For binary16 subnormals, beside forcing exp to -15, retain
// the difference expdelta = E_min - exp. This is the excess
// shift value, in addition to 42, to be used in the
// For target format subnormals, beside forcing exp to
// MIN_EXPONENT-1, retain the difference expdelta = E_min -
// exp. This is the excess shift value, in addition to the
// difference in precision bits, to be used in the
// computations below. Further the (hidden) msb with value 1
// in d must be involved as well.
int expdelta = 0;
long msb = 0x0000_0000_0000_0000L;
if (exp < -14) {
expdelta = -14 - exp; // FIXME?
exp = -15;
msb = 0x0010_0000_0000_0000L; // should be 0x0020_... ?
if (exp < MIN_EXPONENT) {
expdelta = MIN_EXPONENT - exp;
exp = MIN_EXPONENT - 1;
msb = 0x0010_0000_0000_0000L;
}
long f_signif_bits = doppel & 0x000f_ffff_ffff_ffffL | msb;
int PRECISION_DIFF = Double.PRECISION - PRECISION; // 42
// Significand bits as if using rounding to zero (truncation).
short signif_bits = (short)(f_signif_bits >> (42 + expdelta));
short signif_bits = (short)(f_signif_bits >> (PRECISION_DIFF + expdelta));
// For round to nearest even, determining whether or not to
// round up (in magnitude) is a function of the least
@@ -399,9 +409,9 @@ public final class Float16
// 1 1 1
// See "Computer Arithmetic Algorithms," Koren, Table 4.9
long lsb = f_signif_bits & (1L << 42 + expdelta);
long round = f_signif_bits & (1L << 41 + expdelta);
long sticky = f_signif_bits & ((1L << 41 + expdelta) - 1);
long lsb = f_signif_bits & (1L << (PRECISION_DIFF + expdelta));
long round = f_signif_bits & (1L << (PRECISION_DIFF - 1) + expdelta);
long sticky = f_signif_bits & ((1L << (PRECISION_DIFF - 1) + expdelta) - 1);
if (round != 0 && ((lsb | sticky) != 0 )) {
signif_bits++;
@@ -412,7 +422,9 @@ public final class Float16
// to implement a carry out from rounding the significand.
assert (0xf800 & signif_bits) == 0x0;
return new Float16((short)(sign_bit | ( ((exp + 15) << 10) + signif_bits ) ));
// Exponent bias adjust in the representation is equal to MAX_EXPONENT.
return new Float16((short)(sign_bit |
( ((exp + MAX_EXPONENT) << (PRECISION - 1)) + signif_bits ) ));
}
/**
@@ -31,6 +31,7 @@ import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
@@ -67,7 +68,7 @@ final class DesktopIntegration extends ShellCustomAction {
private static final List<String> REPLACEMENT_STRING_IDS = List.of(
COMMANDS_INSTALL, COMMANDS_UNINSTALL, SCRIPTS, COMMON_SCRIPTS);
private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) throws IOException {
private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) {
associations = launcher.fileAssociations().stream().map(
LinuxFileAssociation::create).toList();
@@ -88,10 +89,14 @@ final class DesktopIntegration extends ShellCustomAction {
// This is additional launcher with explicit `no icon` configuration.
withDesktopFile = false;
} else {
final Path nullPath = null;
if (curIconResource.get().saveToFile(nullPath) != OverridableResource.Source.DefaultResource) {
// This launcher has custom icon configured.
withDesktopFile = true;
try {
if (curIconResource.get().saveToFile((Path)null) != OverridableResource.Source.DefaultResource) {
// This launcher has custom icon configured.
withDesktopFile = true;
}
} catch (IOException ex) {
// Should never happen as `saveToFile((Path)null)` should not perform any actual I/O operations.
throw new UncheckedIOException(ex);
}
}
@@ -135,13 +140,13 @@ final class DesktopIntegration extends ShellCustomAction {
return (LinuxLauncher)v;
}).filter(l -> {
return toRequest(l.shortcut()).orElse(true);
}).map(toFunction(l -> {
}).map(l -> {
return new DesktopIntegration(env, pkg, l);
})).toList();
}).toList();
}
}
static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException {
static ShellCustomAction create(BuildEnv env, Package pkg) {
if (pkg.isRuntimeInstaller()) {
return ShellCustomAction.nop(REPLACEMENT_STRING_IDS);
}
@@ -25,362 +25,19 @@
package jdk.jpackage.internal;
import jdk.jpackage.internal.model.LinuxPackage;
import jdk.jpackage.internal.model.PackagerException;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.LinuxDebPackage;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.util.OperatingSystem;
import jdk.jpackage.internal.model.AppImageLayout;
import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction;
import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB;
import jdk.jpackage.internal.model.LinuxDebPackage;
import jdk.jpackage.internal.model.PackagerException;
import jdk.jpackage.internal.model.StandardPackageType;
import jdk.jpackage.internal.util.Result;
public class LinuxDebBundler extends LinuxPackageBundler {
private static final String TOOL_DPKG_DEB = "dpkg-deb";
private static final String TOOL_DPKG = "dpkg";
private static final String TOOL_FAKEROOT = "fakeroot";
public LinuxDebBundler() {
super(LinuxFromParams.DEB_PACKAGE);
}
@Override
protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException {
// Show warning if license file is missing
if (pkg.licenseFile().isEmpty()) {
Log.verbose(I18N.getString("message.debs-like-licenses"));
}
}
@Override
protected List<ToolValidator> getToolValidators() {
return Stream.of(TOOL_DPKG_DEB, TOOL_DPKG, TOOL_FAKEROOT).map(
ToolValidator::new).toList();
}
@Override
protected void createConfigFiles(Map<String, String> replacementData,
BuildEnv env, LinuxPackage pkg) throws IOException {
prepareProjectConfig(replacementData, env, pkg);
adjustPermissionsRecursive(env.appImageDir());
}
@Override
protected Path buildPackageBundle(BuildEnv env, LinuxPackage pkg,
Path outputParentDir) throws PackagerException, IOException {
return buildDeb(env, pkg, outputParentDir);
}
private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):");
@Override
protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) {
libProvidersLookup.setPackageLookup(file -> {
Path realPath = file.toRealPath();
try {
// Try the real path first as it works better on newer Ubuntu versions
return findProvidingPackages(realPath);
} catch (IOException ex) {
// Try the default path if differ
if (!realPath.toString().equals(file.toString())) {
return findProvidingPackages(file);
} else {
throw ex;
}
}
});
}
private static Stream<String> findProvidingPackages(Path file) throws IOException {
//
// `dpkg -S` command does glob pattern lookup. If not the absolute path
// to the file is specified it might return mltiple package names.
// Even for full paths multiple package names can be returned as
// it is OK for multiple packages to provide the same file. `/opt`
// directory is such an example. So we have to deal with multiple
// packages per file situation.
//
// E.g.: `dpkg -S libc.so.6` command reports three packages:
// libc6-x32: /libx32/libc.so.6
// libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6
// libc6-i386: /lib32/libc.so.6
// `:amd64` is architecture suffix and can (should) be dropped.
// Still need to decide what package to choose from three.
// libc6-x32 and libc6-i386 both depend on libc6:
// $ dpkg -s libc6-x32
// Package: libc6-x32
// Status: install ok installed
// Priority: optional
// Section: libs
// Installed-Size: 10840
// Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
// Architecture: amd64
// Source: glibc
// Version: 2.23-0ubuntu10
// Depends: libc6 (= 2.23-0ubuntu10)
//
// We can dive into tracking dependencies, but this would be overly
// complicated.
//
// For simplicity lets consider the following rules:
// 1. If there is one item in `dpkg -S` output, accept it.
// 2. If there are multiple items in `dpkg -S` output and there is at
// least one item with the default arch suffix (DEB_ARCH),
// accept only these items.
// 3. If there are multiple items in `dpkg -S` output and there are
// no with the default arch suffix (DEB_ARCH), accept all items.
// So lets use this heuristics: don't accept packages for whom
// `dpkg -p` command fails.
// 4. Arch suffix should be stripped from accepted package names.
//
Set<String> archPackages = new HashSet<>();
Set<String> otherPackages = new HashSet<>();
var debArch = LinuxPackageArch.getValue(LINUX_DEB);
Executor.of(TOOL_DPKG, "-S", file.toString())
.saveOutput(true).executeExpectSuccess()
.getOutput().forEach(line -> {
Matcher matcher = PACKAGE_NAME_REGEX.matcher(line);
if (matcher.find()) {
String name = matcher.group(1);
if (name.endsWith(":" + debArch)) {
// Strip arch suffix
name = name.substring(0,
name.length() - (debArch.length() + 1));
archPackages.add(name);
} else {
otherPackages.add(name);
}
}
});
if (!archPackages.isEmpty()) {
return archPackages.stream();
}
return otherPackages.stream();
}
@Override
protected List<ConfigException> verifyOutputBundle(BuildEnv env, LinuxPackage pkg,
Path packageBundle) {
List<ConfigException> errors = new ArrayList<>();
String controlFileName = "control";
List<PackageProperty> properties = List.of(
new PackageProperty("Package", pkg.packageName(),
"APPLICATION_PACKAGE", controlFileName),
new PackageProperty("Version", ((LinuxDebPackage)pkg).versionWithRelease(),
"APPLICATION_VERSION_WITH_RELEASE",
controlFileName),
new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName));
List<String> cmdline = new ArrayList<>(List.of(TOOL_DPKG_DEB, "-f",
packageBundle.toString()));
properties.forEach(property -> cmdline.add(property.name));
try {
Map<String, String> actualValues = Executor.of(cmdline.toArray(String[]::new))
.saveOutput(true)
.executeExpectSuccess()
.getOutput().stream()
.map(line -> line.split(":\\s+", 2))
.collect(Collectors.toMap(
components -> components[0],
components -> components[1]));
properties.forEach(property -> errors.add(property.verifyValue(
actualValues.get(property.name))));
} catch (IOException ex) {
// Ignore error as it is not critical. Just report it.
Log.verbose(ex);
}
return errors;
}
/*
* set permissions with a string like "rwxr-xr-x"
*
* This cannot be directly backport to 22u which is built with 1.6
*/
private void setPermissions(Path file, String permissions) {
Set<PosixFilePermission> filePermissions =
PosixFilePermissions.fromString(permissions);
try {
if (Files.exists(file)) {
Files.setPosixFilePermissions(file, filePermissions);
}
} catch (IOException ex) {
Log.error(ex.getMessage());
Log.verbose(ex);
}
}
public static boolean isDebian() {
// we are just going to run "dpkg -s coreutils" and assume Debian
// or deritive if no error is returned.
try {
Executor.of(TOOL_DPKG, "-s", "coreutils").executeExpectSuccess();
return true;
} catch (IOException e) {
// just fall thru
}
return false;
}
private void adjustPermissionsRecursive(Path dir) throws IOException {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
throws IOException {
if (file.endsWith(".so") || !Files.isExecutable(file)) {
setPermissions(file, "rw-r--r--");
} else if (Files.isExecutable(file)) {
setPermissions(file, "rwxr-xr-x");
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e)
throws IOException {
if (e == null) {
setPermissions(dir, "rwxr-xr-x");
return FileVisitResult.CONTINUE;
} else {
// directory iteration failed
throw e;
}
}
});
}
private class DebianFile {
DebianFile(Path dstFilePath, String comment) {
this.dstFilePath = dstFilePath;
this.comment = comment;
}
DebianFile setExecutable() {
permissions = "rwxr-xr-x";
return this;
}
void create(Map<String, String> data, Function<String, OverridableResource> resourceFactory)
throws IOException {
resourceFactory.apply("template." + dstFilePath.getFileName().toString())
.setCategory(I18N.getString(comment))
.setSubstitutionData(data)
.saveToFile(dstFilePath);
if (permissions != null) {
setPermissions(dstFilePath, permissions);
}
}
private final Path dstFilePath;
private final String comment;
private String permissions;
}
private void prepareProjectConfig(Map<String, String> data, BuildEnv env, LinuxPackage pkg) throws IOException {
Path configDir = env.appImageDir().resolve("DEBIAN");
List<DebianFile> debianFiles = new ArrayList<>();
debianFiles.add(new DebianFile(
configDir.resolve("control"),
"resource.deb-control-file"));
debianFiles.add(new DebianFile(
configDir.resolve("preinst"),
"resource.deb-preinstall-script").setExecutable());
debianFiles.add(new DebianFile(
configDir.resolve("prerm"),
"resource.deb-prerm-script").setExecutable());
debianFiles.add(new DebianFile(
configDir.resolve("postinst"),
"resource.deb-postinstall-script").setExecutable());
debianFiles.add(new DebianFile(
configDir.resolve("postrm"),
"resource.deb-postrm-script").setExecutable());
((LinuxDebPackage)pkg).relativeCopyrightFilePath().ifPresent(copyrightFile -> {
debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile),
"resource.copyright-file"));
});
for (DebianFile debianFile : debianFiles) {
debianFile.create(data, env::createResource);
}
}
@Override
protected Map<String, String> createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException {
Map<String, String> data = new HashMap<>();
String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown");
data.put("APPLICATION_MAINTAINER", ((LinuxDebPackage) pkg).maintainer());
data.put("APPLICATION_SECTION", pkg.category().orElseThrow());
data.put("APPLICATION_COPYRIGHT", pkg.app().copyright());
data.put("APPLICATION_LICENSE_TEXT", licenseText);
data.put("APPLICATION_ARCH", pkg.arch());
data.put("APPLICATION_INSTALLED_SIZE", Long.toString(
AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10));
data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map(
value -> "Homepage: " + value).orElse(""));
data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease());
return data;
}
private Path buildDeb(BuildEnv env, LinuxPackage pkg, Path outdir) throws IOException {
Path outFile = outdir.resolve(pkg.packageFileNameWithSuffix());
Log.verbose(I18N.format("message.outputting-to-location", outFile.toAbsolutePath()));
List<String> cmdline = new ArrayList<>();
cmdline.addAll(List.of(TOOL_FAKEROOT, TOOL_DPKG_DEB));
if (Log.isVerbose()) {
cmdline.add("--verbose");
}
cmdline.addAll(List.of("-b", env.appImageDir().toString(),
outFile.toAbsolutePath().toString()));
// run dpkg
RetryExecutor.retryOnKnownErrorMessage(
"semop(1): encountered an error: Invalid argument").execute(
cmdline.toArray(String[]::new));
Log.verbose(I18N.format("message.output-to-location", outFile.toAbsolutePath()));
return outFile;
}
@Override
public String getName() {
return I18N.getString("deb.bundler.name");
@@ -392,12 +49,28 @@ public class LinuxDebBundler extends LinuxPackageBundler {
}
@Override
public boolean supported(boolean runtimeInstaller) {
return OperatingSystem.isLinux() && (new ToolValidator(TOOL_DPKG_DEB).validate() == null);
public Path execute(Map<String, ? super Object> params, Path outputParentDir) throws PackagerException {
return Packager.<LinuxDebPackage>build().outputDir(outputParentDir)
.pkg(LinuxFromParams.DEB_PACKAGE.fetchFrom(params))
.env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params))
.pipelineBuilderMutatorFactory((env, pkg, outputDir) -> {
return new LinuxDebPackager(env, pkg, outputDir, sysEnv.orElseThrow());
}).execute(LinuxPackagingPipeline.build());
}
@Override
protected Result<LinuxDebSystemEnvironment> sysEnv() {
return sysEnv;
}
@Override
public boolean isDefault() {
return isDebian();
return sysEnv.value()
.map(LinuxSystemEnvironment::nativePackageType)
.map(StandardPackageType.LINUX_DEB::equals)
.orElse(false);
}
private final Result<LinuxDebSystemEnvironment> sysEnv = LinuxDebSystemEnvironment.create(SYS_ENV);
}
@@ -0,0 +1,344 @@
/*
* Copyright (c) 2012, 2025, 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 jdk.jpackage.internal;
import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB;
import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.jpackage.internal.PackagingPipeline.PackageTaskID;
import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID;
import jdk.jpackage.internal.model.AppImageLayout;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.LinuxDebPackage;
final class LinuxDebPackager extends LinuxPackager<LinuxDebPackage> {
LinuxDebPackager(BuildEnv env, LinuxDebPackage pkg, Path outputDir, LinuxDebSystemEnvironment sysEnv) {
super(env, pkg, outputDir, sysEnv);
this.sysEnv = Objects.requireNonNull(sysEnv);
}
@Override
protected void createConfigFiles(Map<String, String> replacementData) throws IOException {
prepareProjectConfig(replacementData);
adjustPermissionsRecursive();
}
@Override
protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) {
libProvidersLookup.setPackageLookup(file -> {
Path realPath = file.toRealPath();
try {
// Try the real path first as it works better on newer Ubuntu versions
return findProvidingPackages(realPath, sysEnv.dpkg());
} catch (IOException ex) {
// Try the default path if differ
if (!realPath.equals(file)) {
return findProvidingPackages(file, sysEnv.dpkg());
} else {
throw ex;
}
}
});
}
@Override
protected List<? extends Exception> findErrorsInOutputPackage() throws IOException {
List<ConfigException> errors = new ArrayList<>();
var controlFileName = "control";
List<PackageProperty> properties = List.of(
new PackageProperty("Package", pkg.packageName(),
"APPLICATION_PACKAGE", controlFileName),
new PackageProperty("Version", pkg.versionWithRelease(),
"APPLICATION_VERSION_WITH_RELEASE",
controlFileName),
new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName));
List<String> cmdline = new ArrayList<>(List.of(
sysEnv.dpkgdeb().toString(), "-f", outputPackageFile().toString()));
properties.forEach(property -> cmdline.add(property.name));
Map<String, String> actualValues = Executor.of(cmdline.toArray(String[]::new))
.saveOutput(true)
.executeExpectSuccess()
.getOutput().stream()
.map(line -> line.split(":\\s+", 2))
.collect(Collectors.toMap(
components -> components[0],
components -> components[1]));
for (var property : properties) {
Optional.ofNullable(property.verifyValue(actualValues.get(property.name))).ifPresent(errors::add);
}
return errors;
}
@Override
protected Map<String, String> createReplacementData() throws IOException {
Map<String, String> data = new HashMap<>();
String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown");
data.put("APPLICATION_MAINTAINER", pkg.maintainer());
data.put("APPLICATION_SECTION", pkg.category().orElseThrow());
data.put("APPLICATION_COPYRIGHT", pkg.app().copyright());
data.put("APPLICATION_LICENSE_TEXT", licenseText);
data.put("APPLICATION_ARCH", pkg.arch());
data.put("APPLICATION_INSTALLED_SIZE", Long.toString(
AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10));
data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map(
value -> "Homepage: " + value).orElse(""));
data.put("APPLICATION_VERSION_WITH_RELEASE", pkg.versionWithRelease());
return data;
}
@Override
protected void buildPackage() throws IOException {
Path debFile = outputPackageFile();
Log.verbose(I18N.format("message.outputting-to-location", debFile.toAbsolutePath()));
List<String> cmdline = new ArrayList<>();
Stream.of(sysEnv.fakeroot(), sysEnv.dpkgdeb()).map(Path::toString).forEach(cmdline::add);
if (Log.isVerbose()) {
cmdline.add("--verbose");
}
cmdline.addAll(List.of("-b", env.appImageDir().toString(), debFile.toAbsolutePath().toString()));
// run dpkg
RetryExecutor.retryOnKnownErrorMessage(
"semop(1): encountered an error: Invalid argument").execute(
cmdline.toArray(String[]::new));
Log.verbose(I18N.format("message.output-to-location", debFile.toAbsolutePath()));
}
@Override
public void accept(PackagingPipeline.Builder pipelineBuilder) {
super.accept(pipelineBuilder);
// Build deb config files after app image contents are ready because
// it calculates the size of the image and saves the value in one of the config files.
pipelineBuilder.configuredTasks().filter(task -> {
return PackageTaskID.CREATE_CONFIG_FILES.equals(task.task());
}).findFirst().orElseThrow()
.addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE)
.add();
}
private void adjustPermissionsRecursive() throws IOException {
Files.walkFileTree(env.appImageDir(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (file.endsWith(".so") || !Files.isExecutable(file)) {
Files.setPosixFilePermissions(file, SO_PERMISSIONS);
} else if (Files.isExecutable(file)) {
Files.setPosixFilePermissions(file, EXECUTABLE_PERMISSIONS);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
if (e == null) {
Files.setPosixFilePermissions(dir, FOLDER_PERMISSIONS);
return FileVisitResult.CONTINUE;
} else {
// directory iteration failed
throw e;
}
}
});
}
private void prepareProjectConfig(Map<String, String> data) throws IOException {
Path configDir = env.appImageDir().resolve("DEBIAN");
List<DebianFile> debianFiles = new ArrayList<>();
debianFiles.add(new DebianFile(
configDir.resolve("control"),
"resource.deb-control-file"));
debianFiles.add(new DebianFile(
configDir.resolve("preinst"),
"resource.deb-preinstall-script").setExecutable());
debianFiles.add(new DebianFile(
configDir.resolve("prerm"),
"resource.deb-prerm-script").setExecutable());
debianFiles.add(new DebianFile(
configDir.resolve("postinst"),
"resource.deb-postinstall-script").setExecutable());
debianFiles.add(new DebianFile(
configDir.resolve("postrm"),
"resource.deb-postrm-script").setExecutable());
pkg.relativeCopyrightFilePath().ifPresent(copyrightFile -> {
debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile),
"resource.copyright-file"));
});
for (DebianFile debianFile : debianFiles) {
debianFile.create(data, env::createResource);
}
}
private static Stream<String> findProvidingPackages(Path file, Path dpkg) throws IOException {
//
// `dpkg -S` command does glob pattern lookup. If not the absolute path
// to the file is specified it might return mltiple package names.
// Even for full paths multiple package names can be returned as
// it is OK for multiple packages to provide the same file. `/opt`
// directory is such an example. So we have to deal with multiple
// packages per file situation.
//
// E.g.: `dpkg -S libc.so.6` command reports three packages:
// libc6-x32: /libx32/libc.so.6
// libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6
// libc6-i386: /lib32/libc.so.6
// `:amd64` is architecture suffix and can (should) be dropped.
// Still need to decide what package to choose from three.
// libc6-x32 and libc6-i386 both depend on libc6:
// $ dpkg -s libc6-x32
// Package: libc6-x32
// Status: install ok installed
// Priority: optional
// Section: libs
// Installed-Size: 10840
// Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
// Architecture: amd64
// Source: glibc
// Version: 2.23-0ubuntu10
// Depends: libc6 (= 2.23-0ubuntu10)
//
// We can dive into tracking dependencies, but this would be overly
// complicated.
//
// For simplicity lets consider the following rules:
// 1. If there is one item in `dpkg -S` output, accept it.
// 2. If there are multiple items in `dpkg -S` output and there is at
// least one item with the default arch suffix (DEB_ARCH),
// accept only these items.
// 3. If there are multiple items in `dpkg -S` output and there are
// no with the default arch suffix (DEB_ARCH), accept all items.
// So lets use this heuristics: don't accept packages for whom
// `dpkg -p` command fails.
// 4. Arch suffix should be stripped from accepted package names.
//
Set<String> archPackages = new HashSet<>();
Set<String> otherPackages = new HashSet<>();
var debArch = LinuxPackageArch.getValue(LINUX_DEB);
Executor.of(dpkg.toString(), "-S", file.toString())
.saveOutput(true).executeExpectSuccess()
.getOutput().forEach(line -> {
Matcher matcher = PACKAGE_NAME_REGEX.matcher(line);
if (matcher.find()) {
String name = matcher.group(1);
if (name.endsWith(":" + debArch)) {
// Strip arch suffix
name = name.substring(0,
name.length() - (debArch.length() + 1));
archPackages.add(name);
} else {
otherPackages.add(name);
}
}
});
if (!archPackages.isEmpty()) {
return archPackages.stream();
}
return otherPackages.stream();
}
private static final class DebianFile {
DebianFile(Path dstFilePath, String comment) {
this.dstFilePath = Objects.requireNonNull(dstFilePath);
this.comment = Objects.requireNonNull(comment);
}
DebianFile setExecutable() {
permissions = EXECUTABLE_PERMISSIONS;
return this;
}
void create(Map<String, String> data, Function<String, OverridableResource> resourceFactory)
throws IOException {
resourceFactory.apply("template." + dstFilePath.getFileName().toString())
.setCategory(I18N.getString(comment))
.setSubstitutionData(data)
.saveToFile(dstFilePath);
if (permissions != null) {
Files.setPosixFilePermissions(dstFilePath, permissions);
}
}
private final Path dstFilePath;
private final String comment;
private Set<PosixFilePermission> permissions;
}
private final LinuxDebSystemEnvironment sysEnv;
private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):");
private static final Set<PosixFilePermission> EXECUTABLE_PERMISSIONS = PosixFilePermissions.fromString("rwxr-xr-x");
private static final Set<PosixFilePermission> FOLDER_PERMISSIONS = PosixFilePermissions.fromString("rwxr-xr-x");
private static final Set<PosixFilePermission> SO_PERMISSIONS = PosixFilePermissions.fromString("rw-r--r--");
}
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2025, 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 jdk.jpackage.internal;
import static jdk.jpackage.internal.LinuxSystemEnvironment.mixin;
import jdk.jpackage.internal.util.Result;
public interface LinuxDebSystemEnvironment extends LinuxSystemEnvironment, LinuxDebSystemEnvironmentMixin {
static Result<LinuxDebSystemEnvironment> create(Result<LinuxSystemEnvironment> base) {
return mixin(LinuxDebSystemEnvironment.class, base, LinuxDebSystemEnvironmentMixin::create);
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2025, 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 jdk.jpackage.internal;
import java.nio.file.Path;
import java.util.Objects;
import java.util.stream.Stream;
import jdk.jpackage.internal.util.Result;
public interface LinuxDebSystemEnvironmentMixin {
Path dpkg();
Path dpkgdeb();
Path fakeroot();
record Stub(Path dpkg, Path dpkgdeb, Path fakeroot) implements LinuxDebSystemEnvironmentMixin {
}
static Result<LinuxDebSystemEnvironmentMixin> create() {
final var errors = Stream.of(Internal.TOOL_DPKG_DEB, Internal.TOOL_DPKG, Internal.TOOL_FAKEROOT)
.map(ToolValidator::new)
.map(ToolValidator::validate)
.filter(Objects::nonNull)
.toList();
if (errors.isEmpty()) {
return Result.ofValue(new Stub(Internal.TOOL_DPKG, Internal.TOOL_DPKG_DEB, Internal.TOOL_FAKEROOT));
} else {
return Result.ofErrors(errors);
}
}
static final class Internal {
private static final Path TOOL_DPKG_DEB = Path.of("dpkg-deb");
private static final Path TOOL_DPKG = Path.of("dpkg");
private static final Path TOOL_FAKEROOT = Path.of("fakeroot");
}
}
@@ -39,9 +39,10 @@ import java.io.IOException;
import java.util.Map;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.LinuxApplication;
import jdk.jpackage.internal.model.LinuxDebPackage;
import jdk.jpackage.internal.model.LinuxLauncher;
import jdk.jpackage.internal.model.LinuxLauncherMixin;
import jdk.jpackage.internal.model.LinuxPackage;
import jdk.jpackage.internal.model.LinuxRpmPackage;
import jdk.jpackage.internal.model.StandardPackageType;
final class LinuxFromParams {
@@ -76,7 +77,7 @@ final class LinuxFromParams {
return pkgBuilder;
}
private static LinuxPackage createLinuxRpmPackage(
private static LinuxRpmPackage createLinuxRpmPackage(
Map<String, ? super Object> params) throws ConfigException, IOException {
final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM);
@@ -88,7 +89,7 @@ final class LinuxFromParams {
return pkgBuilder.create();
}
private static LinuxPackage createLinuxDebPackage(
private static LinuxDebPackage createLinuxDebPackage(
Map<String, ? super Object> params) throws ConfigException, IOException {
final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB);
@@ -97,16 +98,23 @@ final class LinuxFromParams {
MAINTAINER_EMAIL.copyInto(params, pkgBuilder::maintainerEmail);
return pkgBuilder.create();
final var pkg = pkgBuilder.create();
// Show warning if license file is missing
if (pkg.licenseFile().isEmpty()) {
Log.verbose(I18N.getString("message.debs-like-licenses"));
}
return pkg;
}
static final BundlerParamInfo<LinuxApplication> APPLICATION = createApplicationBundlerParam(
LinuxFromParams::createLinuxApplication);
static final BundlerParamInfo<LinuxPackage> RPM_PACKAGE = createPackageBundlerParam(
static final BundlerParamInfo<LinuxRpmPackage> RPM_PACKAGE = createPackageBundlerParam(
LinuxFromParams::createLinuxRpmPackage);
static final BundlerParamInfo<LinuxPackage> DEB_PACKAGE = createPackageBundlerParam(
static final BundlerParamInfo<LinuxDebPackage> DEB_PACKAGE = createPackageBundlerParam(
LinuxFromParams::createLinuxDebPackage);
private static final BundlerParamInfo<String> LINUX_SHORTCUT_HINT = createStringBundlerParam(
@@ -38,7 +38,7 @@ import jdk.jpackage.internal.model.Package;
*/
public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices {
private LinuxLaunchersAsServices(BuildEnv env, Package pkg) throws IOException {
private LinuxLaunchersAsServices(BuildEnv env, Package pkg) {
super(env.appImageDir(), pkg.app(), REQUIRED_PACKAGES, launcher -> {
return new LauncherImpl(env, pkg, launcher);
});
@@ -58,7 +58,7 @@ public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices {
return data;
}
static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException {
static ShellCustomAction create(BuildEnv env, Package pkg) {
if (pkg.isRuntimeInstaller()) {
return ShellCustomAction.nop(LINUX_REPLACEMENT_STRING_IDS);
}
@@ -24,33 +24,16 @@
*/
package jdk.jpackage.internal;
import java.io.IOException;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv;
import jdk.jpackage.internal.PackagingPipeline.PackageTaskID;
import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID;
import jdk.jpackage.internal.model.AppImageLayout;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.LinuxDebPackage;
import jdk.jpackage.internal.model.LinuxPackage;
import jdk.jpackage.internal.model.Package;
import jdk.jpackage.internal.model.PackagerException;
import jdk.jpackage.internal.util.Result;
abstract class LinuxPackageBundler extends AbstractBundler {
LinuxPackageBundler(BundlerParamInfo<? extends LinuxPackage> pkgParam) {
this.pkgParam = pkgParam;
customActions = List.of(new CustomActionInstance(
DesktopIntegration::create), new CustomActionInstance(
LinuxLaunchersAsServices::create));
this.pkgParam = Objects.requireNonNull(pkgParam);
}
@Override
@@ -58,39 +41,32 @@ abstract class LinuxPackageBundler extends AbstractBundler {
throws ConfigException {
// Order is important!
LinuxPackage pkg = pkgParam.fetchFrom(params);
var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params);
pkgParam.fetchFrom(params);
BuildEnvFromParams.BUILD_ENV.fetchFrom(params);
for (var validator: getToolValidators()) {
ConfigException ex = validator.validate();
if (ex != null) {
throw ex;
}
LinuxSystemEnvironment sysEnv;
try {
sysEnv = sysEnv().orElseThrow();
} catch (RuntimeException ex) {
throw ConfigException.rethrowConfigException(ex);
}
if (!isDefault()) {
withFindNeededPackages = false;
Log.verbose(MessageFormat.format(I18N.getString(
"message.not-default-bundler-no-dependencies-lookup"),
Log.verbose(I18N.format(
"message.not-default-bundler-no-dependencies-lookup",
getName()));
} else {
withFindNeededPackages = LibProvidersLookup.supported();
if (!withFindNeededPackages) {
final String advice;
if ("deb".equals(getID())) {
advice = "message.deb-ldd-not-available.advice";
} else {
advice = "message.rpm-ldd-not-available.advice";
}
// Let user know package dependencies will not be generated.
Log.error(String.format("%s\n%s", I18N.getString(
"message.ldd-not-available"), I18N.getString(advice)));
} else if (!sysEnv.soLookupAvailable()) {
final String advice;
if ("deb".equals(getID())) {
advice = "message.deb-ldd-not-available.advice";
} else {
advice = "message.rpm-ldd-not-available.advice";
}
// Let user know package dependencies will not be generated.
Log.error(String.format("%s\n%s", I18N.getString(
"message.ldd-not-available"), I18N.getString(advice)));
}
// Packaging specific validation
doValidate(env, pkg);
return true;
}
@@ -100,148 +76,13 @@ abstract class LinuxPackageBundler extends AbstractBundler {
}
@Override
public final Path execute(Map<String, ? super Object> params,
Path outputParentDir) throws PackagerException {
IOUtils.writableOutputDir(outputParentDir);
// Order is important!
final LinuxPackage pkg = pkgParam.fetchFrom(params);
final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params);
final var pipelineBuilder = LinuxPackagingPipeline.build()
.excludeDirFromCopying(outputParentDir)
.task(PackageTaskID.CREATE_PACKAGE_FILE)
.packageAction(this::buildPackage)
.add();
final var createConfigFilesTaskBuilder = pipelineBuilder
.task(PackageTaskID.CREATE_CONFIG_FILES)
.packageAction(this::buildConfigFiles);
if (pkg instanceof LinuxDebPackage) {
// Build deb config files after app image contents are ready because
// it calculates the size of the image and saves the value in one of the config files.
createConfigFilesTaskBuilder.addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE);
}
createConfigFilesTaskBuilder.add();
pipelineBuilder.create().execute(env, pkg, outputParentDir);
return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath();
public boolean supported(boolean runtimeInstaller) {
return sysEnv().hasValue();
}
private void buildConfigFiles(PackageBuildEnv<LinuxPackage, AppImageLayout> env) throws PackagerException, IOException {
for (var ca : customActions) {
ca.init(env.env(), env.pkg());
}
Map<String, String> data = createDefaultReplacementData(env.env(), env.pkg());
for (var ca : customActions) {
ShellCustomAction.mergeReplacementData(data, ca.instance.create());
}
data.putAll(createReplacementData(env.env(), env.pkg()));
createConfigFiles(Collections.unmodifiableMap(data), env.env(), env.pkg());
}
private void buildPackage(PackageBuildEnv<LinuxPackage, AppImageLayout> env) throws PackagerException, IOException {
Path packageBundle = buildPackageBundle(env.env(), env.pkg(), env.outputDir());
verifyOutputBundle(env.env(), env.pkg(), packageBundle).stream()
.filter(Objects::nonNull)
.forEachOrdered(ex -> {
Log.verbose(ex.getLocalizedMessage());
Log.verbose(ex.getAdvice());
});
}
private List<String> getListOfNeededPackages(BuildEnv env) throws IOException {
final List<String> caPackages = customActions.stream()
.map(ca -> ca.instance)
.map(ShellCustomAction::requiredPackages)
.flatMap(List::stream).toList();
final List<String> neededLibPackages;
if (withFindNeededPackages) {
LibProvidersLookup lookup = new LibProvidersLookup();
initLibProvidersLookup(lookup);
neededLibPackages = lookup.execute(env.appImageDir());
} else {
neededLibPackages = Collections.emptyList();
Log.info(I18N.getString("warning.foreign-app-image"));
}
// Merge all package lists together.
// Filter out empty names, sort and remove duplicates.
List<String> result = Stream.of(caPackages, neededLibPackages).flatMap(
List::stream).filter(Predicate.not(String::isEmpty)).sorted().distinct().toList();
Log.verbose(String.format("Required packages: %s", result));
return result;
}
private Map<String, String> createDefaultReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException {
Map<String, String> data = new HashMap<>();
data.put("APPLICATION_PACKAGE", pkg.packageName());
data.put("APPLICATION_VENDOR", pkg.app().vendor());
data.put("APPLICATION_VERSION", pkg.version());
data.put("APPLICATION_DESCRIPTION", pkg.description());
String defaultDeps = String.join(", ", getListOfNeededPackages(env));
String customDeps = pkg.additionalDependencies().orElse("");
if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) {
customDeps = ", " + customDeps;
}
data.put("PACKAGE_DEFAULT_DEPENDENCIES", defaultDeps);
data.put("PACKAGE_CUSTOM_DEPENDENCIES", customDeps);
return data;
}
protected abstract List<ConfigException> verifyOutputBundle(
BuildEnv env, LinuxPackage pkg, Path packageBundle);
protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup);
protected abstract List<ToolValidator> getToolValidators();
protected abstract void doValidate(BuildEnv env, LinuxPackage pkg)
throws ConfigException;
protected abstract Map<String, String> createReplacementData(
BuildEnv env, LinuxPackage pkg) throws IOException;
protected abstract void createConfigFiles(
Map<String, String> replacementData,
BuildEnv env, LinuxPackage pkg) throws IOException;
protected abstract Path buildPackageBundle(
BuildEnv env, LinuxPackage pkg, Path outputParentDir) throws
PackagerException, IOException;
protected abstract Result<? extends LinuxSystemEnvironment> sysEnv();
private final BundlerParamInfo<? extends LinuxPackage> pkgParam;
private boolean withFindNeededPackages;
private final List<CustomActionInstance> customActions;
private static final class CustomActionInstance {
CustomActionInstance(ShellCustomActionFactory factory) {
this.factory = factory;
}
void init(BuildEnv env, Package pkg) throws IOException {
instance = factory.create(env, pkg);
Objects.requireNonNull(instance);
}
private final ShellCustomActionFactory factory;
ShellCustomAction instance;
}
static final Result<LinuxSystemEnvironment> SYS_ENV = LinuxSystemEnvironment.create();
}
@@ -0,0 +1,184 @@
/*
* Copyright (c) 2025, 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 jdk.jpackage.internal;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import jdk.jpackage.internal.PackagingPipeline.PackageTaskID;
import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID;
import jdk.jpackage.internal.PackagingPipeline.TaskID;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.LinuxPackage;
import jdk.jpackage.internal.model.PackagerException;
abstract class LinuxPackager<T extends LinuxPackage> implements Consumer<PackagingPipeline.Builder> {
LinuxPackager(BuildEnv env, T pkg, Path outputDir, LinuxSystemEnvironment sysEnv) {
this.env = Objects.requireNonNull(env);
this.pkg = Objects.requireNonNull(pkg);
this.outputDir = Objects.requireNonNull(outputDir);
this.withRequiredPackagesLookup = sysEnv.soLookupAvailable() && sysEnv.nativePackageType().equals(pkg.type());
customActions = List.of(
DesktopIntegration.create(env, pkg),
LinuxLaunchersAsServices.create(env, pkg));
}
enum LinuxPackageTaskID implements TaskID {
INIT_REQUIRED_PACKAGES,
VERIFY_PACKAGE
}
@Override
public void accept(PackagingPipeline.Builder pipelineBuilder) {
pipelineBuilder.excludeDirFromCopying(outputDir)
.task(PackageTaskID.CREATE_CONFIG_FILES)
.action(this::buildConfigFiles)
.add()
.task(LinuxPackageTaskID.INIT_REQUIRED_PACKAGES)
.addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE)
.addDependent(PackageTaskID.CREATE_CONFIG_FILES)
.action(this::initRequiredPackages)
.add()
.task(LinuxPackageTaskID.VERIFY_PACKAGE)
.addDependencies(PackageTaskID.CREATE_PACKAGE_FILE)
.addDependent(PrimaryTaskID.PACKAGE)
.action(this::verifyOutputPackage)
.add()
.task(PackageTaskID.CREATE_PACKAGE_FILE)
.action(this::buildPackage)
.add();
}
protected final Path outputPackageFile() {
return outputDir.resolve(pkg.packageFileNameWithSuffix());
}
protected abstract void buildPackage() throws IOException;
protected abstract List<? extends Exception> findErrorsInOutputPackage() throws IOException;
protected abstract void createConfigFiles(Map<String, String> replacementData) throws IOException;
protected abstract Map<String, String> createReplacementData() throws IOException;
protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup);
private void buildConfigFiles() throws PackagerException, IOException {
final var data = createDefaultReplacementData();
for (var ca : customActions) {
ShellCustomAction.mergeReplacementData(data, ca.create());
}
data.putAll(createReplacementData());
createConfigFiles(Collections.unmodifiableMap(data));
}
private Map<String, String> createDefaultReplacementData() {
Map<String, String> data = new HashMap<>();
data.put("APPLICATION_PACKAGE", pkg.packageName());
data.put("APPLICATION_VENDOR", pkg.app().vendor());
data.put("APPLICATION_VERSION", pkg.version());
data.put("APPLICATION_DESCRIPTION", pkg.description());
String defaultDeps = String.join(", ", requiredPackages);
String customDeps = pkg.additionalDependencies().orElse("");
if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) {
customDeps = ", " + customDeps;
}
data.put("PACKAGE_DEFAULT_DEPENDENCIES", defaultDeps);
data.put("PACKAGE_CUSTOM_DEPENDENCIES", customDeps);
return data;
}
private void initRequiredPackages() throws IOException {
final List<String> caPackages = customActions.stream()
.map(ShellCustomAction::requiredPackages)
.flatMap(List::stream).toList();
final List<String> neededLibPackages;
if (withRequiredPackagesLookup) {
neededLibPackages = findRequiredPackages();
} else {
neededLibPackages = Collections.emptyList();
Log.info(I18N.getString("warning.foreign-app-image"));
}
// Merge all package lists together.
// Filter out empty names, sort and remove duplicates.
Stream.of(caPackages, neededLibPackages)
.flatMap(List::stream)
.filter(Predicate.not(String::isEmpty))
.sorted().distinct().forEach(requiredPackages::add);
Log.verbose(String.format("Required packages: %s", requiredPackages));
}
private List<String> findRequiredPackages() throws IOException {
var lookup = new LibProvidersLookup();
initLibProvidersLookup(lookup);
return lookup.execute(env.appImageDir());
}
private void verifyOutputPackage() {
final List<? extends Exception> errors;
try {
errors = findErrorsInOutputPackage();
} catch (Exception ex) {
// Ignore error as it is not critical. Just report it.
Log.verbose(ex);
return;
}
for (var ex : errors) {
Log.verbose(ex.getLocalizedMessage());
if (ex instanceof ConfigException cfgEx) {
Log.verbose(cfgEx.getAdvice());
}
}
}
protected final BuildEnv env;
protected final T pkg;
protected final Path outputDir;
private final boolean withRequiredPackagesLookup;
private final List<String> requiredPackages = new ArrayList<>();
private final List<ShellCustomAction> customActions;
}
@@ -25,189 +25,20 @@
package jdk.jpackage.internal;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import jdk.internal.util.OperatingSystem;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.DottedVersion;
import jdk.jpackage.internal.model.LinuxPackage;
import jdk.jpackage.internal.model.LinuxRpmPackage;
import jdk.jpackage.internal.model.Package;
import jdk.jpackage.internal.model.PackagerException;
import jdk.jpackage.internal.model.StandardPackageType;
import jdk.jpackage.internal.util.Result;
/**
* There are two command line options to configure license information for RPM
* packaging: --linux-rpm-license-type and --license-file. Value of
* --linux-rpm-license-type command line option configures "License:" section
* of RPM spec. Value of --license-file command line option specifies a license
* file to be added to the package. License file is a sort of documentation file
* but it will be installed even if user selects an option to install the
* package without documentation. --linux-rpm-license-type is the primary option
* to set license information. --license-file makes little sense in case of RPM
* packaging.
*/
public class LinuxRpmBundler extends LinuxPackageBundler {
private static final String DEFAULT_SPEC_TEMPLATE = "template.spec";
public static final String TOOL_RPM = "rpm";
public static final String TOOL_RPMBUILD = "rpmbuild";
public static final DottedVersion TOOL_RPMBUILD_MIN_VERSION = DottedVersion.lazy(
"4.10");
public LinuxRpmBundler() {
super(LinuxFromParams.RPM_PACKAGE);
}
@Override
protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException {
}
private static ToolValidator createRpmbuildToolValidator() {
Pattern pattern = Pattern.compile(" (\\d+\\.\\d+)");
return new ToolValidator(TOOL_RPMBUILD).setMinimalVersion(
TOOL_RPMBUILD_MIN_VERSION).setVersionParser(lines -> {
String versionString = lines.limit(1).collect(
Collectors.toList()).get(0);
Matcher matcher = pattern.matcher(versionString);
if (matcher.find()) {
return matcher.group(1);
}
return null;
});
}
@Override
protected List<ToolValidator> getToolValidators() {
return List.of(createRpmbuildToolValidator());
}
protected void createConfigFiles(Map<String, String> replacementData,
BuildEnv env, LinuxPackage pkg) throws IOException {
Path specFile = specFile(env, pkg);
// prepare spec file
env.createResource(DEFAULT_SPEC_TEMPLATE)
.setCategory(I18N.getString("resource.rpm-spec-file"))
.setSubstitutionData(replacementData)
.saveToFile(specFile);
}
@Override
protected Path buildPackageBundle(BuildEnv env, LinuxPackage pkg,
Path outputParentDir) throws PackagerException, IOException {
return buildRPM(env, pkg, outputParentDir);
}
private static Path installPrefix(LinuxPackage pkg) {
Path path = pkg.relativeInstallDir();
if (!pkg.isInstallDirInUsrTree()) {
path = path.getParent();
}
return Path.of("/").resolve(path);
}
@Override
protected Map<String, String> createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException {
Map<String, String> data = new HashMap<>();
data.put("APPLICATION_RELEASE", pkg.release().orElseThrow());
data.put("APPLICATION_PREFIX", installPrefix(pkg).toString());
data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString());
data.put("APPLICATION_SUMMARY", pkg.app().name());
data.put("APPLICATION_LICENSE_TYPE", ((LinuxRpmPackage)pkg).licenseType());
String licenseFile = pkg.licenseFile().map(v -> {
return v.toAbsolutePath().normalize().toString();
}).orElse(null);
data.put("APPLICATION_LICENSE_FILE", licenseFile);
data.put("APPLICATION_GROUP", pkg.category().orElse(""));
data.put("APPLICATION_URL", pkg.aboutURL().orElse(""));
return data;
}
@Override
protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) {
libProvidersLookup.setPackageLookup(file -> {
return Executor.of(TOOL_RPM,
"-q", "--queryformat", "%{name}\\n",
"-q", "--whatprovides", file.toString())
.saveOutput(true).executeExpectSuccess().getOutput().stream();
});
}
@Override
protected List<ConfigException> verifyOutputBundle(BuildEnv env, LinuxPackage pkg,
Path packageBundle) {
List<ConfigException> errors = new ArrayList<>();
String specFileName = specFile(env, pkg).getFileName().toString();
try {
List<PackageProperty> properties = List.of(
new PackageProperty("Name", pkg.packageName(),
"APPLICATION_PACKAGE", specFileName),
new PackageProperty("Version", pkg.version(),
"APPLICATION_VERSION", specFileName),
new PackageProperty("Release", pkg.release().orElseThrow(),
"APPLICATION_RELEASE", specFileName),
new PackageProperty("Arch", pkg.arch(), null, specFileName));
List<String> actualValues = Executor.of(TOOL_RPM, "-qp", "--queryformat",
properties.stream().map(entry -> String.format("%%{%s}",
entry.name)).collect(Collectors.joining("\\n")),
packageBundle.toString()).saveOutput(true).executeExpectSuccess().getOutput();
Iterator<String> actualValuesIt = actualValues.iterator();
properties.forEach(property -> errors.add(property.verifyValue(
actualValuesIt.next())));
} catch (IOException ex) {
// Ignore error as it is not critical. Just report it.
Log.verbose(ex);
}
return errors;
}
private Path specFile(BuildEnv env, Package pkg) {
return env.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec"));
}
private Path buildRPM(BuildEnv env, Package pkg, Path outdir) throws IOException {
Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileNameWithSuffix());
Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent()));
//run rpmbuild
Executor.of(TOOL_RPMBUILD,
"-bb", specFile(env, pkg).toAbsolutePath().toString(),
"--define", String.format("%%_sourcedir %s",
env.appImageDir().toAbsolutePath()),
// save result to output dir
"--define", String.format("%%_rpmdir %s", rpmFile.getParent()),
// do not use other system directories to build as current user
"--define", String.format("%%_topdir %s",
env.buildRoot().toAbsolutePath()),
"--define", String.format("%%_rpmfilename %s", rpmFile.getFileName())
).executeExpectSuccess();
Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent()));
return rpmFile;
}
@Override
public String getName() {
return I18N.getString("rpm.bundler.name");
@@ -219,12 +50,28 @@ public class LinuxRpmBundler extends LinuxPackageBundler {
}
@Override
public boolean supported(boolean runtimeInstaller) {
return OperatingSystem.isLinux() && (createRpmbuildToolValidator().validate() == null);
public Path execute(Map<String, ? super Object> params, Path outputParentDir) throws PackagerException {
return Packager.<LinuxRpmPackage>build().outputDir(outputParentDir)
.pkg(LinuxFromParams.RPM_PACKAGE.fetchFrom(params))
.env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params))
.pipelineBuilderMutatorFactory((env, pkg, outputDir) -> {
return new LinuxRpmPackager(env, pkg, outputDir, sysEnv.orElseThrow());
}).execute(LinuxPackagingPipeline.build());
}
@Override
protected Result<LinuxRpmSystemEnvironment> sysEnv() {
return sysEnv;
}
@Override
public boolean isDefault() {
return !LinuxDebBundler.isDebian();
return sysEnv.value()
.map(LinuxSystemEnvironment::nativePackageType)
.map(StandardPackageType.LINUX_RPM::equals)
.orElse(false);
}
private final Result<LinuxRpmSystemEnvironment> sysEnv = LinuxRpmSystemEnvironment.create(SYS_ENV);
}

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