Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d0c2e911f | ||
|
|
a36d5f8fa9 | ||
|
|
538a722c2e | ||
|
|
c57003c9b8 | ||
|
|
2f29b3f24a | ||
|
|
59e76af47b | ||
|
|
6c8e384c63 | ||
|
|
3d97e17a31 | ||
|
|
aabf699dd0 | ||
|
|
9d71af108e | ||
|
|
63688d894e | ||
|
|
9d9c0e0670 | ||
|
|
fdbba049a2 | ||
|
|
6165921449 | ||
|
|
08b677bba4 | ||
|
|
75269fdb49 | ||
|
|
d53190ac44 | ||
|
|
e19ec6f785 | ||
|
|
320230db5f | ||
|
|
af8fb20ac0 | ||
|
|
9093d3a04c | ||
|
|
5b1ebbb271 | ||
|
|
37f0e74d32 | ||
|
|
cedc0117ac | ||
|
|
12c0f29b97 | ||
|
|
c6cecc581f | ||
|
|
62cc347242 | ||
|
|
556dfddac8 | ||
|
|
bdf6853cfd | ||
|
|
aa6ff45052 | ||
|
|
25abdd85c4 | ||
|
|
501b2b3ebc | ||
|
|
2360542e89 | ||
|
|
bdb7d25ac1 | ||
|
|
f0e1078c71 | ||
|
|
7bfdb01207 | ||
|
|
a80ba6260e | ||
|
|
b90799c0e9 | ||
|
|
873078028b | ||
|
|
a663812121 | ||
|
|
ca03080c9f | ||
|
|
648582ab78 | ||
|
|
52e777845f | ||
|
|
3c9fd7688f | ||
|
|
a48538dd63 | ||
|
|
80cb0ead50 | ||
|
|
5c596e2a95 | ||
|
|
32ab0dbc0b | ||
|
|
de1f5a3c43 | ||
|
|
741221988e | ||
|
|
8ca1feaf7e |
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -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())) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+59
@@ -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
Reference in New Issue
Block a user