mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-06 16:41:43 +01:00
Compare commits
67 Commits
jb25-b178
...
jb25.0.1-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59055bc850 | ||
|
|
7666cf1882 | ||
|
|
21a1668c8f | ||
|
|
aa937adccf | ||
|
|
1434025d74 | ||
|
|
89b841701e | ||
|
|
352117baf3 | ||
|
|
79d925f6ae | ||
|
|
e37c54a24f | ||
|
|
d96581ebec | ||
|
|
f37e00d801 | ||
|
|
a49aa72e7b | ||
|
|
5af08d88d5 | ||
|
|
87a46979f3 | ||
|
|
e7a86af739 | ||
|
|
60bfa2b12e | ||
|
|
ae6360371c | ||
|
|
f8aee55ea6 | ||
|
|
ffc581146c | ||
|
|
75930f77d2 | ||
|
|
7b721d2610 | ||
|
|
fed9ce336e | ||
|
|
14be13239e | ||
|
|
c9aea14597 | ||
|
|
d619feefc6 | ||
|
|
b38204cb12 | ||
|
|
c7fe20689c | ||
|
|
bb52503876 | ||
|
|
a9554a0e4a | ||
|
|
cbae1a769b | ||
|
|
505522f2e2 | ||
|
|
9e729bf99d | ||
|
|
14eaa570d1 | ||
|
|
54b65e514f | ||
|
|
86e6947981 | ||
|
|
0f7c371233 | ||
|
|
e880107619 | ||
|
|
39743018bb | ||
|
|
ceb2dcb091 | ||
|
|
fe29694915 | ||
|
|
a336a88057 | ||
|
|
6c753b5d49 | ||
|
|
099394e43a | ||
|
|
71241ecc59 | ||
|
|
377b0902b1 | ||
|
|
04fdd306ab | ||
|
|
06b190878a | ||
|
|
b8cfdc28dc | ||
|
|
1e7ae9c8d5 | ||
|
|
0c7f8b1b00 | ||
|
|
3f53deeaf2 | ||
|
|
a2f4b57bb2 | ||
|
|
a471e942e4 | ||
|
|
d5ceea456c | ||
|
|
e6cb0a1b56 | ||
|
|
ab7a9f8f87 | ||
|
|
6b43d1a768 | ||
|
|
dfe78a31f5 | ||
|
|
e48181b9aa | ||
|
|
f0d54ab6e5 | ||
|
|
20b513f189 | ||
|
|
58f04296e7 | ||
|
|
7a2d71329d | ||
|
|
54276e869b | ||
|
|
75dcbe8f20 | ||
|
|
37b13e2f17 | ||
|
|
bde37c774a |
3
.github/README.md
vendored
3
.github/README.md
vendored
@@ -254,8 +254,7 @@ configurations (for example, `release` and `fastdebug`), supply the `--conf <con
|
||||
Then open the git root directory as a project in IDEA.
|
||||
|
||||
## Contributing
|
||||
We are happy to receive your pull requests!
|
||||
Before you submit one, please sign our [Contributor License Agreement (CLA)](https://www.jetbrains.com/agreements/cla/).
|
||||
Please contribute your changes through [OpenJDK](https://dev.java/contribute/openjdk/).
|
||||
|
||||
## Resources
|
||||
* [JetBrains Runtime on GitHub](https://github.com/JetBrains/JetBrainsRuntime).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[general]
|
||||
project=jdk
|
||||
project=jdk-updates
|
||||
jbs=JDK
|
||||
version=25
|
||||
version=25.0.1
|
||||
|
||||
[checks]
|
||||
error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright
|
||||
|
||||
@@ -47,8 +47,8 @@ VERSION_PATCH=$(getVersionProp "DEFAULT_VERSION_PATCH")
|
||||
[[ $VERSION_UPDATE = 0 ]] && JBSDK_VERSION="$VERSION_FEATURE" || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}"
|
||||
[[ $VERSION_PATCH = 0 ]] || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}.${VERSION_PATCH}"
|
||||
echo "##teamcity[setParameter name='env.JBSDK_VERSION' value='${JBSDK_VERSION}']"
|
||||
tag_prefix="jdk-"
|
||||
OPENJDK_TAG=$(git tag -l | grep "$tag_prefix$JBSDK_VERSION" | grep -v ga | sort -t "-" -k 2 -V -f | tail -n 1)
|
||||
tag_prefix="jbr-"
|
||||
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "${tag_prefix}${JBSDK_VERSION}" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -V -f | tail -n 1 | tr -d ",")
|
||||
JDK_BUILD_NUMBER=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $3}')
|
||||
[ -z $JDK_BUILD_NUMBER ] && JDK_BUILD_NUMBER=1
|
||||
re='^[0-9]+$'
|
||||
|
||||
@@ -27,6 +27,12 @@ JCEF_PATH=${JCEF_PATH:=./jcef_linux_aarch64}
|
||||
function do_configure {
|
||||
|
||||
GTK_SHELL_PATH=/gtk-shell.xml
|
||||
WAYLAND_PROTOCOLS_PATH=/opt/wayland-protocols
|
||||
WITH_WAYLAND_PROTOCOLS=
|
||||
|
||||
if [ -e "$WAYLAND_PROTOCOLS_PATH" ]; then
|
||||
WITH_WAYLAND_PROTOCOLS="--with-wayland-protocols=$WAYLAND_PROTOCOLS_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -e $GTK_SHELL_PATH ]; then
|
||||
echo $GTK_SHELL_PATH" does not exist"
|
||||
@@ -54,6 +60,7 @@ function do_configure {
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|
||||
$WITH_BUNDLED_FREETYPE \
|
||||
$WITH_WAYLAND_PROTOCOLS \
|
||||
|| do_exit $?
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ function do_configure {
|
||||
fi
|
||||
|
||||
GTK_SHELL_PATH=/gtk-shell.xml
|
||||
WAYLAND_PROTOCOLS_PATH=/opt/wayland-protocols
|
||||
WITH_WAYLAND_PROTOCOLS=
|
||||
|
||||
if [ -e "$WAYLAND_PROTOCOLS_PATH" ]; then
|
||||
WITH_WAYLAND_PROTOCOLS="--with-wayland-protocols=$WAYLAND_PROTOCOLS_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -e $GTK_SHELL_PATH ]; then
|
||||
echo $GTK_SHELL_PATH" does not exist"
|
||||
@@ -68,6 +74,7 @@ function do_configure {
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|
||||
$WITH_BUNDLED_FREETYPE \
|
||||
$WITH_WAYLAND_PROTOCOLS \
|
||||
|| do_exit $?
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,23 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
[specify the root directory for the wayland protocols xml files])])
|
||||
AC_ARG_WITH(gtk-shell1-protocol, [AS_HELP_STRING([--with-gtk-shell1-protocol],
|
||||
[specify the path to the gtk-shell1 Wayland protocol xml file])])
|
||||
AC_ARG_WITH(xkbcommon, [AS_HELP_STRING([--with-xkbcommon],
|
||||
[specify prefix directory for the xkbcommon package
|
||||
(expecting the headers under PATH/include)])])
|
||||
AC_ARG_WITH(xkbcommon-include, [AS_HELP_STRING([--with-xkbcommon-include],
|
||||
[specify directory for the xkbcommon include files])])
|
||||
AC_ARG_WITH(xkbcommon-lib, [AS_HELP_STRING([--with-xkbcommon-lib],
|
||||
[specify directory for the xkbcommon library files])])
|
||||
|
||||
if test "x$NEEDS_LIB_WAYLAND" = xfalse; then
|
||||
if (test "x${with_wayland}" != x && test "x${with_wayland}" != xno) || \
|
||||
(test "x${with_wayland_include}" != x && test "x${with_wayland_include}" != xno); then
|
||||
AC_MSG_WARN([[wayland not used, so --with-wayland[-*] is ignored]])
|
||||
fi
|
||||
if (test "x${with_xkbcommon}" != x && test "x${with_xkbcommon}" != xno) || \
|
||||
(test "x${with_xkbcommon_include}" != x && test "x${with_xkbcommon_include}" != xno); then
|
||||
AC_MSG_WARN([[wayland not used, so --with-xkbcommon[-*] is ignored]])
|
||||
fi
|
||||
WAYLAND_CFLAGS=
|
||||
WAYLAND_LIBS=
|
||||
else
|
||||
@@ -55,6 +66,9 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
if test "x${with_wayland}" = xno || test "x${with_wayland_include}" = xno; then
|
||||
AC_MSG_ERROR([It is not possible to disable the use of wayland. Remove the --without-wayland option.])
|
||||
fi
|
||||
if test "x${with_xkbcommon}" = xno || test "x${with_xkbcommon_include}" = xno; then
|
||||
AC_MSG_ERROR([It is not possible to disable the use of xkbcommon. Remove the --without-xkbcommon option.])
|
||||
fi
|
||||
|
||||
if test "x${with_wayland}" != x; then
|
||||
AC_MSG_CHECKING([for wayland headers])
|
||||
@@ -121,7 +135,52 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
HELP_MSG_MISSING_DEPENDENCY([wayland])
|
||||
AC_MSG_ERROR([Could not find wayland! $HELP_MSG ])
|
||||
fi
|
||||
WAYLAND_CFLAGS="${WAYLAND_INCLUDES} ${WAYLAND_DEFINES}"
|
||||
|
||||
XKBCOMMON_FOUND=no
|
||||
XKBCOMMON_INCLUDES=
|
||||
XKBCOMMON_LIBS=-lxkbcommon
|
||||
if test "x${with_xkbcommon}" != x; then
|
||||
AC_MSG_CHECKING([for xkbcommon headers])
|
||||
if test -s "${with_xkbcommon}/include/xkbcommon/xkbcommon.h" &&
|
||||
test -s "${with_xkbcommon}/include/xkbcommon/xkbcommon-compose.h"; then
|
||||
XKBCOMMON_INCLUDES="-I${with_xkbcommon}/include"
|
||||
XKBCOMMON_LIBS="-L${with_xkbcommon}/lib ${XKBCOMMON_LIBS}"
|
||||
|
||||
XKBCOMMON_FOUND=yes
|
||||
AC_MSG_RESULT([$XKBCOMMON_FOUND])
|
||||
else
|
||||
AC_MSG_ERROR([Can't find 'include/xkbcommon/xkbcommon.h' and 'include/xkbcommon/xkbcommon-compose.h' under ${with_xkbcommon} given with the --with-xkbcommon option.])
|
||||
fi
|
||||
fi
|
||||
if test "x${with_xkbcommon_include}" != x; then
|
||||
AC_MSG_CHECKING([for xkbcommon headers])
|
||||
if test -s "${with_xkbcommon_include}/xkbcommon/xkbcommon.h" &&
|
||||
test -s "${with_xkbcommon_include}/xkbcommon/xkbcommon-compose.h"; then
|
||||
XKBCOMMON_INCLUDES="-I${with_xkbcommon_include}"
|
||||
XKBCOMMON_FOUND=yes
|
||||
AC_MSG_RESULT([$XKBCOMMON_FOUND])
|
||||
else
|
||||
AC_MSG_ERROR([Can't find 'include/xkbcommon/xkbcommon.h' and 'include/xkbcommon/xkbcommon-compose.h' under ${with_xkbcommon_include} given with the --with-xkbcommon-include option.])
|
||||
fi
|
||||
fi
|
||||
if test "x${with_xkbcommon_lib}" != x; then
|
||||
XKBCOMMON_LIBS="-L${with_xkbcommon_lib} ${XKBCOMMON_LIBS}"
|
||||
fi
|
||||
|
||||
if test "x${XKBCOMMON_FOUND}" != xyes; then
|
||||
AC_CHECK_HEADERS([xkbcommon/xkbcommon.h xkbcommon/xkbcommon-compose.h],
|
||||
[ XKBCOMMON_FOUND=yes ],
|
||||
[ XKBCOMMON_FOUND=no; break ]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$XKBCOMMON_FOUND" != xyes; then
|
||||
HELP_MSG_MISSING_DEPENDENCY([xkbcommon])
|
||||
AC_MSG_ERROR([Could not find xkbcommon! $HELP_MSG ])
|
||||
fi
|
||||
|
||||
WAYLAND_LIBS="${WAYLAND_LIBS} ${XKBCOMMON_LIBS}"
|
||||
WAYLAND_CFLAGS="${WAYLAND_INCLUDES} ${XKBCOMMON_INCLUDES} ${WAYLAND_DEFINES}"
|
||||
fi
|
||||
AC_SUBST(WAYLAND_CFLAGS)
|
||||
AC_SUBST(WAYLAND_LIBS)
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
|
||||
DEFAULT_VERSION_FEATURE=25
|
||||
DEFAULT_VERSION_INTERIM=0
|
||||
DEFAULT_VERSION_UPDATE=0
|
||||
DEFAULT_VERSION_UPDATE=1
|
||||
DEFAULT_VERSION_PATCH=0
|
||||
DEFAULT_VERSION_EXTRA1=0
|
||||
DEFAULT_VERSION_EXTRA2=0
|
||||
DEFAULT_VERSION_EXTRA3=0
|
||||
DEFAULT_VERSION_DATE=2025-09-16
|
||||
DEFAULT_VERSION_DATE=2025-10-21
|
||||
DEFAULT_VERSION_CLASSFILE_MAJOR=69 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
|
||||
DEFAULT_VERSION_CLASSFILE_MINOR=0
|
||||
DEFAULT_VERSION_DOCS_API_SINCE=11
|
||||
|
||||
@@ -542,10 +542,10 @@ class Bundle {
|
||||
if (pattern != null) {
|
||||
// Perform date-time format pattern conversion which is
|
||||
// applicable to both SimpleDateFormat and j.t.f.DateTimeFormatter.
|
||||
String transPattern = translateDateFormatLetters(calendarType, pattern, this::convertDateTimePatternLetter);
|
||||
String transPattern = translateDateFormatLetters(calendarType, key, pattern, this::convertDateTimePatternLetter);
|
||||
dateTimePatterns.add(i, transPattern);
|
||||
// Additionally, perform SDF specific date-time format pattern conversion
|
||||
sdfPatterns.add(i, translateDateFormatLetters(calendarType, transPattern, this::convertSDFLetter));
|
||||
sdfPatterns.add(i, translateDateFormatLetters(calendarType, key, transPattern, this::convertSDFLetter));
|
||||
} else {
|
||||
dateTimePatterns.add(i, null);
|
||||
sdfPatterns.add(i, null);
|
||||
@@ -568,7 +568,7 @@ class Bundle {
|
||||
}
|
||||
}
|
||||
|
||||
private String translateDateFormatLetters(CalendarType calendarType, String cldrFormat, ConvertDateTimeLetters converter) {
|
||||
private String translateDateFormatLetters(CalendarType calendarType, String patternKey, String cldrFormat, ConvertDateTimeLetters converter) {
|
||||
String pattern = cldrFormat;
|
||||
int length = pattern.length();
|
||||
boolean inQuote = false;
|
||||
@@ -587,7 +587,7 @@ class Bundle {
|
||||
if (nextc == '\'') {
|
||||
i++;
|
||||
if (count != 0) {
|
||||
converter.convert(calendarType, lastLetter, count, jrePattern);
|
||||
converter.convert(calendarType, patternKey, lastLetter, count, jrePattern);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
@@ -597,7 +597,7 @@ class Bundle {
|
||||
}
|
||||
if (!inQuote) {
|
||||
if (count != 0) {
|
||||
converter.convert(calendarType, lastLetter, count, jrePattern);
|
||||
converter.convert(calendarType, patternKey, lastLetter, count, jrePattern);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
@@ -614,7 +614,7 @@ class Bundle {
|
||||
}
|
||||
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
|
||||
if (count != 0) {
|
||||
converter.convert(calendarType, lastLetter, count, jrePattern);
|
||||
converter.convert(calendarType, patternKey, lastLetter, count, jrePattern);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
@@ -627,7 +627,7 @@ class Bundle {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
converter.convert(calendarType, lastLetter, count, jrePattern);
|
||||
converter.convert(calendarType, patternKey, lastLetter, count, jrePattern);
|
||||
lastLetter = c;
|
||||
count = 1;
|
||||
}
|
||||
@@ -637,7 +637,7 @@ class Bundle {
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
converter.convert(calendarType, lastLetter, count, jrePattern);
|
||||
converter.convert(calendarType, patternKey, lastLetter, count, jrePattern);
|
||||
}
|
||||
if (cldrFormat.contentEquals(jrePattern)) {
|
||||
return cldrFormat;
|
||||
@@ -661,7 +661,7 @@ class Bundle {
|
||||
* on the support given by the SimpleDateFormat and the j.t.f.DateTimeFormatter
|
||||
* for date-time formatting.
|
||||
*/
|
||||
private void convertDateTimePatternLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) {
|
||||
private void convertDateTimePatternLetter(CalendarType calendarType, String patternKey, char cldrLetter, int count, StringBuilder sb) {
|
||||
switch (cldrLetter) {
|
||||
case 'u':
|
||||
case 'U':
|
||||
@@ -683,7 +683,7 @@ class Bundle {
|
||||
* Perform a conversion of CLDR date-time format pattern letter which is
|
||||
* specific to the SimpleDateFormat.
|
||||
*/
|
||||
private void convertSDFLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) {
|
||||
private void convertSDFLetter(CalendarType calendarType, String patternKey, char cldrLetter, int count, StringBuilder sb) {
|
||||
switch (cldrLetter) {
|
||||
case 'G':
|
||||
if (calendarType != CalendarType.GREGORIAN) {
|
||||
@@ -722,6 +722,17 @@ class Bundle {
|
||||
appendN('z', count, sb);
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
// If the style is FULL/LONG for a Japanese Calendar, make the
|
||||
// count == 4 for Gan-nen
|
||||
if (calendarType == CalendarType.JAPANESE &&
|
||||
(patternKey.contains("full-") ||
|
||||
patternKey.contains("long-"))) {
|
||||
count = 4;
|
||||
}
|
||||
appendN(cldrLetter, count, sb);
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
if (count == 4 || count == 5) {
|
||||
sb.append("XXX");
|
||||
@@ -767,6 +778,7 @@ class Bundle {
|
||||
.collect(Collectors.toMap(
|
||||
e -> calendarPrefix + e.getKey(),
|
||||
e -> translateDateFormatLetters(calendarType,
|
||||
e.getKey(),
|
||||
(String)e.getValue(),
|
||||
this::convertDateTimePatternLetter)
|
||||
))
|
||||
@@ -775,7 +787,7 @@ class Bundle {
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ConvertDateTimeLetters {
|
||||
void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb);
|
||||
void convert(CalendarType calendarType, String patternKey, char cldrLetter, int count, StringBuilder sb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,6 +65,7 @@ ifeq ($(call isTargetOs, aix), false)
|
||||
CXXFLAGS := $(LIBJSOUND_CFLAGS), \
|
||||
DISABLED_WARNINGS_gcc := undef unused-variable, \
|
||||
DISABLED_WARNINGS_clang := undef unused-variable, \
|
||||
DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_Ports.cpp := vla-cxx-extension, \
|
||||
DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_MidiUtils.c := \
|
||||
unused-but-set-variable, \
|
||||
DISABLED_WARNINGS_clang_DirectAudioDevice.c := unused-function, \
|
||||
|
||||
@@ -33,10 +33,12 @@ WAYLAND_BASIC_PROTOCOL_FILES := \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/stable/viewporter/viewporter.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/stable/xdg-shell/xdg-shell.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-activation/xdg-activation-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/primary-selection/primary-selection-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-output/xdg-output-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/relative-pointer/relative-pointer-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/text-input/text-input-unstable-v3.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml \
|
||||
$(GTK_SHELL1_PROTOCOL_PATH) \
|
||||
#
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
$(TOPDIR)/src/$(MODULE)/share/native/common/font \
|
||||
$(TOPDIR)/src/$(MODULE)/share/native/common/java2d/opengl \
|
||||
$(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt/systemscale \
|
||||
$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/launcher \
|
||||
#
|
||||
endif
|
||||
|
||||
@@ -102,6 +101,7 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
LIBAWT_RCFLAGS ?= -I$(TOPDIR)/src/java.base/windows/native/launcher/icons
|
||||
LIBAWT_VERSIONINFO_RESOURCE := \
|
||||
$(TOPDIR)/src/$(MODULE)/windows/native/libawt/windows/awt.rc
|
||||
LIBAWT_EXTRA_HEADER_DIRS += $(TOPDIR)/src/java.base/windows/native/launcher
|
||||
endif
|
||||
|
||||
# This is the object file to provide the dladdr API, which is not
|
||||
|
||||
@@ -5344,42 +5344,6 @@ void MacroAssembler::add2_with_carry(Register final_dest_hi, Register dest_hi, R
|
||||
add(final_dest_hi, dest_hi, carry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply 32 bit by 32 bit first loop.
|
||||
*/
|
||||
void MacroAssembler::multiply_32_x_32_loop(Register x, Register xstart, Register x_xstart,
|
||||
Register y, Register y_idx, Register z,
|
||||
Register carry, Register product,
|
||||
Register idx, Register kdx) {
|
||||
// jlong carry, x[], y[], z[];
|
||||
// for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx--, kdx--) {
|
||||
// long product = y[idx] * x[xstart] + carry;
|
||||
// z[kdx] = (int)product;
|
||||
// carry = product >>> 32;
|
||||
// }
|
||||
// z[xstart] = (int)carry;
|
||||
|
||||
Label L_first_loop, L_first_loop_exit;
|
||||
blez(idx, L_first_loop_exit);
|
||||
|
||||
shadd(t0, xstart, x, t0, LogBytesPerInt);
|
||||
lwu(x_xstart, Address(t0, 0));
|
||||
|
||||
bind(L_first_loop);
|
||||
subiw(idx, idx, 1);
|
||||
shadd(t0, idx, y, t0, LogBytesPerInt);
|
||||
lwu(y_idx, Address(t0, 0));
|
||||
mul(product, x_xstart, y_idx);
|
||||
add(product, product, carry);
|
||||
srli(carry, product, 32);
|
||||
subiw(kdx, kdx, 1);
|
||||
shadd(t0, kdx, z, t0, LogBytesPerInt);
|
||||
sw(product, Address(t0, 0));
|
||||
bgtz(idx, L_first_loop);
|
||||
|
||||
bind(L_first_loop_exit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply 64 bit by 64 bit first loop.
|
||||
*/
|
||||
@@ -5596,77 +5560,16 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi
|
||||
const Register carry = tmp5;
|
||||
const Register product = xlen;
|
||||
const Register x_xstart = tmp0;
|
||||
const Register jdx = tmp1;
|
||||
|
||||
mv(idx, ylen); // idx = ylen;
|
||||
addw(kdx, xlen, ylen); // kdx = xlen+ylen;
|
||||
mv(carry, zr); // carry = 0;
|
||||
|
||||
Label L_multiply_64_x_64_loop, L_done;
|
||||
|
||||
Label L_done;
|
||||
subiw(xstart, xlen, 1);
|
||||
bltz(xstart, L_done);
|
||||
|
||||
const Register jdx = tmp1;
|
||||
|
||||
if (AvoidUnalignedAccesses) {
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_INT);
|
||||
assert((base_offset % (UseCompactObjectHeaders ? 4 :
|
||||
(UseCompressedClassPointers ? 8 : 4))) == 0, "Must be");
|
||||
|
||||
if ((base_offset % 8) == 0) {
|
||||
// multiply_64_x_64_loop emits 8-byte load/store to access two elements
|
||||
// at a time from int arrays x and y. When base_offset is 8 bytes, these
|
||||
// accesses are naturally aligned if both xlen and ylen are even numbers.
|
||||
orr(t0, xlen, ylen);
|
||||
test_bit(t0, t0, 0);
|
||||
beqz(t0, L_multiply_64_x_64_loop);
|
||||
}
|
||||
|
||||
Label L_second_loop_unaligned, L_third_loop, L_third_loop_exit;
|
||||
|
||||
multiply_32_x_32_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx);
|
||||
shadd(t0, xstart, z, t0, LogBytesPerInt);
|
||||
sw(carry, Address(t0, 0));
|
||||
|
||||
bind(L_second_loop_unaligned);
|
||||
mv(carry, zr);
|
||||
mv(jdx, ylen);
|
||||
subiw(xstart, xstart, 1);
|
||||
bltz(xstart, L_done);
|
||||
|
||||
subi(sp, sp, 2 * wordSize);
|
||||
sd(z, Address(sp, 0));
|
||||
sd(zr, Address(sp, wordSize));
|
||||
shadd(t0, xstart, z, t0, LogBytesPerInt);
|
||||
addi(z, t0, 4);
|
||||
shadd(t0, xstart, x, t0, LogBytesPerInt);
|
||||
lwu(product, Address(t0, 0));
|
||||
|
||||
blez(jdx, L_third_loop_exit);
|
||||
|
||||
bind(L_third_loop);
|
||||
subiw(jdx, jdx, 1);
|
||||
shadd(t0, jdx, y, t0, LogBytesPerInt);
|
||||
lwu(t0, Address(t0, 0));
|
||||
mul(t1, t0, product);
|
||||
add(t0, t1, carry);
|
||||
shadd(tmp6, jdx, z, t1, LogBytesPerInt);
|
||||
lwu(t1, Address(tmp6, 0));
|
||||
add(t0, t0, t1);
|
||||
sw(t0, Address(tmp6, 0));
|
||||
srli(carry, t0, 32);
|
||||
bgtz(jdx, L_third_loop);
|
||||
|
||||
bind(L_third_loop_exit);
|
||||
ld(z, Address(sp, 0));
|
||||
addi(sp, sp, 2 * wordSize);
|
||||
shadd(t0, xstart, z, t0, LogBytesPerInt);
|
||||
sw(carry, Address(t0, 0));
|
||||
|
||||
j(L_second_loop_unaligned);
|
||||
}
|
||||
|
||||
bind(L_multiply_64_x_64_loop);
|
||||
multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx);
|
||||
|
||||
Label L_second_loop_aligned;
|
||||
|
||||
@@ -1384,10 +1384,6 @@ public:
|
||||
void adc(Register dst, Register src1, Register src2, Register carry);
|
||||
void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo,
|
||||
Register src1, Register src2, Register carry);
|
||||
void multiply_32_x_32_loop(Register x, Register xstart, Register x_xstart,
|
||||
Register y, Register y_idx, Register z,
|
||||
Register carry, Register product,
|
||||
Register idx, Register kdx);
|
||||
void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart,
|
||||
Register y, Register y_idx, Register z,
|
||||
Register carry, Register product,
|
||||
|
||||
@@ -8431,6 +8431,17 @@ instruct castVV(vReg dst)
|
||||
ins_pipe(pipe_class_empty);
|
||||
%}
|
||||
|
||||
instruct castVVMask(vRegMask dst)
|
||||
%{
|
||||
match(Set dst (CastVV dst));
|
||||
|
||||
size(0);
|
||||
format %{ "# castVV of $dst" %}
|
||||
ins_encode(/* empty encoding */);
|
||||
ins_cost(0);
|
||||
ins_pipe(pipe_class_empty);
|
||||
%}
|
||||
|
||||
// ============================================================================
|
||||
// Convert Instructions
|
||||
|
||||
|
||||
@@ -203,15 +203,15 @@ void VM_Version::common_initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Misc Intrinsics could depend on RVV
|
||||
// Misc Intrinsics that could depend on RVV.
|
||||
|
||||
if (UseZba || UseRVV) {
|
||||
if (!AvoidUnalignedAccesses && (UseZba || UseRVV)) {
|
||||
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
|
||||
}
|
||||
} else {
|
||||
if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
|
||||
warning("CRC32 intrinsic requires Zba or RVV instructions (not available on this CPU)");
|
||||
warning("CRC32 intrinsic are not available on this CPU.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
|
||||
}
|
||||
@@ -325,20 +325,40 @@ void VM_Version::c2_initialize() {
|
||||
FLAG_SET_DEFAULT(UseMulAddIntrinsic, true);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
|
||||
if (!AvoidUnalignedAccesses) {
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
|
||||
}
|
||||
} else if (UseMultiplyToLenIntrinsic) {
|
||||
warning("Intrinsics for BigInteger.multiplyToLen() not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true);
|
||||
if (!AvoidUnalignedAccesses) {
|
||||
if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true);
|
||||
}
|
||||
} else if (UseSquareToLenIntrinsic) {
|
||||
warning("Intrinsics for BigInteger.squareToLen() not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, false);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true);
|
||||
if (!AvoidUnalignedAccesses) {
|
||||
if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true);
|
||||
}
|
||||
} else if (UseMontgomeryMultiplyIntrinsic) {
|
||||
warning("Intrinsics for BigInteger.montgomeryMultiply() not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true);
|
||||
if (!AvoidUnalignedAccesses) {
|
||||
if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true);
|
||||
}
|
||||
} else if (UseMontgomerySquareIntrinsic) {
|
||||
warning("Intrinsics for BigInteger.montgomerySquare() not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false);
|
||||
}
|
||||
|
||||
// Adler32
|
||||
|
||||
@@ -352,16 +352,6 @@ void ClassLoaderDataGraph::verify_dictionary() {
|
||||
}
|
||||
}
|
||||
|
||||
// (DCEVM) - iterate over dict classes
|
||||
void ClassLoaderDataGraph::dictionary_classes_do(KlassClosure* klass_closure) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
if (cld->dictionary() != nullptr) {
|
||||
cld->dictionary()->classes_do(klass_closure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (DCEVM) rollback redefined classes
|
||||
void ClassLoaderDataGraph::rollback_redefinition() {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
@@ -373,17 +363,27 @@ void ClassLoaderDataGraph::rollback_redefinition() {
|
||||
}
|
||||
|
||||
// (DCEVM) - iterate over all classes in all dictionaries
|
||||
bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass) {
|
||||
bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old) {
|
||||
bool ok = false;
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
if (cld->dictionary() != nullptr) {
|
||||
ok = cld->dictionary()->update_klass(current, name, k, old_klass) || ok;
|
||||
ok = cld->dictionary()->update_klass(current, name, k, old_klass, check_old) || ok;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// (DCEVM) - iterate over all classes in all dictionaries
|
||||
void ClassLoaderDataGraph::dictionary_classes_do_classes_do_safepoint(void f(InstanceKlass* const)) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
if (cld->dictionary() != nullptr) {
|
||||
cld->dictionary()->classes_do_safepoint(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData *cld = iter.get_next()) {
|
||||
|
||||
@@ -102,9 +102,9 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
static void walk_metadata_and_clean_metaspaces();
|
||||
|
||||
// (DCEVM) Enhanced class redefinition
|
||||
static void dictionary_classes_do(KlassClosure* klass_closure);
|
||||
static void rollback_redefinition();
|
||||
static bool dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass);
|
||||
static bool dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old);
|
||||
static void dictionary_classes_do_classes_do_safepoint(void f(InstanceKlass* const));
|
||||
|
||||
static void verify_dictionary();
|
||||
static void print_dictionary(outputStream* st);
|
||||
|
||||
@@ -211,15 +211,23 @@ class UpdateKlassDcevm : public StackObj {
|
||||
InstanceKlass* _new_klass;
|
||||
InstanceKlass* _old_klass;
|
||||
bool _replaced;
|
||||
bool _check_old;
|
||||
public:
|
||||
UpdateKlassDcevm(InstanceKlass* new_klass, InstanceKlass* old_klass) :
|
||||
UpdateKlassDcevm(InstanceKlass* new_klass, InstanceKlass* old_klass, bool check_old) :
|
||||
_new_klass(new_klass),
|
||||
_old_klass(old_klass),
|
||||
_replaced(false) {
|
||||
_replaced(false),
|
||||
_check_old(check_old) {
|
||||
}
|
||||
|
||||
void operator()(InstanceKlass** old_table_value) {
|
||||
assert(*old_table_value == _old_klass, "should be old class");
|
||||
InstanceKlass* table_class = *old_table_value;
|
||||
assert(!_check_old || table_class == _old_klass, "should be old class");
|
||||
assert(table_class->class_loader_data() == _new_klass->class_loader_data(), "Must be same class loader");
|
||||
if (!_check_old && table_class->new_version() != nullptr) {
|
||||
ResourceMark rm;
|
||||
log_debug(redefine, class, redefine, metadata)("Updating old class from doit() %s", table_class->name()->as_C_string());
|
||||
}
|
||||
*old_table_value = _new_klass;
|
||||
_replaced = true;
|
||||
}
|
||||
@@ -230,14 +238,14 @@ public:
|
||||
};
|
||||
|
||||
// (DCEVM) replace old_class by new class in dictionary
|
||||
bool Dictionary::update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass) {
|
||||
UpdateKlassDcevm found(k, old_klass);
|
||||
bool Dictionary::update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old) {
|
||||
UpdateKlassDcevm found(k, old_klass, check_old);
|
||||
|
||||
DictionaryLookup lookup(class_name);
|
||||
InstanceKlass* result = nullptr;
|
||||
bool needs_rehashing = false;
|
||||
bool ret = _table->insert_get(current, lookup, old_klass, found);
|
||||
return ret || found.get_replaced();
|
||||
// (DCEVM): old_klass is replaced with the new one in UpdateKlassDcevm::operator(),
|
||||
// which is invoked when class_name is found in the dictionary.
|
||||
bool exists = _table->get(current, lookup, found);
|
||||
return exists && found.get_replaced();
|
||||
}
|
||||
|
||||
class RollBackDcevm : public StackObj {
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
void verify();
|
||||
|
||||
// (DCEVM) Enhanced class redefinition
|
||||
bool update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass);
|
||||
bool update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old);
|
||||
|
||||
void rollback_redefinition();
|
||||
private:
|
||||
|
||||
@@ -1507,7 +1507,7 @@ BasicType java_lang_Class::as_BasicType(oop java_class, Klass** reference_klass)
|
||||
oop java_lang_Class::primitive_mirror(BasicType t) {
|
||||
oop mirror = Universe::java_mirror(t);
|
||||
assert(mirror != nullptr && (mirror->is_a(vmClasses::Class_klass())
|
||||
|| (Universe::is_inside_redefinition() && vmClasses::Class_klass()->old_version() != NULL && mirror->is_a(vmClasses::Class_klass()->old_version()))), "must be a Class");
|
||||
|| (Universe::is_inside_redefinition() && vmClasses::Class_klass()->old_version() != nullptr && mirror->is_a(vmClasses::Class_klass()->old_version()))), "must be a Class");
|
||||
assert(is_primitive(mirror), "must be primitive");
|
||||
return mirror;
|
||||
}
|
||||
|
||||
@@ -132,8 +132,16 @@ bool StackMapTable::match_stackmap(
|
||||
}
|
||||
|
||||
void StackMapTable::check_jump_target(
|
||||
StackMapFrame* frame, int32_t target, TRAPS) const {
|
||||
StackMapFrame* frame, int bci, int offset, TRAPS) const {
|
||||
ErrorContext ctx;
|
||||
// Jump targets must be within the method and the method size is limited. See JVMS 4.11
|
||||
int min_offset = -1 * max_method_code_size;
|
||||
if (offset < min_offset || offset > max_method_code_size) {
|
||||
frame->verifier()->verify_error(ErrorContext::bad_stackmap(bci, frame),
|
||||
"Illegal target of jump or branch (bci %d + offset %d)", bci, offset);
|
||||
return;
|
||||
}
|
||||
int target = bci + offset;
|
||||
bool match = match_stackmap(
|
||||
frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier()));
|
||||
if (!match || (target < 0 || target >= _code_length)) {
|
||||
|
||||
@@ -67,7 +67,7 @@ class StackMapTable : public StackObj {
|
||||
|
||||
// Check jump instructions. Make sure there are no uninitialized
|
||||
// instances on backward branch.
|
||||
void check_jump_target(StackMapFrame* frame, int32_t target, TRAPS) const;
|
||||
void check_jump_target(StackMapFrame* frame, int bci, int offset, TRAPS) const;
|
||||
|
||||
// The following methods are only used inside this class.
|
||||
|
||||
|
||||
@@ -1360,7 +1360,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, InstanceKlass* ol
|
||||
|
||||
ClassLoaderData* loader_data = k->class_loader_data();
|
||||
assert(loader_data->class_loader() == class_loader(), "they must be the same");
|
||||
bool is_redefining = (old_klass != NULL);
|
||||
bool is_redefining = (old_klass != nullptr);
|
||||
|
||||
// Bootstrap and other parallel classloaders don't acquire a lock,
|
||||
// they use placeholder token.
|
||||
@@ -1386,10 +1386,9 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, InstanceKlass* ol
|
||||
if (is_redefining) {
|
||||
// Update all dictionaries containing old_class to new_class
|
||||
// outcome must be same as result of standard redefinition, that does not create a new Klass
|
||||
ClassLoaderDataGraph_lock->lock();
|
||||
MutexLocker lock(ClassLoaderDataGraph_lock);
|
||||
Symbol* name_h = k->name();
|
||||
bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(THREAD, name_h, k, old_klass);
|
||||
ClassLoaderDataGraph_lock->unlock();
|
||||
bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(THREAD, name_h, k, old_klass, true);
|
||||
assert (ok, "must have found old class and updated!");
|
||||
}
|
||||
check_constraints(k, loader_data, !is_redefining, CHECK);
|
||||
@@ -1487,7 +1486,7 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
|
||||
}
|
||||
}
|
||||
|
||||
define_instance_class(k, NULL, class_loader, THREAD);
|
||||
define_instance_class(k, nullptr, class_loader, THREAD);
|
||||
|
||||
// definer must notify any waiting threads
|
||||
{
|
||||
@@ -1527,7 +1526,7 @@ InstanceKlass* SystemDictionary::find_or_define_instance_class(Symbol* class_nam
|
||||
|
||||
// (DCEVM) - remove from klass hierarchy
|
||||
void SystemDictionary::remove_from_hierarchy(InstanceKlass* k) {
|
||||
assert(k != NULL, "just checking");
|
||||
assert(k != nullptr, "just checking");
|
||||
|
||||
// remove receiver from sibling list
|
||||
k->remove_from_sibling_list();
|
||||
|
||||
@@ -781,7 +781,6 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) {
|
||||
|
||||
// Merge with the next instruction
|
||||
{
|
||||
int target;
|
||||
VerificationType type, type2;
|
||||
VerificationType atype;
|
||||
|
||||
@@ -1606,9 +1605,8 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) {
|
||||
case Bytecodes::_ifle:
|
||||
current_frame.pop_stack(
|
||||
VerificationType::integer_type(), CHECK_VERIFY(this));
|
||||
target = bcs.dest();
|
||||
stackmap_table.check_jump_target(
|
||||
¤t_frame, target, CHECK_VERIFY(this));
|
||||
¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this));
|
||||
no_control_flow = false; break;
|
||||
case Bytecodes::_if_acmpeq :
|
||||
case Bytecodes::_if_acmpne :
|
||||
@@ -1619,19 +1617,16 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) {
|
||||
case Bytecodes::_ifnonnull :
|
||||
current_frame.pop_stack(
|
||||
VerificationType::reference_check(), CHECK_VERIFY(this));
|
||||
target = bcs.dest();
|
||||
stackmap_table.check_jump_target
|
||||
(¤t_frame, target, CHECK_VERIFY(this));
|
||||
(¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this));
|
||||
no_control_flow = false; break;
|
||||
case Bytecodes::_goto :
|
||||
target = bcs.dest();
|
||||
stackmap_table.check_jump_target(
|
||||
¤t_frame, target, CHECK_VERIFY(this));
|
||||
¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this));
|
||||
no_control_flow = true; break;
|
||||
case Bytecodes::_goto_w :
|
||||
target = bcs.dest_w();
|
||||
stackmap_table.check_jump_target(
|
||||
¤t_frame, target, CHECK_VERIFY(this));
|
||||
¤t_frame, bcs.bci(), bcs.get_offset_s4(), CHECK_VERIFY(this));
|
||||
no_control_flow = true; break;
|
||||
case Bytecodes::_tableswitch :
|
||||
case Bytecodes::_lookupswitch :
|
||||
@@ -2280,15 +2275,14 @@ void ClassVerifier::verify_switch(
|
||||
}
|
||||
}
|
||||
}
|
||||
int target = bci + default_offset;
|
||||
stackmap_table->check_jump_target(current_frame, target, CHECK_VERIFY(this));
|
||||
stackmap_table->check_jump_target(current_frame, bci, default_offset, CHECK_VERIFY(this));
|
||||
for (int i = 0; i < keys; i++) {
|
||||
// Because check_jump_target() may safepoint, the bytecode could have
|
||||
// moved, which means 'aligned_bcp' is no good and needs to be recalculated.
|
||||
aligned_bcp = align_up(bcs->bcp() + 1, jintSize);
|
||||
target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
|
||||
int offset = (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
|
||||
stackmap_table->check_jump_target(
|
||||
current_frame, target, CHECK_VERIFY(this));
|
||||
current_frame, bci, offset, CHECK_VERIFY(this));
|
||||
}
|
||||
NOT_PRODUCT(aligned_bcp = nullptr); // no longer valid at this point
|
||||
}
|
||||
@@ -2549,7 +2543,12 @@ bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
|
||||
|
||||
case Bytecodes::_goto:
|
||||
case Bytecodes::_goto_w: {
|
||||
int target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
|
||||
int offset = (opcode == Bytecodes::_goto ? bcs.get_offset_s2() : bcs.get_offset_s4());
|
||||
int min_offset = -1 * max_method_code_size;
|
||||
// Check offset for overflow
|
||||
if (offset < min_offset || offset > max_method_code_size) return false;
|
||||
|
||||
int target = bci + offset;
|
||||
if (visited_branches->contains(bci)) {
|
||||
if (bci_stack->is_empty()) {
|
||||
if (handler_stack->is_empty()) {
|
||||
@@ -2607,7 +2606,10 @@ bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
|
||||
|
||||
// Push the switch alternatives onto the stack.
|
||||
for (int i = 0; i < keys; i++) {
|
||||
int target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
|
||||
int min_offset = -1 * max_method_code_size;
|
||||
int offset = (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
|
||||
if (offset < min_offset || offset > max_method_code_size) return false;
|
||||
int target = bci + offset;
|
||||
if (target > code_length) return false;
|
||||
bci_stack->push(target);
|
||||
}
|
||||
|
||||
@@ -2353,7 +2353,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
}
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
// Skip redefined methods
|
||||
if (task->method()->is_old() || task->method()->method_holder()->new_version() != NULL) {
|
||||
if (task->method()->is_old() || task->method()->method_holder()->new_version() != nullptr) {
|
||||
ci_env.record_method_not_compilable("redefined method", true);
|
||||
} else {
|
||||
comp->compile_method(&ci_env, target, osr_bci, true, directive);
|
||||
|
||||
@@ -231,11 +231,11 @@ uint G1FullGCCompactionPoint::find_contiguous_before(G1HeapRegion* hr, uint num_
|
||||
}
|
||||
|
||||
HeapWord* G1FullGCCompactionPoint::forward_compact_top(size_t size) {
|
||||
assert(_current_region != NULL, "Must have been initialized");
|
||||
assert(_current_region != nullptr, "Must have been initialized");
|
||||
// Ensure the object fit in the current region.
|
||||
while (!object_will_fit(size)) {
|
||||
if (!_compaction_region_iterator.has_next()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
switch_region();
|
||||
}
|
||||
@@ -243,7 +243,7 @@ HeapWord* G1FullGCCompactionPoint::forward_compact_top(size_t size) {
|
||||
}
|
||||
|
||||
void G1FullGCCompactionPoint::forward_dcevm(oop object, size_t size, bool force_forward) {
|
||||
assert(_current_region != NULL, "Must have been initialized");
|
||||
assert(_current_region != nullptr, "Must have been initialized");
|
||||
|
||||
// Ensure the object fit in the current region.
|
||||
while (!object_will_fit(size)) {
|
||||
|
||||
@@ -1936,7 +1936,7 @@ void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAlloca
|
||||
}
|
||||
|
||||
const size_t committed = allocation->committed_capacity();
|
||||
const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested());
|
||||
const ZVirtualMemory non_harvested_vmem = partial_vmem.last_part(allocation->harvested());
|
||||
const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed);
|
||||
const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed);
|
||||
|
||||
|
||||
@@ -214,9 +214,20 @@ void ZPhysicalMemoryManager::free(const ZVirtualMemory& vmem, uint32_t numa_id)
|
||||
});
|
||||
}
|
||||
|
||||
static size_t inject_commit_limit(const ZVirtualMemory& vmem) {
|
||||
// To facilitate easier interoperability with multi partition allocations we
|
||||
// divide by ZNUMA::count(). Users of ZFailLargerCommits need to be aware of
|
||||
// this when writing tests. In the future we could probe the VirtualMemoryManager
|
||||
// and condition this division on whether the vmem is in the multi partition
|
||||
// address space.
|
||||
return align_up(MIN2(ZFailLargerCommits / ZNUMA::count(), vmem.size()), ZGranuleSize);
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryManager::commit(const ZVirtualMemory& vmem, uint32_t numa_id) {
|
||||
zbacking_index* const pmem = _physical_mappings.addr(vmem.start());
|
||||
const size_t size = vmem.size();
|
||||
const size_t size = ZFailLargerCommits > 0
|
||||
? inject_commit_limit(vmem)
|
||||
: vmem.size();
|
||||
|
||||
size_t total_committed = 0;
|
||||
|
||||
|
||||
@@ -118,6 +118,11 @@
|
||||
develop(bool, ZVerifyOops, false, \
|
||||
"Verify accessed oops") \
|
||||
\
|
||||
develop(size_t, ZFailLargerCommits, 0, \
|
||||
"Commits larger than ZFailLargerCommits will be truncated, " \
|
||||
"used to stress page allocation commit failure paths " \
|
||||
"(0: Disabled)") \
|
||||
\
|
||||
develop(uint, ZFakeNUMA, 1, \
|
||||
"ZFakeNUMA is used to test the internal NUMA memory support " \
|
||||
"without the need for UseNUMA") \
|
||||
|
||||
@@ -100,8 +100,23 @@ class BaseBytecodeStream: StackObj {
|
||||
void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; }
|
||||
|
||||
// Bytecode-specific attributes
|
||||
int dest() const { return bci() + bytecode().get_offset_s2(raw_code()); }
|
||||
int dest_w() const { return bci() + bytecode().get_offset_s4(raw_code()); }
|
||||
int get_offset_s2() const { return bytecode().get_offset_s2(raw_code()); }
|
||||
int get_offset_s4() const { return bytecode().get_offset_s4(raw_code()); }
|
||||
|
||||
// These methods are not safe to use before or during verification as they may
|
||||
// have large offsets and cause overflows
|
||||
int dest() const {
|
||||
int min_offset = -1 * max_method_code_size;
|
||||
int offset = bytecode().get_offset_s2(raw_code());
|
||||
guarantee(offset >= min_offset && offset <= max_method_code_size, "must be");
|
||||
return bci() + offset;
|
||||
}
|
||||
int dest_w() const {
|
||||
int min_offset = -1 * max_method_code_size;
|
||||
int offset = bytecode().get_offset_s4(raw_code());
|
||||
guarantee(offset >= min_offset && offset <= max_method_code_size, "must be");
|
||||
return bci() + offset;
|
||||
}
|
||||
|
||||
// One-byte indices.
|
||||
u1 get_index_u1() const { assert_raw_index_size(1); return *(jubyte*)(bcp()+1); }
|
||||
|
||||
@@ -521,7 +521,7 @@ void Klass::initialize_supers(Klass* k, Array<InstanceKlass*>* transitive_interf
|
||||
_primary_supers[0] = this;
|
||||
assert(super_depth() == 0, "Object must already be initialized properly");
|
||||
} else if (k != super() || k == vmClasses::Object_klass() || (k->is_redefining() && k == vmClasses::Object_klass()->newest_version())) {
|
||||
assert(super() == NULL || super() == vmClasses::Object_klass() || (k->is_redefining() && super() == vmClasses::Object_klass()->newest_version()),
|
||||
assert(super() == nullptr || super() == vmClasses::Object_klass() || (k->is_redefining() && super() == vmClasses::Object_klass()->newest_version()),
|
||||
"initialize this only once to a non-trivial value");
|
||||
set_super(k);
|
||||
Klass* sup = k;
|
||||
@@ -1388,18 +1388,18 @@ void Klass::on_secondary_supers_verification_failure(Klass* super, Klass* sub, b
|
||||
}
|
||||
|
||||
void Klass::update_supers_dcevm() {
|
||||
if (_super != NULL) {
|
||||
if (_super != nullptr) {
|
||||
_super = _super->newest_version();
|
||||
}
|
||||
int sup_depth = super_depth();
|
||||
for (int idx = 0; idx < sup_depth; idx++) {
|
||||
Klass* primary = _primary_supers[idx];
|
||||
if (primary == NULL) {
|
||||
if (primary == nullptr) {
|
||||
break;
|
||||
}
|
||||
_primary_supers[idx] = primary->newest_version();
|
||||
}
|
||||
if (secondary_super_cache() != NULL) {
|
||||
if (secondary_super_cache() != nullptr) {
|
||||
set_secondary_super_cache(secondary_super_cache()->newest_version());
|
||||
}
|
||||
|
||||
|
||||
@@ -432,6 +432,9 @@ protected:
|
||||
const Klass* newest_version() const { return _new_version == nullptr ? this : _new_version->newest_version(); }
|
||||
Klass* newest_version() { return _new_version == nullptr ? this : _new_version->newest_version(); }
|
||||
|
||||
const Klass* oldest_version() const { return _old_version == nullptr ? this : _old_version->oldest_version(); }
|
||||
Klass* oldest_version() { return _old_version == nullptr ? this : _old_version->oldest_version(); }
|
||||
|
||||
const Klass* active_version() const { return _new_version == nullptr || _new_version->is_redefining() ? this : _new_version->active_version(); }
|
||||
Klass* active_version() { return _new_version == nullptr || _new_version->is_redefining() ? this : _new_version->active_version(); }
|
||||
|
||||
|
||||
@@ -1575,9 +1575,14 @@ bool LibraryCallKit::inline_string_toBytesU() {
|
||||
Node* src_start = array_element_address(value, offset, T_CHAR);
|
||||
Node* dst_start = basic_plus_adr(newcopy, arrayOopDesc::base_offset_in_bytes(T_BYTE));
|
||||
|
||||
// Check if src array address is aligned to HeapWordSize (dst is always aligned)
|
||||
const TypeInt* toffset = gvn().type(offset)->is_int();
|
||||
bool aligned = toffset->is_con() && ((toffset->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
|
||||
// Check if dst array address is aligned to HeapWordSize
|
||||
bool aligned = (arrayOopDesc::base_offset_in_bytes(T_BYTE) % HeapWordSize == 0);
|
||||
// If true, then check if src array address is aligned to HeapWordSize
|
||||
if (aligned) {
|
||||
const TypeInt* toffset = gvn().type(offset)->is_int();
|
||||
aligned = toffset->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_CHAR) +
|
||||
toffset->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
|
||||
}
|
||||
|
||||
// Figure out which arraycopy runtime method to call (disjoint, uninitialized).
|
||||
const char* copyfunc_name = "arraycopy";
|
||||
@@ -1658,8 +1663,8 @@ bool LibraryCallKit::inline_string_getCharsU() {
|
||||
// Check if array addresses are aligned to HeapWordSize
|
||||
const TypeInt* tsrc = gvn().type(src_begin)->is_int();
|
||||
const TypeInt* tdst = gvn().type(dst_begin)->is_int();
|
||||
bool aligned = tsrc->is_con() && ((tsrc->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0) &&
|
||||
tdst->is_con() && ((tdst->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
|
||||
bool aligned = tsrc->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_BYTE) + tsrc->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0) &&
|
||||
tdst->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_CHAR) + tdst->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
|
||||
|
||||
// Figure out which arraycopy runtime method to call (disjoint, uninitialized).
|
||||
const char* copyfunc_name = "arraycopy";
|
||||
|
||||
@@ -1473,9 +1473,14 @@ void PhaseStringOpts::arraycopy(GraphKit& kit, IdealKit& ideal, Node* src_array,
|
||||
|
||||
Node* src_ptr = __ array_element_address(src_array, __ intcon(0), T_BYTE);
|
||||
Node* dst_ptr = __ array_element_address(dst_array, start, T_BYTE);
|
||||
// Check if destination address is aligned to HeapWordSize
|
||||
const TypeInt* tdst = __ gvn().type(start)->is_int();
|
||||
bool aligned = tdst->is_con() && ((tdst->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0);
|
||||
// Check if src array address is aligned to HeapWordSize
|
||||
bool aligned = (arrayOopDesc::base_offset_in_bytes(T_BYTE) % HeapWordSize == 0);
|
||||
// If true, then check if dst array address is aligned to HeapWordSize
|
||||
if (aligned) {
|
||||
const TypeInt* tdst = __ gvn().type(start)->is_int();
|
||||
aligned = tdst->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_BYTE) +
|
||||
tdst->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0);
|
||||
}
|
||||
// Figure out which arraycopy runtime method to call (disjoint, uninitialized).
|
||||
const char* copyfunc_name = "arraycopy";
|
||||
address copyfunc_addr = StubRoutines::select_arraycopy_function(elembt, aligned, true, copyfunc_name, true);
|
||||
|
||||
@@ -218,9 +218,7 @@ intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, int offset) {
|
||||
DEBUG_ONLY(NoSafepointVerifier nosafepoint;)
|
||||
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
while (field_klass->old_version() != NULL) {
|
||||
field_klass = field_klass->old_version();
|
||||
}
|
||||
field_klass = field_klass->oldest_version();
|
||||
}
|
||||
uintptr_t klass_hash = field_klass->identity_hash();
|
||||
return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place;
|
||||
@@ -242,9 +240,9 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
|
||||
intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask;
|
||||
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
while (k->old_version() != NULL) {
|
||||
k = k->old_version();
|
||||
}
|
||||
// DCEVM: use the oldest class version so all pre-existing IDs
|
||||
// from old classes match IDs of the new (current) class.
|
||||
k = k->oldest_version();
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -253,6 +251,11 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
|
||||
if ((k->identity_hash() & klass_mask) == klass_hash)
|
||||
return true;
|
||||
k = k->super();
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
// DCEVM: Same for each superclass: normalize to the oldest version
|
||||
// so old IDs match the new class IDs.
|
||||
k = k->oldest_version();
|
||||
}
|
||||
} while (k != nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "oops/constantPool.inline.hpp"
|
||||
#if INCLUDE_G1GC
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#endif
|
||||
@@ -695,6 +694,16 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
new_class->old_version()->set_new_version(new_class);
|
||||
}
|
||||
|
||||
// Update Dictionaries to ensure all references contain the new class versions.
|
||||
// During load_new_class_versions(), another thread may have loaded an old version, so this pass replaces
|
||||
// any remaining old ones.
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
InstanceKlass* new_class = _new_classes->at(i);
|
||||
InstanceKlass* old_class = InstanceKlass::cast(new_class->old_version());
|
||||
Symbol *name_h = new_class->name();
|
||||
ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread::current(), name_h, new_class, old_class, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
Klass* new_class = _new_classes->at(i);
|
||||
redefine_single_class(current, _new_classes->at(i));
|
||||
@@ -917,7 +926,7 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
}
|
||||
}
|
||||
log_trace(redefine, class, redefine, metadata)("calling check_class");
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do_safepoint(check_class);
|
||||
ClassLoaderDataGraph::dictionary_classes_do_classes_do_safepoint(check_class);
|
||||
#ifdef PRODUCT
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1097,6 +1097,22 @@ bool WhiteBox::validate_cgroup(bool cgroups_v2_enabled,
|
||||
}
|
||||
#endif
|
||||
|
||||
bool WhiteBox::is_asan_enabled() {
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WhiteBox::is_ubsan_enabled() {
|
||||
#ifdef UNDEFINED_BEHAVIOR_SANITIZER
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThread* THREAD) {
|
||||
// Screen for unavailable/bad comp level or null method
|
||||
AbstractCompiler* comp = CompileBroker::compiler(comp_level);
|
||||
@@ -1908,6 +1924,14 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
|
||||
return (jboolean) obj_oop->mark().has_monitor();
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_IsAsanEnabled(JNIEnv* env))
|
||||
return (jboolean) WhiteBox::is_asan_enabled();
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_IsUbsanEnabled(JNIEnv* env))
|
||||
return (jboolean) WhiteBox::is_ubsan_enabled();
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jlong, WB_getInUseMonitorCount(JNIEnv* env, jobject wb))
|
||||
return (jlong) WhiteBox::get_in_use_monitor_count();
|
||||
WB_END
|
||||
@@ -2908,6 +2932,8 @@ static JNINativeMethod methods[] = {
|
||||
(void*)&WB_AddModuleExportsToAll },
|
||||
{CC"deflateIdleMonitors", CC"()Z", (void*)&WB_DeflateIdleMonitors },
|
||||
{CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
|
||||
{CC"isAsanEnabled", CC"()Z", (void*)&WB_IsAsanEnabled },
|
||||
{CC"isUbsanEnabled", CC"()Z", (void*)&WB_IsUbsanEnabled },
|
||||
{CC"getInUseMonitorCount", CC"()J", (void*)&WB_getInUseMonitorCount },
|
||||
{CC"getLockStackCapacity", CC"()I", (void*)&WB_getLockStackCapacity },
|
||||
{CC"supportsRecursiveLightweightLocking", CC"()Z", (void*)&WB_supportsRecursiveLightweightLocking },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@@ -72,6 +72,9 @@ class WhiteBox : public AllStatic {
|
||||
#ifdef LINUX
|
||||
static bool validate_cgroup(bool cgroups_v2_enabled, const char* controllers_file, const char* proc_self_cgroup, const char* proc_self_mountinfo, u1* cg_flags);
|
||||
#endif
|
||||
// provide info about enabling of Address Sanitizer / Undefined Behavior Sanitizer
|
||||
static bool is_asan_enabled();
|
||||
static bool is_ubsan_enabled();
|
||||
};
|
||||
|
||||
#endif // SHARE_PRIMS_WHITEBOX_HPP
|
||||
|
||||
@@ -1312,24 +1312,24 @@ void VMError::report(outputStream* st, bool _verbose) {
|
||||
NativeHeapTrimmer::print_state(st);
|
||||
st->cr();
|
||||
|
||||
STEP("JNI global references")
|
||||
st->print_cr("JNI global refs:");
|
||||
JNIHandles::print_on_unsafe(st);
|
||||
JNIHandles::print_memory_usage_on(st);
|
||||
STEP_IF("JNI global references", _verbose)
|
||||
st->print_cr("JNI global refs:");
|
||||
JNIHandles::print_on_unsafe(st);
|
||||
JNIHandles::print_memory_usage_on(st);
|
||||
|
||||
STEP_IF("Process memory usage", _verbose)
|
||||
print_process_memory_usage(st);
|
||||
|
||||
STEP("OOME stack traces")
|
||||
st->print_cr("OOME stack traces (most recent first):");
|
||||
print_oome_stacks(st);
|
||||
STEP_IF("OOME stack traces", _verbose)
|
||||
st->print_cr("OOME stack traces (most recent first):");
|
||||
print_oome_stacks(st);
|
||||
|
||||
STEP("Classloader stats")
|
||||
st->print_cr("Classloader memory used:");
|
||||
FREE_C_HEAP_ARRAY(void*, _ballast_memory);
|
||||
_ballast_memory = nullptr;
|
||||
print_classloaders_stats(st);
|
||||
print_dup_classes(st); // do it separately in case we're low on memory
|
||||
STEP_IF("Classloader stats", _verbose)
|
||||
st->print_cr("Classloader memory used:");
|
||||
FREE_C_HEAP_ARRAY(void*, _ballast_memory);
|
||||
_ballast_memory = nullptr;
|
||||
print_classloaders_stats(st);
|
||||
print_dup_classes(st); // do it separately in case we're low on memory
|
||||
|
||||
STEP_IF("printing system", _verbose)
|
||||
st->print_cr("--------------- S Y S T E M ---------------");
|
||||
|
||||
@@ -159,5 +159,84 @@ public class IoOverNio {
|
||||
* <p>
|
||||
* The problem was found with the test {@code jtreg:test/jdk/java/io/FileDescriptor/Sharing.java}.
|
||||
*/
|
||||
public static final ThreadLocal<Closeable> PARENT_FOR_FILE_CHANNEL_IMPL = new ThreadLocal<>();
|
||||
public static class ParentForFileChannelImplHolder {
|
||||
private static final ThreadLocal<Closeable> holder = new ThreadLocal<>();
|
||||
|
||||
private ParentForFileChannelImplHolder() {}
|
||||
|
||||
public static Closeable get() {
|
||||
return holder.get();
|
||||
}
|
||||
|
||||
public static void set(Closeable parent) {
|
||||
RecursionGuard.ensureActive();
|
||||
holder.set(parent);
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
RecursionGuard.ensureActive();
|
||||
holder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>With java.io over java.nio backend, it's possible that some code invokes file system operations while
|
||||
* already executing a similar operation. An example is when a classloader uses {@link FileSystems#getDefault()}
|
||||
* during class loading. Such cases break usage of {@link ParentForFileChannelImplHolder}.</p>
|
||||
*
|
||||
* <p>This class is to be used around places that can hypothetically access {@link ParentForFileChannelImplHolder}
|
||||
* recursively.</p>
|
||||
*/
|
||||
public static class RecursionGuard implements Closeable {
|
||||
private static final ThreadLocal<RecursionGuard> HEAD = new ThreadLocal<>();
|
||||
|
||||
private final RecursionGuard parent;
|
||||
private final Object label;
|
||||
private final ThreadLocalCloseable additionalClosable;
|
||||
|
||||
/**
|
||||
* @param label A unique object for a specific method. The object is used for reference equality.
|
||||
* A static string or a reference to a class is a good candidate.
|
||||
*/
|
||||
public static RecursionGuard create(Object label) {
|
||||
ThreadLocalCloseable additionalClosable = null;
|
||||
for (var guard = HEAD.get(); guard != null; guard = guard.parent) {
|
||||
if (guard.label == label) {
|
||||
additionalClosable = disableInThisThread();
|
||||
break;
|
||||
}
|
||||
}
|
||||
var result = new RecursionGuard(HEAD.get(), label, additionalClosable);
|
||||
HEAD.set(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private RecursionGuard(RecursionGuard parent, Object label, ThreadLocalCloseable additionalClosable) {
|
||||
this.parent = parent;
|
||||
this.label = label;
|
||||
this.additionalClosable = additionalClosable;
|
||||
}
|
||||
|
||||
public static void ensureActive() {
|
||||
if (HEAD.get() == null) {
|
||||
throw new Error("RecursionGuard is not installed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
HEAD.set(parent);
|
||||
if (additionalClosable != null) {
|
||||
additionalClosable.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended only for suppressing warnings about unused variables.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(Object any) {
|
||||
// Nothing here.
|
||||
}
|
||||
}
|
||||
@@ -156,37 +156,40 @@ public class FileInputStream extends InputStream
|
||||
}
|
||||
path = file.getPath();
|
||||
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
Path nioPath = null;
|
||||
if (nioFs != null && path != null) {
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
isRegularFile = Files.isRegularFile(nioPath);
|
||||
} catch (InvalidPathException _) {
|
||||
// Nothing.
|
||||
try (var guard = IoOverNio.RecursionGuard.create(FileInputStream.class)) {
|
||||
IoOverNio.blackhole(guard);
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
Path nioPath = null;
|
||||
if (nioFs != null && path != null) {
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
isRegularFile = Files.isRegularFile(nioPath);
|
||||
} catch (InvalidPathException _) {
|
||||
// Nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
useNio = nioPath != null && isRegularFile == Boolean.TRUE;
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
useNio = nioPath != null && isRegularFile == Boolean.TRUE;
|
||||
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, Set.of(StandardOpenOption.READ), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(path);
|
||||
FileCleanable.register(fd); // open set the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileInputStream for %s%n", file);
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, Set.of(StandardOpenOption.READ), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(path);
|
||||
FileCleanable.register(fd); // open set the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileInputStream for %s%n", file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -225,46 +225,49 @@ public class FileOutputStream extends OutputStream
|
||||
}
|
||||
this.path = file.getPath();
|
||||
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
useNio = path != null && nioFs != null;
|
||||
if (useNio) {
|
||||
Path nioPath = nioFs.getPath(path);
|
||||
try (var guard = IoOverNio.RecursionGuard.create(FileOutputStream.class)) {
|
||||
IoOverNio.blackhole(guard);
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
useNio = path != null && nioFs != null;
|
||||
if (useNio) {
|
||||
Path nioPath = nioFs.getPath(path);
|
||||
|
||||
// java.io backend doesn't open DOS hidden files for writing, but java.nio.file opens.
|
||||
// This code mimics the old behavior.
|
||||
if (nioFs.getSeparator().equals("\\")) {
|
||||
DosFileAttributes attrs = null;
|
||||
try {
|
||||
var view = Files.getFileAttributeView(nioPath, DosFileAttributeView.class);
|
||||
if (view != null) {
|
||||
attrs = view.readAttributes();
|
||||
// java.io backend doesn't open DOS hidden files for writing, but java.nio.file opens.
|
||||
// This code mimics the old behavior.
|
||||
if (nioFs.getSeparator().equals("\\")) {
|
||||
DosFileAttributes attrs = null;
|
||||
try {
|
||||
var view = Files.getFileAttributeView(nioPath, DosFileAttributeView.class);
|
||||
if (view != null) {
|
||||
attrs = view.readAttributes();
|
||||
}
|
||||
} catch (IOException | UnsupportedOperationException _) {
|
||||
// Windows paths without DOS attributes? Not a problem in this case.
|
||||
}
|
||||
if (attrs != null && (attrs.isHidden() || attrs.isDirectory())) {
|
||||
throw new FileNotFoundException(file.getPath() + " (Access is denied)");
|
||||
}
|
||||
} catch (IOException | UnsupportedOperationException _) {
|
||||
// Windows paths without DOS attributes? Not a problem in this case.
|
||||
}
|
||||
if (attrs != null && (attrs.isHidden() || attrs.isDirectory())) {
|
||||
throw new FileNotFoundException(file.getPath() + " (Access is denied)");
|
||||
}
|
||||
|
||||
Set<OpenOption> options = append
|
||||
? Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
|
||||
: Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, options, channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
this.fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
|
||||
open(this.path, append);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileOutputStream for %s%n", file);
|
||||
}
|
||||
|
||||
Set<OpenOption> options = append
|
||||
? Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
|
||||
: Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, options, channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
this.fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
|
||||
open(this.path, append);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileOutputStream for %s%n", file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -273,10 +273,10 @@ class IoOverNioFileSystem extends FileSystem {
|
||||
try {
|
||||
// This tricky thread local variable allows specifying an argument for sun.nio.ch.FileChannelImpl.<init>
|
||||
// which is not present in the NIO public API and which is not easy to specify another way.
|
||||
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.set(owner);
|
||||
IoOverNio.ParentForFileChannelImplHolder.set(owner);
|
||||
return initializeStreamsUsingNio0(owner, nioFs, file, nioPath, optionsForChannel, channelCleanable);
|
||||
} finally {
|
||||
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.remove();
|
||||
IoOverNio.ParentForFileChannelImplHolder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,7 +876,8 @@ class IoOverNioFileSystem extends FileSystem {
|
||||
|
||||
@Override
|
||||
public boolean delete(File f) {
|
||||
try {
|
||||
try (var guard = IoOverNio.RecursionGuard.create("IoOverNioFileSystem.delete")) {
|
||||
IoOverNio.blackhole(guard);
|
||||
boolean result = delete0(f, true);
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("IoOverNioFileSystem.delete(%s) = %b%n", f, result);
|
||||
|
||||
@@ -279,47 +279,50 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
}
|
||||
path = name;
|
||||
|
||||
FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
Path nioPath = null;
|
||||
if (nioFs != null) {
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
} catch (InvalidPathException _) {
|
||||
// Nothing.
|
||||
try (var guard = IoOverNio.RecursionGuard.create(RandomAccessFile.class)) {
|
||||
IoOverNio.blackhole(guard);
|
||||
FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
Path nioPath = null;
|
||||
if (nioFs != null) {
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
} catch (InvalidPathException _) {
|
||||
// Nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
boolean isRegularFile;
|
||||
try {
|
||||
isRegularFile = nioPath != null &&
|
||||
Files.readAttributes(nioPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isRegularFile();
|
||||
}
|
||||
catch (NoSuchFileException _) {
|
||||
isRegularFile = true;
|
||||
}
|
||||
catch (IOException _) {
|
||||
isRegularFile = false;
|
||||
}
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
boolean isRegularFile;
|
||||
try {
|
||||
isRegularFile = nioPath != null &&
|
||||
Files.readAttributes(nioPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isRegularFile();
|
||||
}
|
||||
catch (NoSuchFileException _) {
|
||||
isRegularFile = true;
|
||||
}
|
||||
catch (IOException _) {
|
||||
isRegularFile = false;
|
||||
}
|
||||
|
||||
useNio = nioPath != null && isRegularFile;
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, optionsForChannel(imode), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(name, imode);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a RandomAccessFile for %s%n", file);
|
||||
useNio = nioPath != null && isRegularFile;
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, optionsForChannel(imode), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(name, imode);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a RandomAccessFile for %s%n", file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1448,8 +1448,8 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
|
||||
shift(currValue, coder, count, dstOffset, len);
|
||||
count += len;
|
||||
// Coder of CharSequence may be a mismatch, requiring the value array to be inflated
|
||||
byte[] newValue = (s instanceof String str)
|
||||
? putStringAt(currValue, coder, count, dstOffset, str, start, end)
|
||||
byte[] newValue = (s instanceof String str && str.length() == len)
|
||||
? putStringAt(currValue, coder, count, dstOffset, str)
|
||||
: putCharsAt(currValue, coder, count, dstOffset, s, start, end);
|
||||
if (currValue != newValue) {
|
||||
this.coder = UTF16;
|
||||
@@ -1928,10 +1928,10 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
|
||||
* @param index the index to insert the string
|
||||
* @param str the string
|
||||
*/
|
||||
private static byte[] putStringAt(byte[] value, byte coder, int count, int index, String str, int off, int end) {
|
||||
private static byte[] putStringAt(byte[] value, byte coder, int count, int index, String str) {
|
||||
byte[] newValue = inflateIfNeededFor(value, count, coder, str.coder());
|
||||
coder = (newValue == value) ? coder : UTF16;
|
||||
str.getBytes(newValue, off, index, coder, end - off);
|
||||
str.getBytes(newValue, 0, index, coder, str.length());
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,11 +182,11 @@ public final class LocalDate
|
||||
/**
|
||||
* @serial The month-of-year.
|
||||
*/
|
||||
private final byte month;
|
||||
private final short month;
|
||||
/**
|
||||
* @serial The day-of-month.
|
||||
*/
|
||||
private final byte day;
|
||||
private final short day;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@@ -490,8 +490,8 @@ public final class LocalDate
|
||||
*/
|
||||
private LocalDate(int year, int month, int dayOfMonth) {
|
||||
this.year = year;
|
||||
this.month = (byte) month;
|
||||
this.day = (byte) dayOfMonth;
|
||||
this.month = (short) month;
|
||||
this.day = (short) dayOfMonth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -146,11 +146,11 @@ public final class MonthDay
|
||||
/**
|
||||
* @serial The month-of-year, not null.
|
||||
*/
|
||||
private final byte month;
|
||||
private final int month;
|
||||
/**
|
||||
* @serial The day-of-month.
|
||||
*/
|
||||
private final byte day;
|
||||
private final int day;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@@ -319,8 +319,8 @@ public final class MonthDay
|
||||
* @param dayOfMonth the day-of-month to represent, validated from 1 to 29-31
|
||||
*/
|
||||
private MonthDay(int month, int dayOfMonth) {
|
||||
this.month = (byte) month;
|
||||
this.day = (byte) dayOfMonth;
|
||||
this.month = month;
|
||||
this.day = dayOfMonth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -153,7 +153,7 @@ public final class YearMonth
|
||||
/**
|
||||
* @serial The month-of-year, not null.
|
||||
*/
|
||||
private final byte month;
|
||||
private final int month;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@@ -306,7 +306,7 @@ public final class YearMonth
|
||||
*/
|
||||
private YearMonth(int year, int month) {
|
||||
this.year = year;
|
||||
this.month = (byte) month;
|
||||
this.month = month;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@@ -137,11 +137,11 @@ public final class HijrahDate
|
||||
/**
|
||||
* The month-of-year.
|
||||
*/
|
||||
private final transient byte monthOfYear;
|
||||
private final transient int monthOfYear;
|
||||
/**
|
||||
* The day-of-month.
|
||||
*/
|
||||
private final transient byte dayOfMonth;
|
||||
private final transient int dayOfMonth;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
@@ -273,8 +273,8 @@ public final class HijrahDate
|
||||
|
||||
this.chrono = chrono;
|
||||
this.prolepticYear = prolepticYear;
|
||||
this.monthOfYear = (byte) monthOfYear;
|
||||
this.dayOfMonth = (byte) dayOfMonth;
|
||||
this.monthOfYear = monthOfYear;
|
||||
this.dayOfMonth = dayOfMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,8 +287,8 @@ public final class HijrahDate
|
||||
|
||||
this.chrono = chrono;
|
||||
this.prolepticYear = dateInfo[0];
|
||||
this.monthOfYear = (byte) dateInfo[1];
|
||||
this.dayOfMonth = (byte) dateInfo[2];
|
||||
this.monthOfYear = dateInfo[1];
|
||||
this.dayOfMonth = dateInfo[2];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -140,7 +140,7 @@ public class FileChannelImpl
|
||||
this.sync = sync;
|
||||
this.direct = direct;
|
||||
if (parent == null) {
|
||||
parent = IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.get();
|
||||
parent = IoOverNio.ParentForFileChannelImplHolder.get();
|
||||
}
|
||||
this.parent = parent;
|
||||
if (direct) {
|
||||
|
||||
@@ -859,6 +859,22 @@ public class DerValue {
|
||||
return readStringInternal(tag_UniversalString, new UTF_32BE());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the BMPString does not contain any surrogate characters,
|
||||
* which are outside the Basic Multilingual Plane.
|
||||
*
|
||||
* @throws IOException if illegal characters are detected
|
||||
*/
|
||||
public void validateBMPString() throws IOException {
|
||||
String bmpString = getBMPString();
|
||||
for (int i = 0; i < bmpString.length(); i++) {
|
||||
if (Character.isSurrogate(bmpString.charAt(i))) {
|
||||
throw new IOException(
|
||||
"Illegal character in BMPString, index: " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the ASN.1 NULL value
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, 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
|
||||
@@ -71,19 +71,7 @@ final class EntrustTLSPolicy {
|
||||
// OU=(c) 1999 Entrust.net Limited,
|
||||
// OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.),
|
||||
// O=Entrust.net
|
||||
"6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177",
|
||||
// cacerts alias: affirmtrustcommercialca
|
||||
// DN: CN=AffirmTrust Commercial, O=AffirmTrust, C=US
|
||||
"0376AB1D54C5F9803CE4B2E201A0EE7EEF7B57B636E8A93C9B8D4860C96F5FA7",
|
||||
// cacerts alias: affirmtrustnetworkingca
|
||||
// DN: CN=AffirmTrust Networking, O=AffirmTrust, C=US
|
||||
"0A81EC5A929777F145904AF38D5D509F66B5E2C58FCDB531058B0E17F3F0B41B",
|
||||
// cacerts alias: affirmtrustpremiumca
|
||||
// DN: CN=AffirmTrust Premium, O=AffirmTrust, C=US
|
||||
"70A73F7F376B60074248904534B11482D5BF0E698ECC498DF52577EBF2E93B9A",
|
||||
// cacerts alias: affirmtrustpremiumeccca
|
||||
// DN: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US
|
||||
"BD71FDF6DA97E4CF62D1647ADD2581B07D79ADF8397EB4ECBA9C5E8488821423"
|
||||
"6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177"
|
||||
);
|
||||
|
||||
// Any TLS Server certificate that is anchored by one of the Entrust
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@@ -28,10 +28,13 @@ package sun.security.x509;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.Normalizer;
|
||||
import java.util.*;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.charset.StandardCharsets.UTF_16BE;
|
||||
|
||||
import sun.security.util.*;
|
||||
import sun.security.pkcs.PKCS9Attribute;
|
||||
@@ -589,6 +592,10 @@ public class AVA implements DerEncoder {
|
||||
throw new IOException("AVA, extra bytes = "
|
||||
+ derval.data.available());
|
||||
}
|
||||
|
||||
if (value.tag == DerValue.tag_BMPString) {
|
||||
value.validateBMPString();
|
||||
}
|
||||
}
|
||||
|
||||
AVA(DerInputStream in) throws IOException {
|
||||
@@ -713,7 +720,8 @@ public class AVA implements DerEncoder {
|
||||
* NOTE: this implementation only emits DirectoryStrings of the
|
||||
* types returned by isDerString().
|
||||
*/
|
||||
String valStr = new String(value.getDataBytes(), UTF_8);
|
||||
String valStr =
|
||||
new String(value.getDataBytes(), getCharset(value, false));
|
||||
|
||||
/*
|
||||
* 2.4 (cont): If the UTF-8 string does not have any of the
|
||||
@@ -832,7 +840,8 @@ public class AVA implements DerEncoder {
|
||||
* NOTE: this implementation only emits DirectoryStrings of the
|
||||
* types returned by isDerString().
|
||||
*/
|
||||
String valStr = new String(value.getDataBytes(), UTF_8);
|
||||
String valStr =
|
||||
new String(value.getDataBytes(), getCharset(value, true));
|
||||
|
||||
/*
|
||||
* 2.4 (cont): If the UTF-8 string does not have any of the
|
||||
@@ -927,6 +936,39 @@ public class AVA implements DerEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the charset that should be used to decode each DN string type.
|
||||
*
|
||||
* This method ensures that multi-byte (UTF8String and BMPString) types
|
||||
* are decoded using the correct charset and the String forms represent
|
||||
* the correct characters. For 8-bit ASCII-based types (PrintableString
|
||||
* and IA5String), we return ISO_8859_1 rather than ASCII, so that the
|
||||
* complete range of characters can be represented, as many certificates
|
||||
* do not comply with the Internationalized Domain Name ACE format.
|
||||
*
|
||||
* NOTE: this method only supports DirectoryStrings of the types returned
|
||||
* by isDerString().
|
||||
*/
|
||||
private static Charset getCharset(DerValue value, boolean canonical) {
|
||||
if (canonical) {
|
||||
return switch (value.tag) {
|
||||
case DerValue.tag_PrintableString -> ISO_8859_1;
|
||||
case DerValue.tag_UTF8String -> UTF_8;
|
||||
default -> throw new Error("unexpected tag: " + value.tag);
|
||||
};
|
||||
}
|
||||
|
||||
return switch (value.tag) {
|
||||
case DerValue.tag_PrintableString,
|
||||
DerValue.tag_T61String,
|
||||
DerValue.tag_IA5String,
|
||||
DerValue.tag_GeneralString -> ISO_8859_1;
|
||||
case DerValue.tag_BMPString -> UTF_16BE;
|
||||
case DerValue.tag_UTF8String -> UTF_8;
|
||||
default -> throw new Error("unexpected tag: " + value.tag);
|
||||
};
|
||||
}
|
||||
|
||||
boolean hasRFC2253Keyword() {
|
||||
return AVAKeyword.hasKeyword(oid, RFC2253);
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
Owner: CN=AffirmTrust Commercial, O=AffirmTrust, C=US
|
||||
Issuer: CN=AffirmTrust Commercial, O=AffirmTrust, C=US
|
||||
Serial number: 7777062726a9b17c
|
||||
Valid from: Fri Jan 29 14:06:06 GMT 2010 until: Tue Dec 31 14:06:06 GMT 2030
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Subject Public Key Algorithm: 2048-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
|
||||
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
|
||||
dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
|
||||
MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
|
||||
cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
|
||||
Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
|
||||
ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
|
||||
MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
|
||||
yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
|
||||
VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
|
||||
nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
|
||||
XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
|
||||
vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
|
||||
Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
|
||||
N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
|
||||
nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,27 +0,0 @@
|
||||
Owner: CN=AffirmTrust Networking, O=AffirmTrust, C=US
|
||||
Issuer: CN=AffirmTrust Networking, O=AffirmTrust, C=US
|
||||
Serial number: 7c4f04391cd4992d
|
||||
Valid from: Fri Jan 29 14:08:24 GMT 2010 until: Tue Dec 31 14:08:24 GMT 2030
|
||||
Signature algorithm name: SHA1withRSA
|
||||
Subject Public Key Algorithm: 2048-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
|
||||
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
|
||||
dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
|
||||
MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
|
||||
cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
|
||||
YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
|
||||
kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
|
||||
QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
|
||||
6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
|
||||
yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
|
||||
QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
|
||||
KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
|
||||
tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
|
||||
QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
|
||||
Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
|
||||
olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
|
||||
x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,38 +0,0 @@
|
||||
Owner: CN=AffirmTrust Premium, O=AffirmTrust, C=US
|
||||
Issuer: CN=AffirmTrust Premium, O=AffirmTrust, C=US
|
||||
Serial number: 6d8c1446b1a60aee
|
||||
Valid from: Fri Jan 29 14:10:36 GMT 2010 until: Mon Dec 31 14:10:36 GMT 2040
|
||||
Signature algorithm name: SHA384withRSA
|
||||
Subject Public Key Algorithm: 4096-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
|
||||
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
|
||||
dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
|
||||
A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
|
||||
cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
|
||||
qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
|
||||
JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
|
||||
+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
|
||||
s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
|
||||
HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
|
||||
70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
|
||||
V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
|
||||
qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
|
||||
5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
|
||||
C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
|
||||
OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
|
||||
FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
|
||||
BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
|
||||
KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
|
||||
Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
|
||||
8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
|
||||
MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
|
||||
0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
|
||||
u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
|
||||
u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
|
||||
YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
|
||||
GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
|
||||
RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
|
||||
KeC2uAloGRwYQw==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,20 +0,0 @@
|
||||
Owner: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US
|
||||
Issuer: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US
|
||||
Serial number: 7497258ac73f7a54
|
||||
Valid from: Fri Jan 29 14:20:24 GMT 2010 until: Mon Dec 31 14:20:24 GMT 2040
|
||||
Signature algorithm name: SHA384withECDSA
|
||||
Subject Public Key Algorithm: 384-bit EC (secp384r1) key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
|
||||
VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
|
||||
cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
|
||||
BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
|
||||
VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
|
||||
0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
|
||||
ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
|
||||
A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
|
||||
A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
|
||||
aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
|
||||
flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -32,7 +32,7 @@ formatVersion=3
|
||||
# Version of the currency code information in this class.
|
||||
# It is a serial number that accompanies with each amendment.
|
||||
|
||||
dataVersion=179
|
||||
dataVersion=180
|
||||
|
||||
# List of all valid ISO 4217 currency codes.
|
||||
# To ensure compatibility, do not remove codes.
|
||||
@@ -147,7 +147,7 @@ IO=USD
|
||||
# BRUNEI DARUSSALAM
|
||||
BN=BND
|
||||
# BULGARIA
|
||||
BG=BGN
|
||||
BG=BGN;2025-12-31-22-00-00;EUR
|
||||
# BURKINA FASO
|
||||
BF=XOF
|
||||
# BURUNDI
|
||||
@@ -193,7 +193,7 @@ HR=EUR
|
||||
# CUBA
|
||||
CU=CUP
|
||||
# Curaçao
|
||||
CW=ANG;2025-04-01-04-00-00;XCG
|
||||
CW=XCG
|
||||
# CYPRUS
|
||||
CY=EUR
|
||||
# CZECHIA
|
||||
@@ -510,7 +510,7 @@ SR=SRD
|
||||
# SVALBARD AND JAN MAYEN
|
||||
SJ=NOK
|
||||
# Sint Maarten (Dutch part)
|
||||
SX=ANG;2025-04-01-04-00-00;XCG
|
||||
SX=XCG
|
||||
# ESWATINI
|
||||
SZ=SZL
|
||||
# SWEDEN
|
||||
|
||||
@@ -395,7 +395,8 @@ static jboolean is_superclass(context_type *, fullinfo_type);
|
||||
|
||||
static void initialize_exception_table(context_type *);
|
||||
static int instruction_length(unsigned char *iptr, unsigned char *end);
|
||||
static jboolean isLegalTarget(context_type *, int offset);
|
||||
static jboolean isLegalOffset(context_type *, int bci, int offset);
|
||||
static jboolean isLegalTarget(context_type *, int target);
|
||||
static void verify_constant_pool_type(context_type *, int, unsigned);
|
||||
|
||||
static void initialize_dataflow(context_type *);
|
||||
@@ -1154,9 +1155,9 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
|
||||
case JVM_OPC_goto: {
|
||||
/* Set the ->operand to be the instruction number of the target. */
|
||||
int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2];
|
||||
int target = offset + jump;
|
||||
if (!isLegalTarget(context, target))
|
||||
if (!isLegalOffset(context, offset, jump))
|
||||
CCerror(context, "Illegal target of jump or branch");
|
||||
int target = offset + jump;
|
||||
this_idata->operand.i = code_data[target];
|
||||
break;
|
||||
}
|
||||
@@ -1170,9 +1171,9 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
|
||||
int jump = (((signed char)(code[offset+1])) << 24) +
|
||||
(code[offset+2] << 16) + (code[offset+3] << 8) +
|
||||
(code[offset + 4]);
|
||||
int target = offset + jump;
|
||||
if (!isLegalTarget(context, target))
|
||||
if (!isLegalOffset(context, offset, jump))
|
||||
CCerror(context, "Illegal target of jump or branch");
|
||||
int target = offset + jump;
|
||||
this_idata->operand.i = code_data[target];
|
||||
break;
|
||||
}
|
||||
@@ -1211,13 +1212,16 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
|
||||
}
|
||||
}
|
||||
saved_operand = NEW(int, keys + 2);
|
||||
if (!isLegalTarget(context, offset + _ck_ntohl(lpc[0])))
|
||||
int jump = _ck_ntohl(lpc[0]);
|
||||
if (!isLegalOffset(context, offset, jump))
|
||||
CCerror(context, "Illegal default target in switch");
|
||||
saved_operand[keys + 1] = code_data[offset + _ck_ntohl(lpc[0])];
|
||||
int target = offset + jump;
|
||||
saved_operand[keys + 1] = code_data[target];
|
||||
for (k = keys, lptr = &lpc[3]; --k >= 0; lptr += delta) {
|
||||
int target = offset + _ck_ntohl(lptr[0]);
|
||||
if (!isLegalTarget(context, target))
|
||||
jump = _ck_ntohl(lptr[0]);
|
||||
if (!isLegalOffset(context, offset, jump))
|
||||
CCerror(context, "Illegal branch in tableswitch");
|
||||
target = offset + jump;
|
||||
saved_operand[k + 1] = code_data[target];
|
||||
}
|
||||
saved_operand[0] = keys + 1; /* number of successors */
|
||||
@@ -1746,11 +1750,24 @@ static int instruction_length(unsigned char *iptr, unsigned char *end)
|
||||
|
||||
/* Given the target of a branch, make sure that it's a legal target. */
|
||||
static jboolean
|
||||
isLegalTarget(context_type *context, int offset)
|
||||
isLegalTarget(context_type *context, int target)
|
||||
{
|
||||
int code_length = context->code_length;
|
||||
int *code_data = context->code_data;
|
||||
return (offset >= 0 && offset < code_length && code_data[offset] >= 0);
|
||||
return (target >= 0 && target < code_length && code_data[target] >= 0);
|
||||
}
|
||||
|
||||
/* Given a bci and offset, make sure the offset is valid and the target is legal */
|
||||
static jboolean
|
||||
isLegalOffset(context_type *context, int bci, int offset)
|
||||
{
|
||||
int code_length = context->code_length;
|
||||
int *code_data = context->code_data;
|
||||
int max_offset = 65535; // JVMS 4.11
|
||||
int min_offset = -65535;
|
||||
if (offset < min_offset || offset > max_offset) return JNI_FALSE;
|
||||
int target = bci + offset;
|
||||
return (target >= 0 && target < code_length && code_data[target] >= 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,9 +144,6 @@ typedef enum awt_toolkit {
|
||||
TK_WAYLAND = 2
|
||||
} awt_toolkit;
|
||||
|
||||
// TODO when wayland support will be fully implemented change to TK_UNKNOWN
|
||||
// currently wayland support is not Production-Ready ready so default awt toolkit is X11
|
||||
// wayland could be chosen manually via passing -Dawt.toolkit.name=WLToolkit argument
|
||||
static awt_toolkit _awt_toolkit = TK_X11;
|
||||
|
||||
/*
|
||||
@@ -759,33 +756,48 @@ CallJavaMainInNewThread(jlong stack_size, void* args) {
|
||||
/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
|
||||
#define MAX_PID_STR_SZ 20
|
||||
|
||||
#ifdef __linux
|
||||
static char*
|
||||
getToolkitNameByEnv() {
|
||||
if (_awt_toolkit == TK_UNKNOWN) {
|
||||
char *xdg_session_type = getenv("XDG_SESSION_TYPE");
|
||||
if (xdg_session_type != NULL && strcmp(xdg_session_type, "wayland") == 0) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
} else if (xdg_session_type != NULL && strcmp(xdg_session_type, "x11") == 0) {
|
||||
_awt_toolkit = TK_X11;
|
||||
} else if (getenv("DISPLAY") != NULL) {
|
||||
_awt_toolkit = TK_X11;
|
||||
} else if (getenv("WAYLAND_DISPLAY") != NULL) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
GetToolkitName(void) {
|
||||
if (_awt_toolkit == TK_UNKNOWN) { // Prefer WLToolkit, then XToolkit
|
||||
void* libwayland = dlopen(VERSIONED_JNI_LIB_NAME("wayland-client", "0"), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libwayland) {
|
||||
// Fallback to any development version available on the system
|
||||
libwayland = dlopen(JNI_LIB_NAME("wayland-client"), RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
if (libwayland) {
|
||||
typedef void* (*wl_display_connect_t)(const char*);
|
||||
typedef void (*wl_display_disconnect_t)(void*);
|
||||
|
||||
wl_display_connect_t fp_wl_display_connect = dlsym(libwayland, "wl_display_connect");
|
||||
wl_display_disconnect_t fp_wl_display_disconnect = dlsym(libwayland, "wl_display_disconnect");
|
||||
|
||||
if (fp_wl_display_connect && fp_wl_display_disconnect) {
|
||||
void* display = fp_wl_display_connect(NULL);
|
||||
if (display) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
fp_wl_display_disconnect(display);
|
||||
}
|
||||
}
|
||||
dlclose(libwayland);
|
||||
}
|
||||
}
|
||||
return _awt_toolkit == TK_WAYLAND ? "WLToolkit" : "XToolkit";
|
||||
}
|
||||
#endif // __linux
|
||||
|
||||
int
|
||||
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
|
||||
int argc, char **argv,
|
||||
int mode, char *what, int ret)
|
||||
{
|
||||
char *toolkit_name = getToolkitNameByEnv();
|
||||
#ifdef __linux
|
||||
char *toolkit_name = GetToolkitName();
|
||||
size_t toolkit_name_size = JLI_StrLen("-Dawt.toolkit.name=") + JLI_StrLen(toolkit_name) + 1;
|
||||
char *toolkit_option = (char *)JLI_MemAlloc(toolkit_name_size);
|
||||
snprintf(toolkit_option, toolkit_name_size, "-Dawt.toolkit.name=%s", toolkit_name);
|
||||
AddOption(toolkit_option, NULL);
|
||||
#endif // __linux
|
||||
|
||||
ShowSplashScreen();
|
||||
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
|
||||
@@ -806,7 +818,10 @@ RegisterThread()
|
||||
jboolean
|
||||
ProcessPlatformOption(const char *arg)
|
||||
{
|
||||
if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=WLToolkit") == 0) {
|
||||
if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=auto") == 0) {
|
||||
_awt_toolkit = TK_UNKNOWN;
|
||||
return JNI_TRUE;
|
||||
} else if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=WLToolkit") == 0) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
return JNI_TRUE;
|
||||
} else if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=XToolkit") == 0) {
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
import static sun.nio.fs.WindowsNativeDispatcher.*;
|
||||
import static sun.nio.fs.WindowsConstants.*;
|
||||
@@ -284,9 +285,26 @@ class WindowsWatchService
|
||||
private static final short OFFSETOF_FILENAMELENGTH = 8;
|
||||
private static final short OFFSETOF_FILENAME = 12;
|
||||
|
||||
// size of per-directory buffer for events (FIXME - make this configurable)
|
||||
// Need to be less than 4*16384 = 65536. DWORD align.
|
||||
private static final int CHANGES_BUFFER_SIZE = 16 * 1024;
|
||||
// size of per-directory buffer for events
|
||||
// Need to be less than 4*16384 = 65536 when monitoring a directory over the network. DWORD align.
|
||||
private static final int DEFAULT_CHANGES_BUFFER_SIZE = 16 * 1024;
|
||||
static final int CHANGES_BUFFER_SIZE;
|
||||
static {
|
||||
String rawValue = System.getProperty(
|
||||
"jdk.nio.file.WatchService.bufferSizeToRetrieveEventsPerDirectory",
|
||||
String.valueOf(DEFAULT_CHANGES_BUFFER_SIZE));
|
||||
int intValue;
|
||||
try {
|
||||
// Clamp to size of per-directory buffer used to retrieve events.
|
||||
intValue = Math.clamp(
|
||||
Long.decode(rawValue),
|
||||
1,
|
||||
ArraysSupport.SOFT_MAX_ARRAY_LENGTH);
|
||||
} catch (NumberFormatException e) {
|
||||
intValue = DEFAULT_CHANGES_BUFFER_SIZE;
|
||||
}
|
||||
CHANGES_BUFFER_SIZE = intValue;
|
||||
}
|
||||
|
||||
private final WindowsFileSystem fs;
|
||||
private final WindowsWatchService watcher;
|
||||
|
||||
@@ -27,6 +27,7 @@ package com.apple.eawt;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.desktop.AboutEvent;
|
||||
import java.awt.desktop.AboutHandler;
|
||||
@@ -65,8 +66,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import sun.awt.AppContext;
|
||||
import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
class _AppEventHandler {
|
||||
@@ -274,9 +275,14 @@ class _AppEventHandler {
|
||||
logger.fine("NOTIFY_SCREEN_CHANGE_PARAMETERS");
|
||||
}
|
||||
if (AppContext.getAppContext() != null) {
|
||||
EventQueue.invokeLater(
|
||||
() -> ((SunGraphicsEnvironment) GraphicsEnvironment.
|
||||
getLocalGraphicsEnvironment()).displayParametersChanged());
|
||||
CGraphicsDevice.DisplayConfiguration displayConfiguration = CGraphicsDevice.DisplayConfiguration.get();
|
||||
EventQueue.invokeLater(() -> {
|
||||
for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
|
||||
if (gd instanceof CGraphicsDevice) {
|
||||
((CGraphicsDevice) gd).updateDisplayParameters(displayConfiguration);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. 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 com.jetbrains.desktop;
|
||||
|
||||
import com.jetbrains.desktop.image.TextureWrapperSurfaceManager;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.metal.MTLTextureWrapperSurfaceData;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTexturesService extends SharedTextures {
|
||||
private final int textureType;
|
||||
|
||||
public SharedTexturesService() {
|
||||
textureType = getTextureTypeImpl();
|
||||
if (textureType == UNDEFINED_TEXTURE_TYPE) {
|
||||
throw new JBRApi.ServiceNotAvailableException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTextureType() {
|
||||
return textureType;
|
||||
}
|
||||
|
||||
private static int getTextureTypeImpl() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration();
|
||||
|
||||
if (gc instanceof MTLGraphicsConfig) {
|
||||
return METAL_TEXTURE_TYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd;
|
||||
if (gc instanceof MTLGraphicsConfig mtlGraphicsConfig) {
|
||||
sd = new MTLTextureWrapperSurfaceData(mtlGraphicsConfig, image, texture);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
@@ -34,18 +34,21 @@ import java.awt.Window;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.MacOSFlags;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.opengl.CGLGraphicsConfig;
|
||||
import sun.lwawt.macosx.CThreading;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import static java.awt.peer.ComponentPeer.SET_BOUNDS;
|
||||
|
||||
public final class CGraphicsDevice extends GraphicsDevice
|
||||
implements DisplayChangedListener, DisplayParametersChangedListener {
|
||||
implements DisplayChangedListener {
|
||||
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger(CGraphicsDevice.class.getName());
|
||||
/**
|
||||
@@ -67,7 +70,7 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
private DisplayMode originalMode;
|
||||
private DisplayMode initialMode;
|
||||
|
||||
public CGraphicsDevice(final int displayID) {
|
||||
public CGraphicsDevice(final int displayID, DisplayConfiguration config) {
|
||||
this.displayID = displayID;
|
||||
this.initialMode = getDisplayMode();
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
@@ -91,7 +94,7 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
}
|
||||
|
||||
// [JBR] we don't call displayChanged after creating a device, so call it here.
|
||||
displayChanged();
|
||||
updateDevice(config);
|
||||
}
|
||||
|
||||
int getDisplayID() {
|
||||
@@ -174,8 +177,6 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
yResolution = nativeGetYResolution(displayID);
|
||||
isMirroring = nativeIsMirroring(displayID);
|
||||
bounds = nativeGetBounds(displayID).getBounds(); //does integer rounding
|
||||
screenInsets = nativeGetScreenInsets(displayID);
|
||||
initScaleFactor();
|
||||
resizeFSWindow(getFullScreenWindow(), bounds);
|
||||
//TODO configs?
|
||||
}
|
||||
@@ -183,29 +184,43 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
/**
|
||||
* @return false if display parameters were changed, so we need to recreate the device.
|
||||
*/
|
||||
boolean updateDevice() {
|
||||
boolean updateDevice(DisplayConfiguration config) {
|
||||
int s = scale;
|
||||
double xr = xResolution, yr = yResolution;
|
||||
boolean m = isMirroring;
|
||||
var b = bounds;
|
||||
updateDisplayParameters(config);
|
||||
displayChanged();
|
||||
return s == scale && xr == xResolution && yr == yResolution && m == isMirroring && b.equals(bounds);
|
||||
}
|
||||
|
||||
public void displayParametersChanged() {
|
||||
Insets newScreenInsets = nativeGetScreenInsets(displayID);
|
||||
if (!newScreenInsets.equals(screenInsets)) {
|
||||
public void updateDisplayParameters(DisplayConfiguration config) {
|
||||
Descriptor desc = config.getDescriptor(displayID);
|
||||
if (desc == null) return;
|
||||
if (!desc.screenInsets.equals(screenInsets)) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("Screen insets for display(" + displayID + ") changed " +
|
||||
"[top=" + screenInsets.top + ",left=" + screenInsets.left +
|
||||
",bottom=" + screenInsets.bottom + ",right=" + screenInsets.right +
|
||||
"]->[top=" + newScreenInsets.top + ",left=" + newScreenInsets.left +
|
||||
",bottom=" + newScreenInsets.bottom + ",right=" + newScreenInsets.right +
|
||||
"]->[top=" + desc.screenInsets.top + ",left=" + desc.screenInsets.left +
|
||||
",bottom=" + desc.screenInsets.bottom + ",right=" + desc.screenInsets.right +
|
||||
"]");
|
||||
}
|
||||
screenInsets = newScreenInsets;
|
||||
screenInsets = desc.screenInsets;
|
||||
}
|
||||
int newScale = 1;
|
||||
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
|
||||
double debugScale = SunGraphicsEnvironment.getDebugScale();
|
||||
newScale = (int) (debugScale >= 1 ? Math.round(debugScale) : (int) desc.scale);
|
||||
}
|
||||
if (newScale != scale) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("Scale for display(" + displayID + ") changed " + scale + "->" + newScale);
|
||||
}
|
||||
scale = newScale;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paletteChanged() {
|
||||
// devices do not need to react to this event.
|
||||
@@ -352,23 +367,6 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
}
|
||||
}
|
||||
|
||||
private void initScaleFactor() {
|
||||
int _scale = scale;
|
||||
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
|
||||
double debugScale = SunGraphicsEnvironment.getDebugScale();
|
||||
scale = (int) (debugScale >= 1
|
||||
? Math.round(debugScale)
|
||||
: nativeGetScaleFactor(displayID));
|
||||
} else {
|
||||
scale = 1;
|
||||
}
|
||||
if (_scale != scale && logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("current scale = " + _scale + ", new scale = " + scale + " (" + this + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static native double nativeGetScaleFactor(int displayID);
|
||||
|
||||
private static native void nativeResetDisplayMode();
|
||||
|
||||
private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
|
||||
@@ -383,7 +381,37 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
|
||||
private static native boolean nativeIsMirroring(int displayID);
|
||||
|
||||
private static native Insets nativeGetScreenInsets(int displayID);
|
||||
|
||||
private static native Rectangle2D nativeGetBounds(int displayID);
|
||||
|
||||
private static native void nativeGetDisplayConfiguration(DisplayConfiguration config);
|
||||
|
||||
public static final class DisplayConfiguration {
|
||||
private final Map<Integer, Descriptor> map = new HashMap<>();
|
||||
private void addDescriptor(int displayID, int top, int left, int bottom, int right, double scale) {
|
||||
map.put(displayID, new Descriptor(new Insets(top, left, bottom, right), scale));
|
||||
}
|
||||
public Descriptor getDescriptor(int displayID) {
|
||||
return map.get(displayID);
|
||||
}
|
||||
public static DisplayConfiguration get() {
|
||||
try {
|
||||
return CThreading.executeOnAppKit(() -> {
|
||||
DisplayConfiguration config = new DisplayConfiguration();
|
||||
nativeGetDisplayConfiguration(config);
|
||||
return config;
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Descriptor {
|
||||
private final Insets screenInsets;
|
||||
private final double scale;
|
||||
private Descriptor(Insets screenInsets, double scale) {
|
||||
this.screenInsets = screenInsets;
|
||||
this.scale = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +245,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);
|
||||
devices.clear();
|
||||
mainDisplayID = getMainDisplayID();
|
||||
CGraphicsDevice.DisplayConfiguration config = CGraphicsDevice.DisplayConfiguration.get();
|
||||
|
||||
// initialization of the graphics device may change list of displays on
|
||||
// hybrid systems via an activation of discrete video.
|
||||
@@ -252,7 +253,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
// of displays, and then recheck the main display again.
|
||||
if (!old.containsKey(mainDisplayID)) {
|
||||
try {
|
||||
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID));
|
||||
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID, config));
|
||||
} catch (IllegalStateException e) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("Unable to initialize graphics device for displayID=" +
|
||||
@@ -268,13 +269,13 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
}
|
||||
for (int id : displayIDs) {
|
||||
old.compute(id, (i, d) -> {
|
||||
if (d != null && d.updateDevice()) {
|
||||
if (d != null && d.updateDevice(config)) {
|
||||
// Device didn't change -> reuse
|
||||
devices.put(i, d);
|
||||
return null;
|
||||
} else {
|
||||
// Device changed -> create new
|
||||
devices.put(i, new CGraphicsDevice(i));
|
||||
devices.put(i, new CGraphicsDevice(i, config));
|
||||
return d;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 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
|
||||
@@ -31,7 +31,6 @@ import sun.awt.CGraphicsEnvironment;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.TextureWrapperSurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
@@ -49,7 +48,6 @@ import java.awt.BufferCapabilities;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.awt.Rectangle;
|
||||
@@ -71,7 +69,7 @@ import static sun.java2d.pipe.hw.ContextCapabilities.*;
|
||||
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
|
||||
|
||||
public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
implements AccelGraphicsConfig, SurfaceManager.Factory, SurfaceManager.TextureWrapperFactory
|
||||
implements AccelGraphicsConfig, SurfaceManager.Factory
|
||||
{
|
||||
private static ImageCapabilities imageCaps = new MTLImageCaps();
|
||||
|
||||
@@ -380,11 +378,4 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
Object context) {
|
||||
return new MTLVolatileSurfaceManager(image, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createTextureWrapperSurfaceManager(
|
||||
GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd = MTLSurfaceData.createData(this, image, texture);
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import java.awt.Transparency;
|
||||
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_SURFACE;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
|
||||
@@ -152,7 +151,7 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
private native void initOps(MTLGraphicsConfig gc, long pConfigInfo, long pPeerData, long layerPtr,
|
||||
int xoff, int yoff, boolean isOpaque);
|
||||
|
||||
private MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
|
||||
protected MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
|
||||
ColorModel cm, int type, int width, int height)
|
||||
{
|
||||
super(getCustomSurfaceType(type), cm);
|
||||
@@ -201,10 +200,6 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
type);
|
||||
}
|
||||
|
||||
public static MTLTextureWrapperSurfaceData createData(MTLGraphicsConfig gc, Image image, long pTexture) {
|
||||
return new MTLTextureWrapperSurfaceData(gc, image, pTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultScaleX() {
|
||||
return scale;
|
||||
@@ -224,8 +219,6 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
|
||||
protected native boolean initTexture(long pData, boolean isOpaque, int width, int height);
|
||||
|
||||
protected native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);
|
||||
|
||||
protected native boolean initRTexture(long pData, boolean isOpaque, int width, int height);
|
||||
|
||||
protected native boolean initFlipBackbuffer(long pData, boolean isOpaque, int width, int height);
|
||||
@@ -681,46 +674,4 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
}
|
||||
|
||||
private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);
|
||||
|
||||
/**
|
||||
* Surface data for an existing texture
|
||||
*/
|
||||
public static final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
|
||||
private final Image myImage;
|
||||
|
||||
private MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
|
||||
super(null, gc, ColorModel.getRGBdefault(), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
|
||||
myImage = image;
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
|
||||
rq.lock();
|
||||
try {
|
||||
MTLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(initWithTexture(getNativeOps(), false, pTexture)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return myImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package sun.java2d.metal;
|
||||
|
||||
public class MTLSurfaceDataExt {
|
||||
public static boolean initWithTexture(MTLSurfaceData sd, long texturePtr) {
|
||||
return initWithTexture(sd.getNativeOps(), false, texturePtr);
|
||||
}
|
||||
|
||||
private static native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Surface data for an existing texture
|
||||
*/
|
||||
public final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
|
||||
private final Image myImage;
|
||||
|
||||
public MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
|
||||
super(null, gc, gc.getColorModel(TRANSLUCENT), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
|
||||
myImage = image;
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
|
||||
rq.lock();
|
||||
try {
|
||||
MTLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(MTLSurfaceDataExt.initWithTexture(this, pTexture)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return myImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,6 @@ import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowStateListener;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -1066,33 +1065,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
return isFullScreenMode;
|
||||
}
|
||||
|
||||
private void waitForWindowState(int state) {
|
||||
if (peer.getState() == state) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object lock = new Object();
|
||||
WindowStateListener wsl = new WindowStateListener() {
|
||||
public void windowStateChanged(WindowEvent e) {
|
||||
synchronized (lock) {
|
||||
if (e.getNewState() == state) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
target.addWindowStateListener(wsl);
|
||||
if (peer.getState() != state) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
target.removeWindowStateListener(wsl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowState(int windowState) {
|
||||
if (peer == null || !peer.isVisible()) {
|
||||
@@ -1114,7 +1086,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
// let's return into the normal states first
|
||||
// the zoom call toggles between the normal and the max states
|
||||
unmaximize();
|
||||
waitForWindowState(Frame.NORMAL);
|
||||
}
|
||||
execute(CWrapper.NSWindow::miniaturize);
|
||||
break;
|
||||
@@ -1122,7 +1093,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
if (prevWindowState == Frame.ICONIFIED) {
|
||||
// let's return into the normal states first
|
||||
execute(CWrapper.NSWindow::deminiaturize);
|
||||
waitForWindowState(Frame.NORMAL);
|
||||
}
|
||||
maximize();
|
||||
break;
|
||||
|
||||
@@ -363,47 +363,6 @@ Java_sun_awt_CGraphicsDevice_nativeGetBounds
|
||||
return CGToJavaRect(env, rect);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeGetScreenInsets
|
||||
* Signature: (I)D
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets
|
||||
(JNIEnv *env, jclass class, jint displayID)
|
||||
{
|
||||
jobject ret = NULL;
|
||||
__block NSRect frame = NSZeroRect;
|
||||
__block NSRect visibleFrame = NSZeroRect;
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
NSArray *screens = [NSScreen screens];
|
||||
for (NSScreen *screen in screens) {
|
||||
NSDictionary *screenInfo = [screen deviceDescription];
|
||||
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
|
||||
if ([screenID unsignedIntValue] == displayID){
|
||||
frame = [screen frame];
|
||||
visibleFrame = [screen visibleFrame];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}];
|
||||
// Convert between Cocoa's coordinate system and Java.
|
||||
jint bottom = visibleFrame.origin.y - frame.origin.y;
|
||||
jint top = frame.size.height - visibleFrame.size.height - bottom;
|
||||
jint left = visibleFrame.origin.x - frame.origin.x;
|
||||
jint right = frame.size.width - visibleFrame.size.width - left;
|
||||
|
||||
DECLARE_CLASS_RETURN(jc_Insets, "java/awt/Insets", ret);
|
||||
DECLARE_METHOD_RETURN(jc_Insets_ctor, jc_Insets, "<init>", "(IIII)V", ret);
|
||||
ret = (*env)->NewObject(env, jc_Insets, jc_Insets_ctor, top, left, bottom, right);
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeResetDisplayMode
|
||||
@@ -557,31 +516,40 @@ Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeGetScaleFactor
|
||||
* Signature: (I)D
|
||||
* Method: nativeGetDisplayConfiguration
|
||||
* Signature: (Lsun/awt/CGraphicsDevice$DisplayConfiguration;)V
|
||||
*/
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
|
||||
(JNIEnv *env, jclass class, jint displayID)
|
||||
{
|
||||
__block jdouble ret = 1.0f;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeGetDisplayConfiguration
|
||||
(JNIEnv *env, jclass class, jobject config) {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
NSArray *screens = [NSScreen screens];
|
||||
for (NSScreen *screen in screens) {
|
||||
NSDictionary *screenInfo = [screen deviceDescription];
|
||||
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
|
||||
if ([screenID unsignedIntValue] == displayID){
|
||||
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
|
||||
ret = [screen backingScaleFactor];
|
||||
}
|
||||
break;
|
||||
}
|
||||
DECLARE_CLASS(jc_DisplayConfiguration, "sun/awt/CGraphicsDevice$DisplayConfiguration");
|
||||
DECLARE_METHOD(jc_DisplayConfiguration_addDescriptor, jc_DisplayConfiguration, "addDescriptor", "(IIIIID)V");
|
||||
|
||||
NSArray *screens = [NSScreen screens];
|
||||
for (NSScreen *screen in screens) {
|
||||
NSDictionary *screenInfo = [screen deviceDescription];
|
||||
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
|
||||
|
||||
jint displayID = [screenID unsignedIntValue];
|
||||
jdouble scale = 1.0;
|
||||
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
|
||||
scale = [screen backingScaleFactor];
|
||||
}
|
||||
}];
|
||||
NSRect frame = [screen frame];
|
||||
NSRect visibleFrame = [screen visibleFrame];
|
||||
// Convert between Cocoa's coordinate system and Java.
|
||||
jint bottom = visibleFrame.origin.y - frame.origin.y;
|
||||
jint top = frame.size.height - visibleFrame.size.height - bottom;
|
||||
jint left = visibleFrame.origin.x - frame.origin.x;
|
||||
jint right = frame.size.width - visibleFrame.size.width - left;
|
||||
|
||||
(*env)->CallVoidMethod(env, config, jc_DisplayConfiguration_addDescriptor,
|
||||
displayID, top, left, bottom, right, scale);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ static void displaycb_handle
|
||||
(CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo)
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
if (TRACE_DISPLAY_CALLBACKS) {
|
||||
@@ -152,7 +153,6 @@ JNI_COCOA_ENTER(env);
|
||||
block:^()
|
||||
{
|
||||
@try {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
@@ -173,7 +173,6 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
// braces to reduce variable scope
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
|
||||
@@ -311,11 +311,11 @@ static const struct SymbolicHotKey defaultSymbolicHotKeys[] = {
|
||||
[Shortcut_FullScreenTileRight] = { "FullScreenTileRight", "Windows: Full-Screen Tile Right", YES, 65535, 65535, 0, 15, 4 },
|
||||
};
|
||||
|
||||
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
|
||||
#define NUM_SYMBOLIC_HOTKEYS (sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]))
|
||||
|
||||
static struct SystemHotkeyState {
|
||||
bool symbolicHotkeysFilled;
|
||||
struct SymbolicHotKey currentSymbolicHotkeys[numSymbolicHotkeys];
|
||||
struct SymbolicHotKey currentSymbolicHotkeys[NUM_SYMBOLIC_HOTKEYS];
|
||||
|
||||
bool initialized;
|
||||
bool enabled;
|
||||
@@ -398,7 +398,7 @@ static void visitServicesShortcut(Visitor visitorBlock, NSString * key_equivalen
|
||||
visitorBlock(-1, keyChar.UTF8String, modifiers, desc.UTF8String, -1, NULL);
|
||||
}
|
||||
|
||||
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
|
||||
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS]) {
|
||||
// Called from the main thread
|
||||
|
||||
@try {
|
||||
@@ -425,7 +425,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(hotkeys, defaultSymbolicHotKeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
|
||||
memcpy(hotkeys, defaultSymbolicHotKeys, NUM_SYMBOLIC_HOTKEYS * sizeof(struct SymbolicHotKey));
|
||||
|
||||
for (id keyObj in hkObj) {
|
||||
if (![keyObj isKindOfClass:[NSString class]]) {
|
||||
@@ -438,7 +438,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
|
||||
int uid = [hkNumber intValue];
|
||||
|
||||
// Ignore hotkeys out of range, as well as 0, which is the "invalid value" for intValue
|
||||
if (uid <= 0 || uid >= numSymbolicHotkeys) {
|
||||
if (uid <= 0 || uid >= NUM_SYMBOLIC_HOTKEYS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -512,7 +512,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
|
||||
}
|
||||
|
||||
static void updateAppleSymbolicHotkeysCache() {
|
||||
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
|
||||
struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS];
|
||||
readAppleSymbolicHotkeys(hotkeys);
|
||||
|
||||
pthread_mutex_lock(&state.mutex);
|
||||
@@ -521,10 +521,10 @@ static void updateAppleSymbolicHotkeysCache() {
|
||||
pthread_mutex_unlock(&state.mutex);
|
||||
}
|
||||
|
||||
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys], Visitor visitorBlock) {
|
||||
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS], Visitor visitorBlock) {
|
||||
const NSOperatingSystemVersion macOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
|
||||
for (int uid = 0; uid < numSymbolicHotkeys; ++uid) {
|
||||
for (int uid = 0; uid < NUM_SYMBOLIC_HOTKEYS; ++uid) {
|
||||
struct SymbolicHotKey* hotkey = &hotkeys[uid];
|
||||
|
||||
if (!hotkey->enabled) {
|
||||
@@ -646,12 +646,12 @@ static bool ensureInitializedAndEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
|
||||
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
|
||||
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS]) {
|
||||
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * NUM_SYMBOLIC_HOTKEYS);
|
||||
|
||||
pthread_mutex_lock(&state.mutex);
|
||||
if (state.symbolicHotkeysFilled) {
|
||||
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
|
||||
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * NUM_SYMBOLIC_HOTKEYS);
|
||||
}
|
||||
pthread_mutex_unlock(&state.mutex);
|
||||
}
|
||||
@@ -661,7 +661,7 @@ static void readSystemHotkeysImpl(Visitor visitorBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
|
||||
struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS];
|
||||
readAppleSymbolicHotkeysCached(hotkeys);
|
||||
|
||||
iterateAppleSymbolicHotkeys(hotkeys, visitorBlock);
|
||||
|
||||
@@ -67,9 +67,17 @@ static jclass sjc_CAccessibility = NULL;
|
||||
jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
|
||||
sjm_getCurrentAccessiblePopupMenu,
|
||||
fAccessible, fComponent);
|
||||
CHECK_EXCEPTION();
|
||||
if (axComponent == NULL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent
|
||||
withEnv:env withView:self->fView isCurrent:YES];
|
||||
(*env)->DeleteLocalRef(env, axComponent);
|
||||
if (currentElement == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement
|
||||
withEnv:env
|
||||
|
||||
@@ -112,6 +112,13 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
NSLock* _lock;
|
||||
}
|
||||
|
||||
+ (NSUInteger) getDrawableId:(id<MTLDrawable>)mtlDrawable {
|
||||
if (@available(macOS 10.15.4, *)) {
|
||||
return [mtlDrawable drawableID];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (id) initWithJavaLayer:(jobject)layer usePerfCounters:(jboolean)perfCountersEnabled
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
@@ -246,12 +253,12 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
#if TRACE_DISPLAY_ON
|
||||
self.avgNextDrawableTime = nextDrawableLatency * a + self.avgNextDrawableTime * (1.0 - a);
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: drawable(%d) presented"
|
||||
" - nextDrawableLatency = %.3lf ms - average = %.3lf ms",
|
||||
CACurrentMediaTime(), mtlDrawable.drawableID,
|
||||
1000.0 * nextDrawableLatency, 1000.0 * self.avgNextDrawableTime
|
||||
);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: drawable(%d) presented"
|
||||
" - nextDrawableLatency = %.3lf ms - average = %.3lf ms",
|
||||
CACurrentMediaTime(), [MTLLayer getDrawableId:mtlDrawable],
|
||||
1000.0 * nextDrawableLatency, 1000.0 * self.avgNextDrawableTime
|
||||
);
|
||||
#endif
|
||||
}
|
||||
// Keep Fence from now:
|
||||
@@ -284,7 +291,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture_PresentedHandler: drawable(%d) presented"
|
||||
" - presentedHandlerLatency = %.3lf ms frameInterval = %.3lf ms",
|
||||
CACurrentMediaTime(), drawable.drawableID,
|
||||
CACurrentMediaTime(), [MTLLayer getDrawableId:drawable],
|
||||
1000.0 * presentedHandlerLatency, 1000.0 * frameInterval
|
||||
);
|
||||
self.lastPresentedTime = presentedTime;
|
||||
@@ -299,7 +306,8 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture_PresentedHandler: drawable(%d) skipped"
|
||||
" - presentedHandlerLatency = %.3lf ms",
|
||||
CACurrentMediaTime(), drawable.drawableID, 1000.0 * presentedHandlerLatency
|
||||
CACurrentMediaTime(), [MTLLayer getDrawableId:drawable],
|
||||
1000.0 * presentedHandlerLatency
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -309,7 +317,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
// Present drawable:
|
||||
NSUInteger drawableId = -1;
|
||||
if (TRACE_DISPLAY) {
|
||||
drawableId = mtlDrawable.drawableID;
|
||||
drawableId = [MTLLayer getDrawableId:mtlDrawable];
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO,
|
||||
"[%.6lf] MTLLayer.blitTexture: layer[%p] present drawable(%d)",
|
||||
CACurrentMediaTime(), self, drawableId);
|
||||
|
||||
@@ -107,81 +107,6 @@ static jboolean MTLSurfaceData_initTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean MTLSurfaceData_initWithTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque, void* pTexture) {
|
||||
@autoreleasepool {
|
||||
if (bmtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (pTexture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
|
||||
if (texture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
|
||||
texture.width == 0 || texture.height == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
|
||||
texture.width, texture.height);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
|
||||
texture.pixelFormat);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
bmtlsdo->pTexture = texture;
|
||||
bmtlsdo->pOutTexture = NULL;
|
||||
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||
if (mtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLContext* ctx = mtlsdo->configInfo->context;
|
||||
MTLTextureDescriptor *stencilDataDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
|
||||
|
||||
MTLTextureDescriptor *stencilTextureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
|
||||
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
bmtlsdo->width = texture.width;
|
||||
bmtlsdo->height = texture.height;
|
||||
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
|
||||
|
||||
[texture retain];
|
||||
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
|
||||
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an MTL texture, using the given width and height as
|
||||
* a guide.
|
||||
@@ -198,19 +123,6 @@ Java_sun_java2d_metal_MTLSurfaceData_initTexture(
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_initWithTexture(
|
||||
JNIEnv *env, jobject mtlds,
|
||||
jlong pData, jboolean isOpaque,
|
||||
jlong pTexture) {
|
||||
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
|
||||
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a framebuffer object, using the given width and height as
|
||||
* a guide. See MTLSD_InitTextureObject() and MTLSD_initRTexture()
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#import "MTLSurfaceData.h"
|
||||
|
||||
#import "jni_util.h"
|
||||
|
||||
// From MTLSurfaceData.m
|
||||
extern void MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *bmtlsdo, jint w, jint h);
|
||||
|
||||
static jboolean MTLSurfaceData_initWithTexture(
|
||||
BMTLSDOps *bmtlsdo,
|
||||
jboolean isOpaque,
|
||||
void* pTexture
|
||||
) {
|
||||
@autoreleasepool {
|
||||
if (bmtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (pTexture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
|
||||
if (texture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
|
||||
texture.width == 0 || texture.height == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
|
||||
texture.width, texture.height);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
|
||||
texture.pixelFormat);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
bmtlsdo->pTexture = texture;
|
||||
bmtlsdo->pOutTexture = NULL;
|
||||
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||
if (mtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLContext* ctx = mtlsdo->configInfo->context;
|
||||
MTLTextureDescriptor *stencilDataDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
|
||||
|
||||
MTLTextureDescriptor *stencilTextureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
|
||||
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
bmtlsdo->width = texture.width;
|
||||
bmtlsdo->height = texture.height;
|
||||
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
|
||||
|
||||
[texture retain];
|
||||
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
|
||||
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceDataExt_initWithTexture(
|
||||
JNIEnv *env,
|
||||
jclass cls,
|
||||
jlong pData,
|
||||
jboolean isOpaque,
|
||||
jlong pTexture
|
||||
) {
|
||||
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
|
||||
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
@@ -254,8 +254,11 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
|
||||
*/
|
||||
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
|
||||
blockCopy();
|
||||
Block_release(blockCopy);
|
||||
@try {
|
||||
blockCopy();
|
||||
} @finally {
|
||||
Block_release(blockCopy);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString*)getCaller:(NSString*)prefixSymbol {
|
||||
@@ -780,9 +783,18 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
const NSUInteger count = [self.queue count];
|
||||
if (count != 0) {
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
|
||||
// invoke callback:
|
||||
[ThreadUtilities invokeBlockCopy:blockCopy];
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
|
||||
// invoke callback:
|
||||
[ThreadUtilities invokeBlockCopy:blockCopy];
|
||||
} @catch (NSException *exception) {
|
||||
// handle any exception to avoid crashing the main run loop:
|
||||
NSLog(@"Apple AWT Cocoa Exception: %@", [exception description]);
|
||||
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [exception callStackSymbols]);
|
||||
} @finally {
|
||||
[pool drain];
|
||||
}
|
||||
}
|
||||
// reset queue anyway:
|
||||
[self reset];
|
||||
|
||||
@@ -26,52 +26,19 @@
|
||||
package com.jetbrains.desktop;
|
||||
|
||||
import com.jetbrains.desktop.image.TextureWrapperImage;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.*;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTextures {
|
||||
public abstract class SharedTextures {
|
||||
public final static int UNDEFINED_TEXTURE_TYPE = 0;
|
||||
public final static int METAL_TEXTURE_TYPE = 1;
|
||||
|
||||
private final int textureType;
|
||||
public abstract int getTextureType();
|
||||
|
||||
public static SharedTextures create() {
|
||||
return new SharedTextures();
|
||||
public final Image wrapTexture(GraphicsConfiguration gc, long texture) {
|
||||
return new TextureWrapperImage((img) -> createSurfaceManager(gc, img, texture));
|
||||
}
|
||||
|
||||
private SharedTextures() {
|
||||
textureType = getTextureTypeImpl();
|
||||
if (textureType == 0) {
|
||||
throw new JBRApi.ServiceNotAvailableException();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTextureType() {
|
||||
return textureType;
|
||||
}
|
||||
|
||||
public Image wrapTexture(GraphicsConfiguration gc, long texture) {
|
||||
return new TextureWrapperImage(gc, texture);
|
||||
}
|
||||
|
||||
private static int getTextureTypeImpl() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration();
|
||||
try {
|
||||
if (SunToolkit.isInstanceOf(gc, "sun.java2d.metal.MTLGraphicsConfig")) {
|
||||
return METAL_TEXTURE_TYPE;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InternalError("Unexpected exception during reflection", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
protected abstract SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.awt.ImageCapabilities;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for a GPU texture-based image.
|
||||
@@ -51,31 +52,14 @@ import java.awt.image.ImageProducer;
|
||||
* the surface flushing.
|
||||
*/
|
||||
public class TextureWrapperImage extends Image {
|
||||
final GraphicsConfiguration gc;
|
||||
final SurfaceData sd;
|
||||
final static ImageCapabilities capabilities = new ImageCapabilities(true);
|
||||
|
||||
/**
|
||||
* Constructs a TextureWrapperImage instance with the specified graphics configuration
|
||||
* and a texture.
|
||||
*
|
||||
* @param gc the graphics configuration
|
||||
* @param texture the texture that will be wrapped by this instance.
|
||||
* Platform-specific details:
|
||||
* macOS (with the Metal rendering pipeline) - a pointer to an MTLTexture object is expected
|
||||
*
|
||||
* @throws UnsupportedOperationException if the current pipeline is not supported
|
||||
* @throws IllegalArgumentException if the texture cannot be wrapped
|
||||
*/
|
||||
public TextureWrapperImage(GraphicsConfiguration gc, long texture)
|
||||
public TextureWrapperImage(Function<Image, SurfaceManager> surfaceManagerFactory)
|
||||
throws UnsupportedOperationException, IllegalArgumentException {
|
||||
this.gc = gc;
|
||||
SurfaceManager surfaceManager;
|
||||
if (gc instanceof SurfaceManager.TextureWrapperFactory factory) {
|
||||
surfaceManager = factory.createTextureWrapperSurfaceManager(gc, this, texture);
|
||||
} else throw new UnsupportedOperationException();
|
||||
sd = surfaceManager.getPrimarySurfaceData();
|
||||
SurfaceManager.setManager(this, surfaceManager);
|
||||
SurfaceManager sm = surfaceManagerFactory.apply(this);
|
||||
sd = sm.getPrimarySurfaceData();
|
||||
SurfaceManager.setManager(this, sm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt.image;
|
||||
package com.jetbrains.desktop.image;
|
||||
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
@@ -4377,11 +4377,6 @@ public class Window extends Container implements Accessible {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWindowListener(Window w, WindowListener listener) {
|
||||
w.addWindowListener(listener);
|
||||
}
|
||||
|
||||
private static void dumpCounter(final String counterName, final double valPerSecond) {
|
||||
if (USE_COUNTERS) {
|
||||
doLog(String.format("%s per second: %.2f", counterName, valPerSecond),
|
||||
|
||||
@@ -37,7 +37,6 @@ import java.awt.event.InputEvent;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.awt.image.BufferStrategy;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
|
||||
@@ -338,8 +337,6 @@ public final class AWTAccessor {
|
||||
double getCounterPerSecond(Window w, String counterName);
|
||||
|
||||
void dumpStats(Window w, boolean reset, StringBuilder sb);
|
||||
|
||||
void addWindowListener(Window w, WindowListener listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. 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 sun.awt;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
public interface DisplayParametersChangedListener extends EventListener {
|
||||
/**
|
||||
* Invoked when the display parameters changed.
|
||||
*/
|
||||
public void displayParametersChanged();
|
||||
}
|
||||
@@ -184,14 +184,6 @@ public abstract class SurfaceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See TextureWrapperImage.
|
||||
*/
|
||||
public interface TextureWrapperFactory {
|
||||
SurfaceManager createTextureWrapperSurfaceManager(
|
||||
GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for GraphicsConfiguration objects to implement if
|
||||
* they create their own VolatileSurfaceManager implementations.
|
||||
|
||||
@@ -44,7 +44,6 @@ import java.util.Locale;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import sun.awt.DisplayChangedListener;
|
||||
import sun.awt.DisplayParametersChangedListener;
|
||||
import sun.awt.SunDisplayChanger;
|
||||
import sun.font.FontManager;
|
||||
import sun.font.FontManagerFactory;
|
||||
@@ -60,7 +59,7 @@ import sun.java2d.pipe.Region;
|
||||
* @see GraphicsConfiguration
|
||||
*/
|
||||
public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
|
||||
implements DisplayChangedListener, DisplayParametersChangedListener {
|
||||
implements DisplayChangedListener {
|
||||
|
||||
/** Establish the default font to be used by SG2D. */
|
||||
private final Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
|
||||
@@ -276,15 +275,6 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
|
||||
displayChanger.notifyListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayParametersChanged() {
|
||||
for (GraphicsDevice gd : getScreenDevices()) {
|
||||
if (gd instanceof DisplayParametersChangedListener) {
|
||||
((DisplayParametersChangedListener) gd).displayParametersChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the DisplayChangedListener interface:
|
||||
* propagate this event to listeners
|
||||
|
||||
@@ -1944,10 +1944,15 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
awtLock();
|
||||
try {
|
||||
if (numberOfButtons == 0) {
|
||||
if (XdgDesktopPortal.isRemoteDesktop()
|
||||
&& ScreencastHelper.isAvailable()) {
|
||||
numberOfButtons = 3;
|
||||
} else {
|
||||
// The commented-out code is introduced in 8351907 and causes inability to use
|
||||
// any mouse extra buttons under XWayland GNOME of version >= 47,
|
||||
// thus causing JBR-9713, JBR-9714, JBR-9715.
|
||||
// Please don't enable it back until a proper fix appears in OpenJDK.
|
||||
//
|
||||
//if (XdgDesktopPortal.isRemoteDesktop()
|
||||
// && ScreencastHelper.isAvailable()) {
|
||||
// numberOfButtons = 3;
|
||||
//} else {
|
||||
numberOfButtons = getNumberOfButtonsImpl();
|
||||
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
|
||||
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
|
||||
@@ -1959,7 +1964,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
} else if (numberOfButtons == 4 || numberOfButtons == 5) {
|
||||
numberOfButtons = 3;
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
//Assume don't have to re-query the number again and again.
|
||||
return numberOfButtons;
|
||||
|
||||
@@ -26,7 +26,6 @@ package sun.awt.wl;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
@@ -130,5 +129,7 @@ public abstract class FrameDecoration {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void notifyNativeWindowCreated(long nativePtr);
|
||||
public abstract void notifyNativeWindowToBeHidden(long nativePtr);
|
||||
public abstract void dispose();
|
||||
}
|
||||
|
||||
@@ -294,6 +294,14 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowCreated(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
WLToolkit.getDefaultToolkit().removePropertyChangeListener("awt.os.theme.isDark", pcl);
|
||||
|
||||
@@ -74,6 +74,14 @@ public class MinimalFrameDecoration extends FrameDecoration {
|
||||
// Nothing to repaint
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowCreated(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Nothing to dispose
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2022-2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. 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 sun.awt.wl;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Decorations based on the xdg-decoration-unstable-v1 protocol.
|
||||
* Supported iff WLToolkit.isSSDAvailable().
|
||||
*
|
||||
* The decoration itself is added by the server on a surface separate from the window itself,
|
||||
* so the window acts as if it is undecorated. For example, there are no insets, no special
|
||||
* repainting is done, etc.
|
||||
*/
|
||||
public class ServerSideFrameDecoration extends FrameDecoration {
|
||||
private long nativeDecorPtr;
|
||||
|
||||
public ServerSideFrameDecoration(WLDecoratedPeer peer) {
|
||||
super(peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getContentInsets() {
|
||||
return new Insets(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getTitleBarBounds() {
|
||||
return new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
// Nothing to paint here, the Wayland server provides all the painting
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyConfigured(boolean active, boolean maximized, boolean fullscreen) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepaintNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRepaintNeeded(boolean value) {
|
||||
// Nothing to repaint
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowCreated(long nativePtr) {
|
||||
if (!peer.targetIsWlPopup()) {
|
||||
nativeDecorPtr = createToplevelDecorationImpl(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
if (nativeDecorPtr != 0) {
|
||||
disposeImpl(nativeDecorPtr);
|
||||
nativeDecorPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Native resources must have been already disposed when the window was hidden
|
||||
assert nativeDecorPtr == 0;
|
||||
}
|
||||
|
||||
private native long createToplevelDecorationImpl(long nativeFramePtr);
|
||||
private native void disposeImpl(long nativeDecorPtr);
|
||||
}
|
||||
@@ -113,6 +113,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
private boolean repositionPopup = false; // protected by stateLock
|
||||
private boolean resizePending = false; // protected by stateLock
|
||||
|
||||
private static final boolean shadowEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.wl.Shadow", "true"));
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
@@ -121,6 +123,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
* Standard peer constructor, with corresponding Component
|
||||
*/
|
||||
WLComponentPeer(Component target) {
|
||||
this(target, true);
|
||||
}
|
||||
|
||||
protected WLComponentPeer(Component target, boolean dropShadow) {
|
||||
this.target = target;
|
||||
this.background = target.getBackground();
|
||||
Dimension size = constrainSize(target.getBounds().getSize());
|
||||
@@ -135,14 +141,11 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
log.fine("WLComponentPeer: target=" + target + " with size=" + wlSize);
|
||||
}
|
||||
|
||||
boolean shadowEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.wl.Shadow", "true"));
|
||||
if (shadowEnabled) {
|
||||
if (dropShadow && shadowEnabled) {
|
||||
shadow = new ShadowImpl(targetIsWlPopup() ? ShadowImage.POPUP_SHADOW_SIZE : ShadowImage.WINDOW_SHADOW_SIZE);
|
||||
} else {
|
||||
shadow = new NilShadow();
|
||||
}
|
||||
// TODO
|
||||
// setup parent window for target
|
||||
}
|
||||
|
||||
int getDisplayScale() {
|
||||
@@ -387,6 +390,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
WLRobotPeer.setLocationOfWLSurface(wlSurface, xNative, yNative);
|
||||
}
|
||||
|
||||
notifyNativeWindowCreated(nativePtr);
|
||||
|
||||
shadow.createSurface();
|
||||
|
||||
// From xdg-shell.xml: "After creating a role-specific object and
|
||||
@@ -394,6 +399,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
// without any buffer attached"
|
||||
shadow.commitSurface();
|
||||
wlSurface.commit();
|
||||
if (!isWlPopup && target.getParent() != null) activate();
|
||||
|
||||
((WLToolkit) Toolkit.getDefaultToolkit()).flush();
|
||||
});
|
||||
@@ -404,6 +410,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
} else {
|
||||
performLocked(() -> {
|
||||
if (wlSurface != null) { // may get a "hide" request even though we were never shown
|
||||
notifyNativeWindowToBeHidden(nativePtr);
|
||||
|
||||
nativeHideFrame(nativePtr);
|
||||
|
||||
shadow.hide();
|
||||
@@ -414,6 +422,12 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyNativeWindowCreated(long nativePtr) {
|
||||
}
|
||||
|
||||
protected void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if our target should be treated as a popup in Wayland's sense,
|
||||
* i.e. it has to have a parent to position relative to.
|
||||
@@ -440,6 +454,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
shadow.updateSurfaceData();
|
||||
}
|
||||
|
||||
public boolean isResizable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSurfaceSize() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
@@ -460,9 +478,15 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
wlSurface.updateSurfaceSize(surfaceWidth, surfaceHeight);
|
||||
nativeSetWindowGeometry(nativePtr, 0, 0, surfaceWidth, surfaceHeight);
|
||||
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
|
||||
if (surfaceMaxSize != null) {
|
||||
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
|
||||
if (isResizable()) {
|
||||
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
|
||||
if (surfaceMaxSize != null) {
|
||||
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
|
||||
}
|
||||
} else {
|
||||
// Prevent SSD from resizing windows that are not meant to be resizeable
|
||||
nativeSetMinimumSize(nativePtr, surfaceWidth, surfaceHeight);
|
||||
nativeSetMaximumSize(nativePtr, surfaceWidth, surfaceHeight);
|
||||
}
|
||||
|
||||
if (popupNeedsReposition()) {
|
||||
@@ -875,6 +899,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
performLocked(() -> nativeShowWindowMenu(serial, nativePtr, xNative, yNative));
|
||||
}
|
||||
|
||||
void setIcon(int size, int[] pixels) {
|
||||
performLocked(() -> nativeSetIcon(nativePtr, size, pixels));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorModel getColorModel() {
|
||||
GraphicsConfiguration graphicsConfig = target.getGraphicsConfiguration();
|
||||
@@ -1092,15 +1120,20 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
private static long getSerialForActivation() {
|
||||
long serial = WLToolkit.getInputState().keyboardEnterSerial(); // a focus event
|
||||
if (serial == 0) { // may have just left one surface and not yet entered another
|
||||
serial = WLToolkit.getInputState().keySerial(); // an input event
|
||||
}
|
||||
if (serial == 0) {
|
||||
// The pointer button serial seems to not work with Mutter, but may work
|
||||
// with other implementations, so let's keep it as an input event serial
|
||||
// of the last resort.
|
||||
serial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
long serial;
|
||||
if (WLToolkit.isKDE()) {
|
||||
serial = WLToolkit.getInputState().latestInputSerial();
|
||||
} else {
|
||||
serial = WLToolkit.getInputState().keyboardEnterSerial(); // a focus event
|
||||
if (serial == 0) { // may have just left one surface and not yet entered another
|
||||
serial = WLToolkit.getInputState().keySerial(); // an input event
|
||||
}
|
||||
if (serial == 0) {
|
||||
// The pointer button serial seems to not work with Mutter but may work
|
||||
// with other implementations, so let's keep it as an input event serial
|
||||
// of the last resort.
|
||||
serial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
}
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
@@ -1138,6 +1171,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
private native void nativeSetMinimumSize(long ptr, int width, int height);
|
||||
private native void nativeSetMaximumSize(long ptr, int width, int height);
|
||||
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
|
||||
private native void nativeSetIcon(long ptr, int size, int[] pixels);
|
||||
|
||||
static long getNativePtrFor(Component component) {
|
||||
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
|
||||
@@ -68,7 +68,7 @@ public class WLDataOffer {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] receiveData(String mime) throws IOException {
|
||||
public synchronized byte[] receiveData(String mime) throws IOException {
|
||||
int fd;
|
||||
|
||||
if (nativePtr == 0) {
|
||||
@@ -86,7 +86,7 @@ public class WLDataOffer {
|
||||
}
|
||||
}
|
||||
|
||||
public void accept(long serial, String mime) {
|
||||
public synchronized void accept(long serial, String mime) {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("nativePtr is 0");
|
||||
}
|
||||
@@ -94,15 +94,17 @@ public class WLDataOffer {
|
||||
acceptImpl(nativePtr, serial, mime);
|
||||
}
|
||||
|
||||
public void finishDnD() {
|
||||
public synchronized void finishDnD() {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("nativePtr is 0");
|
||||
}
|
||||
|
||||
finishDnDImpl(nativePtr);
|
||||
if (selectedAction != 0) {
|
||||
finishDnDImpl(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDnDActions(int actions, int preferredAction) {
|
||||
public synchronized void setDnDActions(int actions, int preferredAction) {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("nativePtr is 0");
|
||||
}
|
||||
|
||||
@@ -40,10 +40,37 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
private final boolean showMaximize;
|
||||
private final boolean showMinimize;
|
||||
|
||||
private final static String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
|
||||
private enum DecorationTypePreference {
|
||||
DEFAULT, // The default decorations painted purely in Java
|
||||
GTK, // Decorations are painted with the help of GTK (if available)
|
||||
SERVER; // Wayland server-side decorations (if available)
|
||||
}
|
||||
|
||||
private static final DecorationTypePreference decorationType = determineDecorationPreferenceType();
|
||||
|
||||
private static DecorationTypePreference determineDecorationPreferenceType() {
|
||||
String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
|
||||
if (decorationPreference != null) {
|
||||
if ("builtin".equals(decorationPreference)) {
|
||||
return DecorationTypePreference.DEFAULT;
|
||||
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
|
||||
return DecorationTypePreference.GTK;
|
||||
} else if ("server".equals(decorationPreference) && WLToolkit.isSSDAvailable()) {
|
||||
return DecorationTypePreference.SERVER;
|
||||
} else {
|
||||
return DecorationTypePreference.DEFAULT;
|
||||
}
|
||||
} else {
|
||||
if (!WLToolkit.isKDE() && isGTKAvailable()) {
|
||||
return DecorationTypePreference.GTK;
|
||||
} else {
|
||||
return DecorationTypePreference.DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WLDecoratedPeer(Window target, boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
|
||||
super(target);
|
||||
super(target, decorationType != DecorationTypePreference.SERVER);
|
||||
this.isUndecorated = isUndecorated;
|
||||
this.showMinimize = showMinimize;
|
||||
this.showMaximize = showMaximize;
|
||||
@@ -54,20 +81,12 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
FrameDecoration d;
|
||||
if (isUndecorated) {
|
||||
d = new MinimalFrameDecoration(this);
|
||||
} else if (decorationPreference != null) {
|
||||
if ("builtin".equals(decorationPreference)) {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
|
||||
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
}
|
||||
} else {
|
||||
if (!WLToolkit.isKDE() && isGTKAvailable()) {
|
||||
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
}
|
||||
d = switch (decorationType) {
|
||||
case DecorationTypePreference.DEFAULT -> new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
case DecorationTypePreference.GTK -> new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
case DecorationTypePreference.SERVER -> new ServerSideFrameDecoration(this);
|
||||
};
|
||||
}
|
||||
return d;
|
||||
}
|
||||
@@ -84,9 +103,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean isResizable();
|
||||
public abstract boolean isInteractivelyResizable();
|
||||
|
||||
public abstract boolean isFrameStateSupported(int state);
|
||||
public abstract void setState(int newState);
|
||||
public abstract int getState();
|
||||
@@ -230,4 +247,14 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
getDecoration().dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyNativeWindowCreated(long nativePtr) {
|
||||
decoration.notifyNativeWindowCreated(nativePtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
decoration.notifyNativeWindowToBeHidden(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,14 @@ public class WLDragSourceContextPeer extends SunDragSourceContextPeer {
|
||||
|
||||
@Override
|
||||
protected synchronized void handleDnDAction(int action) {
|
||||
this.action = action;
|
||||
// This if statement is a workaround for a KWin bug.
|
||||
// KWin 6.5.1 may send an additional action(0) after dnd_drop_performed().
|
||||
// Spec says that after dnd_drop_performed(), no further action() events will be sent,
|
||||
// except for maybe action(dnd_ask), but since we do not announce support for dnd_ask,
|
||||
// we don't need to worry about it.
|
||||
if (!didSucceed) {
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,7 +70,7 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
|
||||
int dropAction = 0;
|
||||
|
||||
if (hasTarget() && event != MouseEvent.MOUSE_EXITED) {
|
||||
dropAction = currentOffer.getSelectedAction();
|
||||
dropAction = WLDataDevice.waylandActionsToJava(currentOffer.getSelectedAction());
|
||||
}
|
||||
|
||||
postDropTargetEvent(
|
||||
@@ -106,7 +106,10 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDropDone(boolean success, int dropAction, boolean isLocal) {
|
||||
protected synchronized void doDropDone(boolean success, int dropAction, boolean isLocal) {
|
||||
if (success && currentOffer != null) {
|
||||
currentOffer.finishDnD();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -115,17 +118,20 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
|
||||
return;
|
||||
}
|
||||
|
||||
int actions = 0;
|
||||
int javaActions = 0;
|
||||
if (hasTarget()) {
|
||||
actions = WLDataDevice.javaActionsToWayland(getTargetActions());
|
||||
javaActions = getTargetActions();
|
||||
}
|
||||
|
||||
int preferredAction = SunDragSourceContextPeer.convertModifiersToDropAction(WLToolkit.getInputState().getModifiers(), actions);
|
||||
int javaPreferredAction = SunDragSourceContextPeer.convertModifiersToDropAction(WLToolkit.getInputState().getModifiers(), javaActions);
|
||||
|
||||
if (actions != lastActions || preferredAction != lastPreferredAction) {
|
||||
currentOffer.setDnDActions(actions, preferredAction);
|
||||
lastActions = actions;
|
||||
lastPreferredAction = preferredAction;
|
||||
int waylandActions = WLDataDevice.javaActionsToWayland(javaActions);
|
||||
int waylandPreferredAction = WLDataDevice.javaActionsToWayland(javaPreferredAction);
|
||||
|
||||
if (waylandActions != lastActions || waylandPreferredAction != lastPreferredAction) {
|
||||
currentOffer.setDnDActions(waylandActions, waylandPreferredAction);
|
||||
lastActions = waylandActions;
|
||||
lastPreferredAction = waylandPreferredAction;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
package sun.awt.wl;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.peer.FramePeer;
|
||||
import sun.awt.AWTAccessor;
|
||||
@@ -43,12 +42,6 @@ public class WLFramePeer extends WLDecoratedPeer implements FramePeer {
|
||||
super(target, target.isUndecorated(),
|
||||
Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.ICONIFIED),
|
||||
Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH));
|
||||
AWTAccessor.getWindowAccessor().addWindowListener(target, new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
getFrame().removeNotify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,6 +43,8 @@ import java.awt.event.InputEvent;
|
||||
* @param pointerButtonPressedEvent null or the latest PointerButtonEvent such that getIsButtonPressed() == true
|
||||
* @param modifiers a bit set of modifiers reflecting currently pressed keys (@see WLInputState.getNewModifiers())
|
||||
* @param surfaceForKeyboardInput represents 'struct wl_surface*' that keyboards events should go to
|
||||
* @param isPointerOverSurface true if the mouse pointer has entered a surface and has not left yet
|
||||
* @param latestInputSerial the serial of the latest input event (key or pointer button press)
|
||||
*/
|
||||
record WLInputState(WLPointerEvent eventWithSurface,
|
||||
long pointerEnterSerial,
|
||||
@@ -54,7 +56,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
PointerButtonEvent pointerButtonPressedEvent,
|
||||
int modifiers,
|
||||
long surfaceForKeyboardInput,
|
||||
boolean isPointerOverSurface) {
|
||||
boolean isPointerOverSurface,
|
||||
long latestInputSerial) {
|
||||
/**
|
||||
* Groups together information about a mouse pointer button event.
|
||||
* @param surface 'struct wl_surface*' the button was pressed over
|
||||
@@ -75,7 +78,7 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
|
||||
static WLInputState initialState() {
|
||||
return new WLInputState(null, 0, 0, 0, 0, null, null,
|
||||
null, 0, 0, false);
|
||||
null, 0, 0, false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,6 +104,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
boolean newPointerOverSurface = (pointerEvent.hasEnterEvent() || isPointerOverSurface)
|
||||
&& !pointerEvent.hasLeaveEvent();
|
||||
|
||||
final long newLatestInputEventSerial = pointerEvent.hasButtonEvent()
|
||||
? pointerEvent.getSerial() : latestInputSerial;
|
||||
|
||||
return new WLInputState(
|
||||
newEventWithSurface,
|
||||
newPointerEnterSerial,
|
||||
@@ -112,7 +118,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
newPointerButtonEvent,
|
||||
newModifiers,
|
||||
surfaceForKeyboardInput,
|
||||
newPointerOverSurface);
|
||||
newPointerOverSurface,
|
||||
newLatestInputEventSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyEvent(long serial) {
|
||||
@@ -127,7 +134,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
surfaceForKeyboardInput,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
serial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardEnterEvent(long serial, long surfacePtr) {
|
||||
@@ -143,7 +151,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
surfacePtr,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardModifiersEvent(long serial, int keyboardModifiers) {
|
||||
@@ -161,7 +170,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
newModifiers,
|
||||
surfaceForKeyboardInput,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardLeaveEvent(long serial, long surfacePtr) {
|
||||
@@ -185,7 +195,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
newModifiers,
|
||||
0,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromUnregisteredSurface(long surfacePtr) {
|
||||
@@ -203,7 +214,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
0,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
@@ -221,7 +233,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers & ~WLPointerEvent.PointerButtonCodes.combinedMask(),
|
||||
surfaceForKeyboardInput,
|
||||
false);
|
||||
false,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
private PointerButtonEvent getNewPointerButtonEvent(WLPointerEvent pointerEvent,
|
||||
|
||||
@@ -83,6 +83,7 @@ import java.awt.peer.TrayIconPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -142,6 +143,11 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
private static final boolean isKDE;
|
||||
|
||||
// NOTE: xdg_toplevel_icon_v1 is pretty much only supported on KDE, and KWin always sends 96px as the icon size,
|
||||
// regardless of the display resolution, scale, or anything else.
|
||||
// TODO: this is currently unused
|
||||
private static final java.util.List<Integer> preferredIconSizes = new ArrayList<>();
|
||||
|
||||
private static native void initIDs(long displayPtr);
|
||||
|
||||
static {
|
||||
@@ -173,11 +179,31 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
toolkitSystemThread.start();
|
||||
|
||||
dataDevice = new WLDataDevice(0); // TODO: for multiseat support pass wl_seat pointer here
|
||||
|
||||
registerShutdownHook();
|
||||
} else {
|
||||
dataDevice = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerShutdownHook() {
|
||||
Runnable r = () -> {
|
||||
ArrayList<WLWindowPeer> livePeers;
|
||||
synchronized (wlSurfaceToPeerMap) {
|
||||
livePeers = new ArrayList<>(wlSurfaceToPeerMap.values());
|
||||
}
|
||||
livePeers.forEach(p -> {
|
||||
Component target = p.getTarget();
|
||||
if (target.isDisplayable()) {
|
||||
target.removeNotify();
|
||||
}
|
||||
});
|
||||
};
|
||||
Thread shutdownThread = InnocuousThread.newSystemThread("WLToolkit-Shutdown-Thread", r);
|
||||
shutdownThread.setDaemon(true);
|
||||
Runtime.getRuntime().addShutdownHook(shutdownThread);
|
||||
}
|
||||
|
||||
public static synchronized boolean getSunAwtDisableGtkFileDialogs() {
|
||||
if (sunAwtDisableGtkFileDialogs == null) {
|
||||
sunAwtDisableGtkFileDialogs = Boolean.getBoolean("sun.awt.disableGtkFileDialogs");
|
||||
@@ -255,7 +281,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
WLToolkit.awtLock();
|
||||
try {
|
||||
dispatchEventsOnEDT();
|
||||
dataDevice.performDeletionsOnEDT();
|
||||
if (dataDevice != null) {
|
||||
dataDevice.performDeletionsOnEDT();
|
||||
}
|
||||
} finally {
|
||||
eventsQueued.release();
|
||||
WLToolkit.awtUnlock();
|
||||
@@ -1071,6 +1099,15 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if xdg-decoration-unstable-v1 is supported and false otherwise.
|
||||
*/
|
||||
public static boolean isSSDAvailable() {
|
||||
return isSSDAvailableImpl();
|
||||
}
|
||||
|
||||
private static native boolean isSSDAvailableImpl();
|
||||
|
||||
private native int readEvents();
|
||||
private native void dispatchEventsOnEDT();
|
||||
private native void flushImpl();
|
||||
@@ -1109,4 +1146,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
public static boolean isKDE() {
|
||||
return isKDE;
|
||||
}
|
||||
|
||||
// called from native
|
||||
private static void handleToplevelIconSize(int size) {
|
||||
preferredIconSizes.add(size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
@@ -51,6 +53,7 @@ import java.awt.image.BufferedImage;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
public class WLWindowPeer extends WLComponentPeer implements WindowPeer, SurfacePixelGrabber {
|
||||
private static Font defaultFont;
|
||||
@@ -77,7 +80,11 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
}
|
||||
|
||||
public WLWindowPeer(Window target) {
|
||||
super(target);
|
||||
this(target, true);
|
||||
}
|
||||
|
||||
public WLWindowPeer(Window target, boolean dropShadow) {
|
||||
super(target, dropShadow);
|
||||
|
||||
if (!target.isFontSet()) {
|
||||
target.setFont(getDefaultFont());
|
||||
@@ -176,7 +183,38 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
@Override
|
||||
public void updateIconImages() {
|
||||
// No support for this from Wayland, icon is a desktop integration feature.
|
||||
List<Image> iconImages = getWindow().getIconImages();
|
||||
if (iconImages == null || iconImages.isEmpty()) {
|
||||
setIcon(0, null);
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = iconImages.stream()
|
||||
.filter(x -> x.getWidth(null) > 0 && x.getHeight(null) > 0)
|
||||
.filter(x -> x.getWidth(null) == x.getHeight(null))
|
||||
.max((a, b) -> Integer.compare(a.getWidth(null), b.getWidth(null)))
|
||||
.orElse(null);
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = image.getWidth(null);
|
||||
int height = image.getHeight(null);
|
||||
int size = width;
|
||||
|
||||
BufferedImage bufferedImage;
|
||||
if (image instanceof BufferedImage && ((BufferedImage) image).getType() == BufferedImage.TYPE_INT_ARGB) {
|
||||
bufferedImage = (BufferedImage) image;
|
||||
} else {
|
||||
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = bufferedImage.createGraphics();
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
bufferedImage.getRGB(0, 0, width, height, pixels, 0, width);
|
||||
setIcon(size, pixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user