diff --git a/.github/workflows/submit.yml b/.github/workflows/submit.yml
index b0a4e7b952e..71cbd228ade 100644
--- a/.github/workflows/submit.yml
+++ b/.github/workflows/submit.yml
@@ -401,7 +401,7 @@ jobs:
--verbose
--include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev,libffi-dev
--resolve-deps
- buster
+ bullseye
~/sysroot-${{ matrix.debian-arch }}
http://httpredir.debian.org/debian/
if: matrix.debian-arch != '' && steps.cache-sysroot.outputs.cache-hit != 'true'
@@ -867,6 +867,8 @@ jobs:
VS2010_DIR: "${{ fromJson(needs.prerequisites.outputs.dependencies).VS2010_DIR }}"
VS2010_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).VS2010_FILENAME }}"
VS2010_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).VS2010_URL }}"
+ VS2010_TORRENT_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).VS2010_TORRENT_URL }}"
+ VS2010_TORRENT_DIR: "${{ fromJson(needs.prerequisites.outputs.dependencies).VS2010_TORRENT_DIR }}"
VS2010_SHA256: "${{ fromJson(needs.prerequisites.outputs.dependencies).VS2010_SHA256 }}"
steps:
@@ -933,10 +935,11 @@ jobs:
- name: Download and unpack Visual Studio 2010
run: |
mkdir "$HOME\$env:VS2010_DIR"
- & curl -L "$env:VS2010_URL" -o "$HOME/$env:VS2010_FILENAME"
- $FileHash = Get-FileHash -Algorithm SHA256 "$HOME/$env:VS2010_FILENAME"
+ $ImagePath = "$HOME/$env:VS2010_TORRENT_DIR/$env:VS2010_FILENAME"
+ & aria2c -d "$HOME" --seed-time=0 --bt-stop-timeout=300 "$env:VS2010_TORRENT_URL" || & curl -L "$env:VS2010_URL" -o "$ImagePath" --create-dirs
+ $FileHash = Get-FileHash -Algorithm SHA256 "$ImagePath"
$FileHash.Hash -eq $env:VS2010_SHA256
- & 7z x -o"$HOME/$env:VS2010_DIR" "$HOME/$env:VS2010_FILENAME"
+ & 7z x -o"$HOME/$env:VS2010_DIR" "$ImagePath"
& dir "$HOME/$env:VS2010_DIR"
if: steps.vs2010.outputs.cache-hit != 'true'
@@ -1328,7 +1331,7 @@ jobs:
macos_x64_build:
name: macOS x64
- runs-on: "macos-11"
+ runs-on: "macos-13"
needs: prerequisites
if: needs.prerequisites.outputs.should_run != 'false' && needs.prerequisites.outputs.platform_macos_x64 != 'false'
@@ -1392,10 +1395,10 @@ jobs:
run: chmod -R a+rx ${HOME}/jtreg/
- name: Install dependencies
- run: brew install make
+ run: brew install make gawk
- name: Select Xcode version
- run: sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer
+ run: sudo xcode-select --switch /Applications/Xcode_14.3.1.app/Contents/Developer
- name: Configure
run: >
@@ -1426,7 +1429,7 @@ jobs:
macos_x64_test:
name: macOS x64
- runs-on: "macos-11"
+ runs-on: "macos-13"
needs:
- prerequisites
- macos_x64_build
@@ -1509,10 +1512,10 @@ jobs:
tar -xzf "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_osx-x64_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_osx-x64_bin${{ matrix.artifact }}"
- name: Install dependencies
- run: brew install make
+ run: brew install make gawk
- name: Select Xcode version
- run: sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer
+ run: sudo xcode-select --switch /Applications/Xcode_14.3.1.app/Contents/Developer
- name: Run tests
run: >
diff --git a/.jcheck/conf b/.jcheck/conf
index e657e8ff3f8..f002fd8b96f 100644
--- a/.jcheck/conf
+++ b/.jcheck/conf
@@ -1,7 +1,7 @@
[general]
project=jdk8u
jbs=JDK
-version=openjdk8u412
+version=openjdk8u422
[checks]
error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 85eb8a16a21..6f17436eff3 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -4440,7 +4440,7 @@ VS_TOOLSET_SUPPORTED_2022=true
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1704508692
+DATE_WHEN_GENERATED=1705630975
###############################################################################
#
@@ -27586,13 +27586,6 @@ fi
as_fn_error $? "The xcodebuild tool was not found, the Xcode command line tools are required to build on Mac OS X" "$LINENO" 5
fi
- # Fail-fast: verify we're building on a supported Xcode version
- XCODE_VERSION=`$XCODEBUILD -version | grep '^Xcode ' | sed 's/Xcode //'`
- XC_VERSION_PARTS=( ${XCODE_VERSION//./ } )
- if test "${XC_VERSION_PARTS[0]}" != "6" -a "${XC_VERSION_PARTS[0]}" != "9" -a "${XC_VERSION_PARTS[0]}" != "10" -a "${XC_VERSION_PARTS[0]}" != "11" -a "${XC_VERSION_PARTS[0]}" != "12" ; then
- as_fn_error $? "Xcode 6, 9-12 is required to build JDK 8, the version found was $XCODE_VERSION. Use --with-xcode-path to specify the location of Xcode or make Xcode active by using xcode-select." "$LINENO" 5
- fi
-
# Some versions of Xcode command line tools install gcc and g++ as symlinks to
# clang and clang++, which will break the build. So handle that here if we need to.
if test -L "/usr/bin/gcc" -o -L "/usr/bin/g++"; then
@@ -57465,4 +57458,3 @@ fi
printf "\n"
fi
fi
-
diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4
index ab0167a6191..ba4798e795f 100644
--- a/common/autoconf/toolchain.m4
+++ b/common/autoconf/toolchain.m4
@@ -287,13 +287,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION],
AC_MSG_ERROR([The xcodebuild tool was not found, the Xcode command line tools are required to build on Mac OS X])
fi
- # Fail-fast: verify we're building on a supported Xcode version
- XCODE_VERSION=`$XCODEBUILD -version | grep '^Xcode ' | sed 's/Xcode //'`
- XC_VERSION_PARTS=( ${XCODE_VERSION//./ } )
- if test "${XC_VERSION_PARTS[[0]]}" != "6" -a "${XC_VERSION_PARTS[[0]]}" != "9" -a "${XC_VERSION_PARTS[[0]]}" != "10" -a "${XC_VERSION_PARTS[[0]]}" != "11" -a "${XC_VERSION_PARTS[[0]]}" != "12" ; then
- AC_MSG_ERROR([Xcode 6, 9-12 is required to build JDK 8, the version found was $XCODE_VERSION. Use --with-xcode-path to specify the location of Xcode or make Xcode active by using xcode-select.])
- fi
-
# Some versions of Xcode command line tools install gcc and g++ as symlinks to
# clang and clang++, which will break the build. So handle that here if we need to.
if test -L "/usr/bin/gcc" -o -L "/usr/bin/g++"; then
diff --git a/common/autoconf/version-numbers b/common/autoconf/version-numbers
index 248532982d6..bd3c3824e33 100644
--- a/common/autoconf/version-numbers
+++ b/common/autoconf/version-numbers
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -26,7 +26,7 @@
JDK_MAJOR_VERSION=1
JDK_MINOR_VERSION=8
JDK_MICRO_VERSION=0
-JDK_UPDATE_VERSION=412
+JDK_UPDATE_VERSION=422
LAUNCHER_NAME=openjdk
PRODUCT_NAME=OpenJDK
PRODUCT_SUFFIX="Runtime Environment"
diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make
index b4f0d39e502..26c215f8d06 100644
--- a/hotspot/make/windows/makefiles/compile.make
+++ b/hotspot/make/windows/makefiles/compile.make
@@ -53,7 +53,7 @@ CXX=cl.exe
# improving the quality of crash log stack traces involving jvm.dll.
# These are always used in all compiles
-CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX
+CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX /wd4800
# Let's add debug information when Full Debug Symbols is enabled
!if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1"
diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp
index 4abd2f03df5..2df1a223fdb 100644
--- a/hotspot/src/os/aix/vm/os_aix.cpp
+++ b/hotspot/src/os/aix/vm/os_aix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1452,7 +1452,7 @@ bool os::dll_address_to_library_name(address addr, char* buf,
// Loads .dll/.so and in case of error it checks if .dll/.so was built
// for the same architecture as Hotspot is running on.
-void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
+static void* dll_load_library(const char *filename, char *ebuf, int ebuflen) {
if (ebuf && ebuflen > 0) {
ebuf[0] = '\0';
@@ -1481,6 +1481,27 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
return NULL;
}
+// Load library named
+// If filename matches .so, and loading fails, repeat with .a.
+void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
+ void* result = NULL;
+ char* const file_path = strdup(filename);
+ char* const pointer_to_dot = strrchr(file_path, '.');
+ const char old_extension[] = ".so";
+ const char new_extension[] = ".a";
+ STATIC_ASSERT(sizeof(old_extension) >= sizeof(new_extension));
+ // First try to load the existing file.
+ result = dll_load_library(filename, ebuf, ebuflen);
+ // If the load fails,we try to reload by changing the extension to .a for .so files only.
+ // Shared object in .so format dont have braces, hence they get removed for archives with members.
+ if (result == NULL && pointer_to_dot != NULL && strcmp(pointer_to_dot, old_extension) == 0) {
+ snprintf(pointer_to_dot, sizeof(old_extension), "%s", new_extension);
+ result = dll_load_library(file_path, ebuf, ebuflen);
+ }
+ FREE_C_HEAP_ARRAY(char, file_path, mtInternal);
+ return result;
+}
+
// Glibc-2.0 libdl is not MT safe. If you are building with any glibc,
// chances are you might want to run the generated bits against glibc-2.0
// libdl.so, so always use locking for any version of glibc.
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
index 54cfcdd116e..5629a640f63 100644
--- a/hotspot/src/os/linux/vm/os_linux.cpp
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
@@ -2008,11 +2008,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
static Elf32_Half running_arch_code=EM_68K;
#elif (defined AARCH64)
static Elf32_Half running_arch_code=EM_AARCH64;
- #elif (defined LOONGARCH)
+ #elif (defined LOONGARCH64)
static Elf32_Half running_arch_code=EM_LOONGARCH;
#else
#error Method os::dll_load requires that one of following is defined:\
- IA32, AMD64, IA64, __sparc, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K, AARCH64, LOONGARCH
+ IA32, AMD64, IA64, __sparc, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K, AARCH64, LOONGARCH64
#endif
// Identify compatability class for VM's architecture and library's architecture
diff --git a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.cpp b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.cpp
index 397b88a08fe..9db92910cd6 100644
--- a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.cpp
+++ b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -441,14 +441,14 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList
if (c) {
jint value = c->type()->as_IntConstant()->value();
- if (value != min_jint) {
- if (ao->op() == Bytecodes::_isub) {
- value = -value;
- }
+ if (ao->op() == Bytecodes::_iadd) {
base = java_add(base, value);
- last_integer = base;
- last_instruction = other;
+ } else {
+ assert(ao->op() == Bytecodes::_isub, "unexpected bytecode");
+ base = java_subtract(base, value);
}
+ last_integer = base;
+ last_instruction = other;
index = other;
} else {
break;
diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp
index aebc377527c..b2bff3809db 100644
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp
@@ -58,6 +58,7 @@
#include "runtime/vframeArray.hpp"
#include "utilities/copy.hpp"
#include "utilities/events.hpp"
+#include "utilities/exceptions.hpp"
// Implementation of StubAssembler
@@ -536,8 +537,9 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
if (TraceExceptions) {
ttyLocker ttyl;
ResourceMark rm;
- tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "",
- exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread));
+ tty->print_cr("Exception <%.*s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "",
+ MAX_LEN, exception->print_value_string(),
+ p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread));
}
// for AbortVMOnException flag
NOT_PRODUCT(Exceptions::debug_check_abort(exception));
diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp
index 1c6b42fceb0..810945d2b46 100644
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -236,7 +236,23 @@ unsigned int SymbolTable::hash_symbol(const char* s, int len) {
// entries in the symbol table during normal execution (only during
// safepoints).
+// Symbols should represent entities from the constant pool that are
+// limited to <64K in length, but usage errors creep in allowing Symbols
+// to be used for arbitrary strings. For debug builds we will assert if
+// a string is too long, whereas product builds will truncate it.
+static int check_length(const char* name, int len) {
+ assert(len <= Symbol::max_length(),
+ "String length exceeds the maximum Symbol length");
+ if (len > Symbol::max_length()) {
+ warning("A string \"%.80s ... %.80s\" exceeds the maximum Symbol "
+ "length of %d and has been truncated", name, (name + len - 80), Symbol::max_length());
+ len = Symbol::max_length();
+ }
+ return len;
+}
+
Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) {
+ len = check_length(name, len);
unsigned int hashValue = hash_symbol(name, len);
int index = the_table()->hash_to_index(hashValue);
@@ -367,6 +383,7 @@ void SymbolTable::add(ClassLoaderData* loader_data, constantPoolHandle cp,
for (int i=0; ihash_to_index(hashValues[i]);
bool c_heap = !loader_data->is_the_null_class_loader_data();
+ assert(lengths[i] <= Symbol::max_length(), "must be - these come from the constant pool");
Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], hashValues[i], c_heap, CHECK);
cp->symbol_at_put(cp_indices[i], sym);
}
@@ -375,7 +392,8 @@ void SymbolTable::add(ClassLoaderData* loader_data, constantPoolHandle cp,
Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
unsigned int hash;
- Symbol* result = SymbolTable::lookup_only((char*)name, (int)strlen(name), hash);
+ int len = check_length(name, (int)strlen(name));
+ Symbol* result = SymbolTable::lookup_only((char*)name, len, hash);
if (result != NULL) {
return result;
}
@@ -384,13 +402,14 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
SymbolTable* table = the_table();
int index = table->hash_to_index(hash);
- return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD);
+ return table->basic_add(index, (u1*)name, len, hash, false, THREAD);
}
Symbol* SymbolTable::basic_add(int index_arg, u1 *name, int len,
unsigned int hashValue_arg, bool c_heap, TRAPS) {
assert(!Universe::heap()->is_in_reserved(name),
"proposed name of symbol must be stable");
+ assert(len <= Symbol::max_length(), "caller should have ensured this");
// Don't allow symbols to be created which cannot fit in a Symbol*.
if (len > Symbol::max_length()) {
diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp
index fe737ae71f5..731e6a8db18 100644
--- a/hotspot/src/share/vm/compiler/compilerOracle.cpp
+++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp
@@ -493,7 +493,8 @@ static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) {
int match = MethodMatcher::Exact;
while (name[0] == '*') {
match |= MethodMatcher::Suffix;
- strcpy(name, name + 1);
+ // Copy remaining string plus NUL to the beginning
+ memmove(name, name + 1, strlen(name + 1) + 1);
}
if (strcmp(name, "*") == 0) return MethodMatcher::Any;
diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
index 3a5f31ae732..d9e561555ff 100644
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
@@ -2854,7 +2854,9 @@ BytecodeInterpreter::run(interpreterState istate) {
if (TraceExceptions) {
ttyLocker ttyl;
ResourceMark rm;
- tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), p2i(except_oop()));
+ tty->print_cr("Exception <%.*s> (" INTPTR_FORMAT ")",
+ MAX_LEN, except_oop->print_value_string(),
+ p2i(except_oop()));
tty->print_cr(" thrown in interpreter method <%s>", METHOD->print_value_string());
tty->print_cr(" at bci %d, continuing at %d for thread " INTPTR_FORMAT,
(int)(istate->bcp() - METHOD->code_base()),
@@ -2870,7 +2872,9 @@ BytecodeInterpreter::run(interpreterState istate) {
if (TraceExceptions) {
ttyLocker ttyl;
ResourceMark rm;
- tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), p2i(except_oop()));
+ tty->print_cr("Exception <%.*s> (" INTPTR_FORMAT ")",
+ MAX_LEN, except_oop->print_value_string(),
+ p2i(except_oop()));
tty->print_cr(" thrown in interpreter method <%s>", METHOD->print_value_string());
tty->print_cr(" at bci %d, unwinding for thread " INTPTR_FORMAT,
(int)(istate->bcp() - METHOD->code_base()),
diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
index cad9d290084..425ad7f4636 100644
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
@@ -56,6 +56,7 @@
#include "runtime/synchronizer.hpp"
#include "runtime/threadCritical.hpp"
#include "utilities/events.hpp"
+#include "utilities/exceptions.hpp"
#ifdef TARGET_ARCH_x86
# include "vm_version_x86.hpp"
#endif
@@ -454,12 +455,13 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea
const char* detail_message = java_lang_Throwable::message_as_utf8(h_exception());
ttyLocker ttyl; // Lock after getting the detail message
if (detail_message != NULL) {
- tty->print_cr("Exception <%s: %s> (" INTPTR_FORMAT ")",
- h_exception->print_value_string(), detail_message,
+ tty->print_cr("Exception <%.*s: %.*s> (" INTPTR_FORMAT ")",
+ MAX_LEN, h_exception->print_value_string(),
+ MAX_LEN, detail_message,
(address)h_exception());
} else {
- tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")",
- h_exception->print_value_string(),
+ tty->print_cr("Exception <%.*s> (" INTPTR_FORMAT ")",
+ MAX_LEN, h_exception->print_value_string(),
(address)h_exception());
}
tty->print_cr(" thrown in interpreter method <%s>", h_method->print_value_string());
diff --git a/hotspot/src/share/vm/oops/symbol.cpp b/hotspot/src/share/vm/oops/symbol.cpp
index 7c18a4ce8b1..385714e5c15 100644
--- a/hotspot/src/share/vm/oops/symbol.cpp
+++ b/hotspot/src/share/vm/oops/symbol.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
#include "memory/resourceArea.hpp"
Symbol::Symbol(const u1* name, int length, int refcount) {
+ assert(length <= max_length(), "SymbolTable should have caught this!");
_refcount = refcount;
_length = length;
_identity_hash = os::random();
diff --git a/hotspot/src/share/vm/oops/symbol.hpp b/hotspot/src/share/vm/oops/symbol.hpp
index aaa55c58992..086650008a0 100644
--- a/hotspot/src/share/vm/oops/symbol.hpp
+++ b/hotspot/src/share/vm/oops/symbol.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -135,6 +135,7 @@ class Symbol : private SymbolBase {
_body[index] = value;
}
+ // Constructor is private for use only by SymbolTable.
Symbol(const u1* name, int length, int refcount);
void* operator new(size_t size, int len, TRAPS) throw();
void* operator new(size_t size, int len, Arena* arena, TRAPS) throw();
diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp
index e56cfa9b5ed..22bfcfdeee8 100644
--- a/hotspot/src/share/vm/opto/addnode.cpp
+++ b/hotspot/src/share/vm/opto/addnode.cpp
@@ -833,6 +833,95 @@ const Type *XorLNode::add_ring( const Type *t0, const Type *t1 ) const {
return TypeLong::make( r0->get_con() ^ r1->get_con() );
}
+
+Node* MaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn) {
+ bool is_int = gvn.type(a)->isa_int();
+ assert(is_int || gvn.type(a)->isa_long(), "int or long inputs");
+ assert(is_int == (gvn.type(b)->isa_int() != NULL), "inconsistent inputs");
+ if (!is_unsigned) {
+ if (is_max) {
+ if (is_int) {
+ Node* res = gvn.transform(new (gvn.C) MaxINode(a, b));
+ assert(gvn.type(res)->is_int()->_lo >= t->is_int()->_lo && gvn.type(res)->is_int()->_hi <= t->is_int()->_hi, "type doesn't match");
+ return res;
+ } else {
+ Node* cmp = gvn.transform(new (gvn.C) CmpLNode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveLNode(bol, a, b, t->is_long()));
+ }
+ } else {
+ if (is_int) {
+ Node* res = gvn.transform(new (gvn.C) MinINode(a, b));
+ assert(gvn.type(res)->is_int()->_lo >= t->is_int()->_lo && gvn.type(res)->is_int()->_hi <= t->is_int()->_hi, "type doesn't match");
+ return res;
+ } else {
+ Node* cmp = gvn.transform(new (gvn.C) CmpLNode(b, a));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveLNode(bol, a, b, t->is_long()));
+ }
+ }
+ } else {
+ if (is_max) {
+ if (is_int) {
+ Node* cmp = gvn.transform(new (gvn.C) CmpUNode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveINode(bol, a, b, t->is_int()));
+ } else {
+ Node* cmp = gvn.transform(new (gvn.C) CmpULNode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveLNode(bol, a, b, t->is_long()));
+ }
+ } else {
+ if (is_int) {
+ Node* cmp = gvn.transform(new (gvn.C) CmpUNode(b, a));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveINode(bol, a, b, t->is_int()));
+ } else {
+ Node* cmp = gvn.transform(new (gvn.C) CmpULNode(b, a));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveLNode(bol, a, b, t->is_long()));
+ }
+ }
+ }
+}
+
+Node* MaxNode::build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn) {
+ bool is_int = gvn.type(a)->isa_int();
+ assert(is_int || gvn.type(a)->isa_long(), "int or long inputs");
+ assert(is_int == (gvn.type(b)->isa_int() != NULL), "inconsistent inputs");
+ Node* zero = NULL;
+ if (is_int) {
+ zero = gvn.intcon(0);
+ } else {
+ zero = gvn.longcon(0);
+ }
+ if (is_max) {
+ if (is_int) {
+ Node* cmp = gvn.transform(new (gvn.C) CmpINode(a, b));
+ Node* sub = gvn.transform(new (gvn.C) SubINode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveINode(bol, sub, zero, t->is_int()));
+ } else {
+ Node* cmp = gvn.transform(new (gvn.C) CmpLNode(a, b));
+ Node* sub = gvn.transform(new (gvn.C) SubLNode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveLNode(bol, sub, zero, t->is_long()));
+ }
+ } else {
+ if (is_int) {
+ Node* cmp = gvn.transform(new (gvn.C) CmpINode(b, a));
+ Node* sub = gvn.transform(new (gvn.C) SubINode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveINode(bol, sub, zero, t->is_int()));
+ } else {
+ Node* cmp = gvn.transform(new (gvn.C) CmpLNode(b, a));
+ Node* sub = gvn.transform(new (gvn.C) SubLNode(a, b));
+ Node* bol = gvn.transform(new (gvn.C) BoolNode(cmp, BoolTest::lt));
+ return gvn.transform(new (gvn.C) CMoveLNode(bol, sub, zero, t->is_long()));
+ }
+ }
+}
+
//=============================================================================
//------------------------------add_ring---------------------------------------
// Supplied function returns the sum of the inputs.
@@ -935,6 +1024,140 @@ Node *MinINode::Ideal(PhaseGVN *phase, bool can_reshape) {
return NULL;
}
+// Collapse the "addition with overflow-protection" pattern, and the symmetrical
+// "subtraction with underflow-protection" pattern. These are created during the
+// unrolling, when we have to adjust the limit by subtracting the stride, but want
+// to protect against underflow: MaxL(SubL(limit, stride), min_jint).
+// If we have more than one of those in a sequence:
+//
+// x con2
+// | |
+// AddL clamp2
+// | |
+// Max/MinL con1
+// | |
+// AddL clamp1
+// | |
+// Max/MinL (n)
+//
+// We want to collapse it to:
+//
+// x con1 con2
+// | | |
+// | AddLNode (new_con)
+// | |
+// AddLNode clamp1
+// | |
+// Max/MinL (n)
+//
+// Note: we assume that SubL was already replaced by an AddL, and that the stride
+// has its sign flipped: SubL(limit, stride) -> AddL(limit, -stride).
+static bool is_clamp(PhaseGVN* phase, Node* n, Node* c) {
+ // Check that the two clamps have the correct values.
+ jlong clamp = (n->Opcode() == Op_MaxL) ? min_jint : max_jint;
+ const TypeLong* t = phase->type(c)->isa_long();
+ return t != NULL && t->is_con() &&
+ t->get_con() == clamp;
+}
+
+static bool is_sub_con(PhaseGVN* phase, Node* n, Node* c) {
+ // Check that the constants are negative if MaxL, and positive if MinL.
+ const TypeLong* t = phase->type(c)->isa_long();
+ return t != NULL && t->is_con() &&
+ t->get_con() < max_jint && t->get_con() > min_jint &&
+ (t->get_con() < 0) == (n->Opcode() == Op_MaxL);
+}
+
+Node* fold_subI_no_underflow_pattern(Node* n, PhaseGVN* phase) {
+ assert(n->Opcode() == Op_MaxL || n->Opcode() == Op_MinL, "sanity");
+ // Verify the graph level by level:
+ Node* add1 = n->in(1);
+ Node* clamp1 = n->in(2);
+ if (add1->Opcode() == Op_AddL && is_clamp(phase, n, clamp1)) {
+ Node* max2 = add1->in(1);
+ Node* con1 = add1->in(2);
+ if (max2->Opcode() == n->Opcode() && is_sub_con(phase, n, con1)) {
+ Node* add2 = max2->in(1);
+ Node* clamp2 = max2->in(2);
+ if (add2->Opcode() == Op_AddL && is_clamp(phase, n, clamp2)) {
+ Node* x = add2->in(1);
+ Node* con2 = add2->in(2);
+ if (is_sub_con(phase, n, con2)) {
+ Node* new_con = phase->transform(new (phase->C) AddLNode(con1, con2));
+ Node* new_sub = phase->transform(new (phase->C) AddLNode(x, new_con));
+ n->set_req_X(1, new_sub, phase);
+ return n;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const Type* MaxLNode::add_ring(const Type* t0, const Type* t1) const {
+ const TypeLong* r0 = t0->is_long();
+ const TypeLong* r1 = t1->is_long();
+
+ return TypeLong::make(MAX2(r0->_lo, r1->_lo), MAX2(r0->_hi, r1->_hi), MAX2(r0->_widen, r1->_widen));
+}
+
+Node* MaxLNode::Identity(PhaseTransform* phase) {
+ const TypeLong* t1 = phase->type(in(1))->is_long();
+ const TypeLong* t2 = phase->type(in(2))->is_long();
+
+ // Can we determine maximum statically?
+ if (t1->_lo >= t2->_hi) {
+ return in(1);
+ } else if (t2->_lo >= t1->_hi) {
+ return in(2);
+ }
+
+ return MaxNode::Identity(phase);
+}
+
+Node* MaxLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
+ Node* n = AddNode::Ideal(phase, can_reshape);
+ if (n != NULL) {
+ return n;
+ }
+ if (can_reshape) {
+ return fold_subI_no_underflow_pattern(this, phase);
+ }
+ return NULL;
+}
+
+const Type* MinLNode::add_ring(const Type* t0, const Type* t1) const {
+ const TypeLong* r0 = t0->is_long();
+ const TypeLong* r1 = t1->is_long();
+
+ return TypeLong::make(MIN2(r0->_lo, r1->_lo), MIN2(r0->_hi, r1->_hi), MIN2(r0->_widen, r1->_widen));
+}
+
+Node* MinLNode::Identity(PhaseTransform* phase) {
+ const TypeLong* t1 = phase->type(in(1))->is_long();
+ const TypeLong* t2 = phase->type(in(2))->is_long();
+
+ // Can we determine minimum statically?
+ if (t1->_lo >= t2->_hi) {
+ return in(2);
+ } else if (t2->_lo >= t1->_hi) {
+ return in(1);
+ }
+
+ return MaxNode::Identity(phase);
+}
+
+Node* MinLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
+ Node* n = AddNode::Ideal(phase, can_reshape);
+ if (n != NULL) {
+ return n;
+ }
+ if (can_reshape) {
+ return fold_subI_no_underflow_pattern(this, phase);
+ }
+ return NULL;
+}
+
//------------------------------add_ring---------------------------------------
// Supplied function returns the sum of the inputs.
const Type *MinINode::add_ring( const Type *t0, const Type *t1 ) const {
diff --git a/hotspot/src/share/vm/opto/addnode.hpp b/hotspot/src/share/vm/opto/addnode.hpp
index 31aed490e78..73234caa3c5 100644
--- a/hotspot/src/share/vm/opto/addnode.hpp
+++ b/hotspot/src/share/vm/opto/addnode.hpp
@@ -217,9 +217,39 @@ class XorLNode : public AddNode {
// all the behavior of addition on a ring. Only new thing is that we allow
// 2 equal inputs to be equal.
class MaxNode : public AddNode {
+private:
+ static Node* build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn);
+ static Node* build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn);
+
public:
MaxNode( Node *in1, Node *in2 ) : AddNode(in1,in2) {}
virtual int Opcode() const = 0;
+
+ static Node* unsigned_max(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
+ return build_min_max(a, b, true, true, t, gvn);
+ }
+
+ static Node* unsigned_min(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
+ return build_min_max(a, b, false, true, t, gvn);
+ }
+
+ static Node* signed_max(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
+ return build_min_max(a, b, true, false, t, gvn);
+ }
+
+ static Node* signed_min(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
+ return build_min_max(a, b, false, false, t, gvn);
+ }
+
+ // max(a-b, 0)
+ static Node* max_diff_with_zero(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
+ return build_min_max_diff_with_zero(a, b, true, t, gvn);
+ }
+
+ // min(a-b, 0)
+ static Node* min_diff_with_zero(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
+ return build_min_max_diff_with_zero(a, b, false, t, gvn);
+ }
};
//------------------------------MaxINode---------------------------------------
@@ -249,4 +279,38 @@ class MinINode : public MaxNode {
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
};
+//------------------------------MaxLNode---------------------------------------
+// MAXimum of 2 longs.
+class MaxLNode : public MaxNode {
+public:
+ MaxLNode(Compile* C, Node* in1, Node* in2) : MaxNode(in1, in2) {
+ init_flags(Flag_is_macro);
+ C->add_macro_node(this);
+ }
+ virtual int Opcode() const;
+ virtual const Type* add_ring(const Type* t0, const Type* t1) const;
+ virtual const Type* add_id() const { return TypeLong::make(min_jlong); }
+ virtual const Type* bottom_type() const { return TypeLong::LONG; }
+ virtual uint ideal_reg() const { return Op_RegL; }
+ virtual Node* Identity(PhaseTransform* phase);
+ virtual Node* Ideal(PhaseGVN *phase, bool can_reshape);
+};
+
+//------------------------------MinLNode---------------------------------------
+// MINimum of 2 longs.
+class MinLNode : public MaxNode {
+public:
+ MinLNode(Compile* C, Node* in1, Node* in2) : MaxNode(in1, in2) {
+ init_flags(Flag_is_macro);
+ C->add_macro_node(this);
+ }
+ virtual int Opcode() const;
+ virtual const Type* add_ring(const Type* t0, const Type* t1) const;
+ virtual const Type* add_id() const { return TypeLong::make(max_jlong); }
+ virtual const Type* bottom_type() const { return TypeLong::LONG; }
+ virtual uint ideal_reg() const { return Op_RegL; }
+ virtual Node* Identity(PhaseTransform* phase);
+ virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
+};
+
#endif // SHARE_VM_OPTO_ADDNODE_HPP
diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp
index c4a964fd56e..7503d81bae6 100644
--- a/hotspot/src/share/vm/opto/classes.hpp
+++ b/hotspot/src/share/vm/opto/classes.hpp
@@ -169,6 +169,7 @@ macro(LoopLimit)
macro(Mach)
macro(MachProj)
macro(MaxI)
+macro(MaxL)
macro(MemBarAcquire)
macro(LoadFence)
macro(MemBarAcquireLock)
@@ -180,6 +181,7 @@ macro(MemBarVolatile)
macro(MemBarStoreStore)
macro(MergeMem)
macro(MinI)
+macro(MinL)
macro(ModD)
macro(ModF)
macro(ModI)
diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp
index ff56804df34..6c0b68a8252 100644
--- a/hotspot/src/share/vm/opto/connode.cpp
+++ b/hotspot/src/share/vm/opto/connode.cpp
@@ -942,6 +942,20 @@ const Type *ConvI2LNode::Value( PhaseTransform *phase ) const {
return tl;
}
+Node* ConvI2LNode::Identity(PhaseTransform* phase) {
+ // If type is in "int" sub-range, we can
+ // convert I2L(L2I(x)) => x
+ // since the conversions have no effect.
+ if (in(1)->Opcode() == Op_ConvL2I) {
+ Node* x = in(1)->in(1);
+ const TypeLong* t = phase->type(x)->isa_long();
+ if (t != NULL && t->_lo >= min_jint && t->_hi <= max_jint) {
+ return x;
+ }
+ }
+ return this;
+}
+
#ifdef _LP64
static inline bool long_ranges_overlap(jlong lo1, jlong hi1,
jlong lo2, jlong hi2) {
diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp
index 21c22762f83..a24c13590a5 100644
--- a/hotspot/src/share/vm/opto/connode.hpp
+++ b/hotspot/src/share/vm/opto/connode.hpp
@@ -513,6 +513,7 @@ class ConvI2LNode : public TypeNode {
virtual int Opcode() const;
virtual const Type *Value( PhaseTransform *phase ) const;
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
+ virtual Node* Identity(PhaseTransform* phase);
virtual uint ideal_reg() const { return Op_RegL; }
};
diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp
index 7b3f3abe819..0ba727ab37f 100644
--- a/hotspot/src/share/vm/opto/loopTransform.cpp
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp
@@ -1291,7 +1291,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
new_limit = _igvn.intcon(limit->get_int() - stride_con);
set_ctrl(new_limit, C->root());
} else {
- // Limit is not constant.
+ // Limit is not constant. Int subtraction could lead to underflow.
if (loop_head->unrolled_count() == 1) { // only for first unroll
// Separate limit by Opaque node in case it is an incremented
// variable from previous loop to avoid using pre-incremented
@@ -1303,53 +1303,37 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
Node* opaq_ctrl = get_ctrl(opaq);
limit = new (C) Opaque2Node( C, limit );
register_new_node( limit, opaq_ctrl );
+
+ // The Opaque2 node created above (in the case of the first unrolling) hides the type of the loop limit.
+ // Propagate this precise type information.
+ limit = new (C) CastIINode(limit, limit_type);
+ register_new_node(limit, opaq_ctrl);
}
- if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) ||
- stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) {
- // No underflow.
- new_limit = new (C) SubINode(limit, stride);
+ // (1) Convert to long.
+ Node* limit_l = new (C) ConvI2LNode(limit);
+ register_new_node(limit_l, get_ctrl(limit));
+ Node* stride_l = _igvn.longcon(stride_con);
+ set_ctrl(stride_l, C->root());
+
+ // (2) Subtract: compute in long, to prevent underflow.
+ Node* new_limit_l = new (C) SubLNode(limit_l, stride_l);
+ register_new_node(new_limit_l, ctrl);
+
+ // (3) Clamp to int range, in case we had subtraction underflow.
+ Node* underflow_clamp_l = _igvn.longcon((stride_con > 0) ? min_jint : max_jint);
+ set_ctrl(underflow_clamp_l, C->root());
+ Node* new_limit_no_underflow_l = NULL;
+ if (stride_con > 0) {
+ // limit = MaxL(limit - stride, min_jint)
+ new_limit_no_underflow_l = new (C) MaxLNode(C, new_limit_l, underflow_clamp_l);
} else {
- // (limit - stride) may underflow.
- // Clamp the adjustment value with MININT or MAXINT:
- //
- // new_limit = limit-stride
- // if (stride > 0)
- // new_limit = (limit < new_limit) ? MININT : new_limit;
- // else
- // new_limit = (limit > new_limit) ? MAXINT : new_limit;
- //
- BoolTest::mask bt = loop_end->test_trip();
- assert(bt == BoolTest::lt || bt == BoolTest::gt, "canonical test is expected");
- Node* adj_max = _igvn.intcon((stride_con > 0) ? min_jint : max_jint);
- set_ctrl(adj_max, C->root());
- Node* old_limit = NULL;
- Node* adj_limit = NULL;
- Node* bol = limit->is_CMove() ? limit->in(CMoveNode::Condition) : NULL;
- if (loop_head->unrolled_count() > 1 &&
- limit->is_CMove() && limit->Opcode() == Op_CMoveI &&
- limit->in(CMoveNode::IfTrue) == adj_max &&
- bol->as_Bool()->_test._test == bt &&
- bol->in(1)->Opcode() == Op_CmpI &&
- bol->in(1)->in(2) == limit->in(CMoveNode::IfFalse)) {
- // Loop was unrolled before.
- // Optimize the limit to avoid nested CMove:
- // use original limit as old limit.
- old_limit = bol->in(1)->in(1);
- // Adjust previous adjusted limit.
- adj_limit = limit->in(CMoveNode::IfFalse);
- adj_limit = new (C) SubINode(adj_limit, stride);
- } else {
- old_limit = limit;
- adj_limit = new (C) SubINode(limit, stride);
- }
- assert(old_limit != NULL && adj_limit != NULL, "");
- register_new_node( adj_limit, ctrl ); // adjust amount
- Node* adj_cmp = new (C) CmpINode(old_limit, adj_limit);
- register_new_node( adj_cmp, ctrl );
- Node* adj_bool = new (C) BoolNode(adj_cmp, bt);
- register_new_node( adj_bool, ctrl );
- new_limit = new (C) CMoveINode(adj_bool, adj_limit, adj_max, TypeInt::INT);
+ // limit = MinL(limit - stride, max_jint)
+ new_limit_no_underflow_l = new (C) MinLNode(C, new_limit_l, underflow_clamp_l);
}
+ register_new_node(new_limit_no_underflow_l, ctrl);
+
+ // (4) Convert back to int.
+ new_limit = new (C) ConvL2INode(new_limit_no_underflow_l);
register_new_node(new_limit, ctrl);
}
assert(new_limit != NULL, "");
@@ -1532,6 +1516,9 @@ bool IdealLoopTree::dominates_backedge(Node* ctrl) {
//------------------------------adjust_limit-----------------------------------
// Helper function that computes new loop limit as (rc_limit-offset)/scale
Node* PhaseIdealLoop::adjust_limit(bool is_positive_stride, Node* scale, Node* offset, Node* rc_limit, Node* old_limit, Node* pre_ctrl, bool round) {
+ Node* old_limit_long = new (C) ConvI2LNode(old_limit);
+ register_new_node(old_limit_long, pre_ctrl);
+
Node* sub = new (C) SubLNode(rc_limit, offset);
register_new_node(sub, pre_ctrl);
Node* limit = new (C) DivLNode(NULL, sub, scale);
@@ -1544,22 +1531,32 @@ Node* PhaseIdealLoop::adjust_limit(bool is_positive_stride, Node* scale, Node* o
register_new_node(limit, pre_ctrl);
}
- // Clamp the limit to handle integer under-/overflows.
+ // Clamp the limit to handle integer under-/overflows by using long values.
+ // We only convert the limit back to int when we handled under-/overflows.
+ // Note that all values are longs in the following computations.
// When reducing the limit, clamp to [min_jint, old_limit]:
- // MIN(old_limit, MAX(limit, min_jint))
+ // INT(MINL(old_limit, MAXL(limit, min_jint)))
+ // - integer underflow of limit: MAXL chooses min_jint.
+ // - integer overflow of limit: MINL chooses old_limit (<= MAX_INT < limit)
// When increasing the limit, clamp to [old_limit, max_jint]:
- // MAX(old_limit, MIN(limit, max_jint))
- Node* cmp = new (C) CmpLNode(limit, _igvn.longcon(is_positive_stride ? min_jint : max_jint));
- register_new_node(cmp, pre_ctrl);
- Node* bol = new (C) BoolNode(cmp, is_positive_stride ? BoolTest::lt : BoolTest::gt);
- register_new_node(bol, pre_ctrl);
- limit = new (C) ConvL2INode(limit);
- register_new_node(limit, pre_ctrl);
- limit = new (C) CMoveINode(bol, limit, _igvn.intcon(is_positive_stride ? min_jint : max_jint), TypeInt::INT);
- register_new_node(limit, pre_ctrl);
+ // INT(MAXL(old_limit, MINL(limit, max_jint)))
+ // - integer overflow of limit: MINL chooses max_jint.
+ // - integer underflow of limit: MAXL chooses old_limit (>= MIN_INT > limit)
+ // INT() is finally converting the limit back to an integer value.
+
+ Node* inner_result_long = NULL;
+ Node* outer_result_long = NULL;
+ if (is_positive_stride) {
+ inner_result_long = new (C) MaxLNode(C, limit, _igvn.longcon(min_jint));
+ outer_result_long = new (C) MinLNode(C, inner_result_long, old_limit_long);
+ } else {
+ inner_result_long = new (C) MinLNode(C, limit, _igvn.longcon(max_jint));
+ outer_result_long = new (C) MaxLNode(C, inner_result_long, old_limit_long);
+ }
+ register_new_node(inner_result_long, pre_ctrl);
+ register_new_node(outer_result_long, pre_ctrl);
- limit = is_positive_stride ? (Node*)(new (C) MinINode(old_limit, limit))
- : (Node*)(new (C) MaxINode(old_limit, limit));
+ limit = new (C) ConvL2INode(outer_result_long);
register_new_node(limit, pre_ctrl);
return limit;
}
diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp
index 737cbcb9ff6..ae3755c636b 100644
--- a/hotspot/src/share/vm/opto/macro.cpp
+++ b/hotspot/src/share/vm/opto/macro.cpp
@@ -2487,7 +2487,9 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
assert(n->Opcode() == Op_LoopLimit ||
n->Opcode() == Op_Opaque1 ||
n->Opcode() == Op_Opaque2 ||
- n->Opcode() == Op_Opaque3, "unknown node type in macro list");
+ n->Opcode() == Op_Opaque3 ||
+ n->Opcode() == Op_MaxL ||
+ n->Opcode() == Op_MinL, "unknown node type in macro list");
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
@@ -2552,6 +2554,18 @@ bool PhaseMacroExpand::expand_macro_nodes() {
_igvn.replace_node(n, repl);
success = true;
#endif
+ } else if (n->Opcode() == Op_MaxL) {
+ // Since MaxL and MinL are not implemented in the backend, we expand them to
+ // a CMoveL construct now. At least until here, the type could be computed
+ // precisely. CMoveL is not so smart, but we can give it at least the best
+ // type we know abouot n now.
+ Node* repl = MaxNode::signed_max(n->in(1), n->in(2), _igvn.type(n), _igvn);
+ _igvn.replace_node(n, repl);
+ success = true;
+ } else if (n->Opcode() == Op_MinL) {
+ Node* repl = MaxNode::signed_min(n->in(1), n->in(2), _igvn.type(n), _igvn);
+ _igvn.replace_node(n, repl);
+ success = true;
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp
index 270b96623c5..feb8ad3e7d7 100644
--- a/hotspot/src/share/vm/opto/node.hpp
+++ b/hotspot/src/share/vm/opto/node.hpp
@@ -506,6 +506,7 @@ class Node {
disconnect_inputs(NULL, c);
}
void set_req_X( uint i, Node *n, PhaseIterGVN *igvn );
+ void set_req_X(uint i, Node *n, PhaseGVN *gvn);
// Find the one non-null required input. RegionNode only
Node *nonnull_req() const;
// Add or remove precedence edges
diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp
index 9c4a7056dd9..0cd51708c4c 100644
--- a/hotspot/src/share/vm/opto/phaseX.cpp
+++ b/hotspot/src/share/vm/opto/phaseX.cpp
@@ -1957,6 +1957,15 @@ void Node::set_req_X( uint i, Node *n, PhaseIterGVN *igvn ) {
}
+void Node::set_req_X(uint i, Node *n, PhaseGVN *gvn) {
+ PhaseIterGVN* igvn = gvn->is_IterGVN();
+ if (igvn == NULL) {
+ set_req(i, n);
+ return;
+ }
+ set_req_X(i, n, igvn);
+}
+
//-------------------------------replace_by-----------------------------------
// Using def-use info, replace one node for another. Follow the def-use info
// to all users of the OLD node. Then make all uses point to the NEW node.
diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp
index aeb52f05cb1..63baac179f3 100644
--- a/hotspot/src/share/vm/opto/superword.cpp
+++ b/hotspot/src/share/vm/opto/superword.cpp
@@ -2187,20 +2187,39 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
_igvn.register_new_node_with_optimizer(N);
_phase->set_ctrl(N, pre_ctrl);
+ // The computation of the new pre-loop limit could overflow or underflow the int range. This is problematic in
+ // combination with Range Check Elimination (RCE), which determines a "safe" range where a RangeCheck will always
+ // succeed. RCE adjusts the pre-loop limit such that we only enter the main-loop once we have reached the "safe"
+ // range, and adjusts the main-loop limit so that we exit the main-loop before we leave the "safe" range. After RCE,
+ // the range of the main-loop can only be safely narrowed, and should never be widened. Hence, the pre-loop limit
+ // can only be increased (for stride > 0), but an add overflow might decrease it, or decreased (for stride < 0), but
+ // a sub underflow might increase it. To prevent that, we perform the Sub / Add and Max / Min with long operations.
+ lim0 = new (_phase->C) ConvI2LNode(lim0);
+ N = new (_phase->C) ConvI2LNode(N);
+ orig_limit = new (_phase->C) ConvI2LNode(orig_limit);
+ _igvn.register_new_node_with_optimizer(lim0);
+ _igvn.register_new_node_with_optimizer(N);
+ _igvn.register_new_node_with_optimizer(orig_limit);
+
// substitute back into (1), so that new limit
// lim = lim0 + N
Node* lim;
if (stride < 0) {
- lim = new (_phase->C) SubINode(lim0, N);
+ lim = new (_phase->C) SubLNode(lim0, N);
} else {
- lim = new (_phase->C) AddINode(lim0, N);
+ lim = new (_phase->C) AddLNode(lim0, N);
}
_igvn.register_new_node_with_optimizer(lim);
_phase->set_ctrl(lim, pre_ctrl);
Node* constrained =
- (stride > 0) ? (Node*) new (_phase->C) MinINode(lim, orig_limit)
- : (Node*) new (_phase->C) MaxINode(lim, orig_limit);
+ (stride > 0) ? (Node*) new (_phase->C) MinLNode(_phase->C, lim, orig_limit)
+ : (Node*) new (_phase->C) MaxLNode(_phase->C, lim, orig_limit);
_igvn.register_new_node_with_optimizer(constrained);
+
+ // We know that the result is in the int range, there is never truncation
+ constrained = new (_phase->C) ConvL2INode(constrained);
+ _igvn.register_new_node_with_optimizer(constrained);
+
_phase->set_ctrl(constrained, pre_ctrl);
_igvn.hash_delete(pre_opaq);
pre_opaq->set_req(1, constrained);
diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp
index 2dcda097ebb..8bb170b4453 100644
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp
@@ -81,6 +81,7 @@ Mutex* Shared_SATB_Q_lock = NULL;
Mutex* DirtyCardQ_FL_lock = NULL;
Monitor* DirtyCardQ_CBL_mon = NULL;
Mutex* Shared_DirtyCardQ_lock = NULL;
+Mutex* MonitoringSupport_lock = NULL;
Mutex* ParGCRareEvent_lock = NULL;
Mutex* EvacFailureStack_lock = NULL;
Mutex* DerivedPointerTableGC_lock = NULL;
@@ -209,6 +210,8 @@ void mutex_init() {
def(StringDedupQueue_lock , Monitor, leaf, true );
def(StringDedupTable_lock , Mutex , leaf, true );
}
+ def(MonitoringSupport_lock , Mutex , leaf, true ); // used for serviceability monitoring support
+
def(ParGCRareEvent_lock , Mutex , leaf , true );
def(DerivedPointerTableGC_lock , Mutex, leaf, true );
def(CodeCache_lock , Mutex , special, true );
diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp
index ec642a24e65..098cb9f443f 100644
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, 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
@@ -101,6 +101,7 @@ extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card
// queue shared by
// non-Java threads.
// (see option ExplicitGCInvokesConcurrent)
+extern Mutex* MonitoringSupport_lock; // Protects updates to the serviceability memory pools and allocated memory high water mark.
extern Mutex* ParGCRareEvent_lock; // Synchronizes various (rare) parallel GC ops.
extern Mutex* EvacFailureStack_lock; // guards the evac failure scan stack
extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp
index 32e3921b2b5..e0e9bcf7e9c 100644
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp
@@ -1747,6 +1747,8 @@ typedef TwoOopHashtable SymbolTwoOopHashtable;
declare_c2_type(MaxNode, AddNode) \
declare_c2_type(MaxINode, MaxNode) \
declare_c2_type(MinINode, MaxNode) \
+ declare_c2_type(MaxLNode, MaxNode) \
+ declare_c2_type(MinLNode, MaxNode) \
declare_c2_type(StartNode, MultiNode) \
declare_c2_type(StartOSRNode, StartNode) \
declare_c2_type(ParmNode, ProjNode) \
diff --git a/hotspot/src/share/vm/services/jmm.h b/hotspot/src/share/vm/services/jmm.h
index e00b882dd1d..00adb4ad584 100644
--- a/hotspot/src/share/vm/services/jmm.h
+++ b/hotspot/src/share/vm/services/jmm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -218,7 +218,8 @@ typedef struct {
} dcmdArgInfo;
typedef struct jmmInterface_1_ {
- void* reserved1;
+ jlong (JNICALL *GetTotalThreadAllocatedMemory)
+ (JNIEnv *env);
jlong (JNICALL *GetOneThreadAllocatedMemory)
(JNIEnv *env,
jlong thread_id);
diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp
index 6163ac35dac..715a9e4c87a 100644
--- a/hotspot/src/share/vm/services/management.cpp
+++ b/hotspot/src/share/vm/services/management.cpp
@@ -37,6 +37,7 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
+#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/serviceThread.hpp"
#include "runtime/thread.inline.hpp"
@@ -428,8 +429,6 @@ static MemoryPool* get_memory_pool_from_jobject(jobject obj, TRAPS) {
return MemoryService::get_memory_pool(ph);
}
-#endif // INCLUDE_MANAGEMENT
-
static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) {
int num_threads = ids_ah->length();
@@ -445,8 +444,6 @@ static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) {
}
}
-#if INCLUDE_MANAGEMENT
-
static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) {
// check if the element of infoArray is of type ThreadInfo class
Klass* threadinfo_klass = Management::java_lang_management_ThreadInfo_klass(CHECK);
@@ -2230,7 +2227,40 @@ jlong Management::ticks_to_ms(jlong ticks) {
return (jlong)(((double)ticks / (double)os::elapsed_frequency())
* (double)1000.0);
}
-#endif // INCLUDE_MANAGEMENT
+
+// Gets the amount of memory allocated on the Java heap since JVM launch.
+JVM_ENTRY(jlong, jmm_GetTotalThreadAllocatedMemory(JNIEnv *env))
+ // We keep a high water mark to ensure monotonicity
+ static jlong high_water_result = 0;
+ static jlong prev_result = 0;
+
+ jlong result;
+ if (Threads_lock->try_lock()) {
+ result = ThreadService::exited_allocated_bytes();
+ for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {
+ jlong size = thread->cooked_allocated_bytes();
+ result += size;
+ }
+ Threads_lock->unlock();
+ } else {
+ // Return the previous result if Threads_lock is locked
+ result = prev_result;
+ }
+
+ {
+ assert(MonitoringSupport_lock != NULL, "Must be");
+ MutexLockerEx ml(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
+ if (result < high_water_result) {
+ // Result wrapped to a negative value, in which case it's
+ // pegged at the last positive value.
+ result = high_water_result;
+ } else {
+ high_water_result = result;
+ }
+ prev_result = result;
+ }
+ return result;
+JVM_END
// Gets the amount of memory allocated on the Java heap for a single thread.
// Returns -1 if the thread does not exist or has terminated.
@@ -2368,11 +2398,8 @@ JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids,
}
JVM_END
-
-
-#if INCLUDE_MANAGEMENT
const struct jmmInterface_1_ jmm_interface = {
- NULL,
+ jmm_GetTotalThreadAllocatedMemory,
jmm_GetOneThreadAllocatedMemory,
jmm_GetVersion,
jmm_GetOptionalSupport,
diff --git a/hotspot/src/share/vm/services/threadService.cpp b/hotspot/src/share/vm/services/threadService.cpp
index 93ba0579fad..3bfd6b538de 100644
--- a/hotspot/src/share/vm/services/threadService.cpp
+++ b/hotspot/src/share/vm/services/threadService.cpp
@@ -58,6 +58,8 @@ PerfVariable* ThreadService::_daemon_threads_count = NULL;
volatile int ThreadService::_exiting_threads_count = 0;
volatile int ThreadService::_exiting_daemon_threads_count = 0;
+volatile jlong ThreadService::_exited_allocated_bytes = 0;
+
ThreadDumpResult* ThreadService::_threaddump_list = NULL;
static const int INITIAL_ARRAY_SIZE = 10;
@@ -119,6 +121,9 @@ void ThreadService::add_thread(JavaThread* thread, bool daemon) {
}
void ThreadService::remove_thread(JavaThread* thread, bool daemon) {
+ // Include hidden thread allcations in exited_allocated_bytes
+ ThreadService::incr_exited_allocated_bytes(thread->cooked_allocated_bytes());
+
Atomic::dec((jint*) &_exiting_threads_count);
if (thread->is_hidden_from_external_view() ||
diff --git a/hotspot/src/share/vm/services/threadService.hpp b/hotspot/src/share/vm/services/threadService.hpp
index 46bc012f73e..5c725db60c8 100644
--- a/hotspot/src/share/vm/services/threadService.hpp
+++ b/hotspot/src/share/vm/services/threadService.hpp
@@ -58,6 +58,8 @@ class ThreadService : public AllStatic {
static PerfVariable* _peak_threads_count;
static PerfVariable* _daemon_threads_count;
+ static volatile jlong _exited_allocated_bytes;
+
// These 2 counters are atomically incremented once the thread is exiting.
// They will be atomically decremented when ThreadService::remove_thread is called.
static volatile int _exiting_threads_count;
@@ -95,6 +97,14 @@ class ThreadService : public AllStatic {
static int exiting_threads_count() { return _exiting_threads_count; }
static int exiting_daemon_threads_count() { return _exiting_daemon_threads_count; }
+ static jlong exited_allocated_bytes() { return Atomic::load(&_exited_allocated_bytes); }
+ static void incr_exited_allocated_bytes(jlong size) {
+ // No need for an atomic add because called under the Threads_lock,
+ // but because _exited_allocated_bytes is read concurrently, need
+ // atomic store to avoid readers seeing a partial update.
+ Atomic::store(_exited_allocated_bytes + size, &_exited_allocated_bytes);
+ }
+
// Support for thread dump
static void add_thread_dump(ThreadDumpResult* dump);
static void remove_thread_dump(ThreadDumpResult* dump);
diff --git a/hotspot/src/share/vm/utilities/exceptions.cpp b/hotspot/src/share/vm/utilities/exceptions.cpp
index db4a17029f1..c2ae6000960 100644
--- a/hotspot/src/share/vm/utilities/exceptions.cpp
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp
@@ -141,10 +141,11 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc
// tracing (do this up front - so it works during boot strapping)
if (TraceExceptions) {
ttyLocker ttyl;
- tty->print_cr("Exception <%s%s%s> (" INTPTR_FORMAT ") \n"
+ tty->print_cr("Exception <%.*s%s%.*s> (" INTPTR_FORMAT ") \n"
"thrown [%s, line %d]\nfor thread " INTPTR_FORMAT,
- h_exception->print_value_string(),
- message ? ": " : "", message ? message : "",
+ MAX_LEN, h_exception->print_value_string(),
+ message ? ": " : "",
+ MAX_LEN, message ? message : "",
(address)h_exception(), file, line, thread);
}
// for AbortVMOnException flag
diff --git a/hotspot/src/share/vm/utilities/exceptions.hpp b/hotspot/src/share/vm/utilities/exceptions.hpp
index 7e10f735e98..995c11d4d95 100644
--- a/hotspot/src/share/vm/utilities/exceptions.hpp
+++ b/hotspot/src/share/vm/utilities/exceptions.hpp
@@ -29,6 +29,9 @@
#include "oops/oopsHierarchy.hpp"
#include "utilities/sizes.hpp"
+// Limit exception message components to 64K (the same max as Symbols)
+#define MAX_LEN 65535
+
// This file provides the basic support for exception handling in the VM.
// Note: We do not use C++ exceptions to avoid compiler dependencies and
// unpredictable performance.
diff --git a/hotspot/src/share/vm/utilities/utf8.cpp b/hotspot/src/share/vm/utilities/utf8.cpp
index 8c013c9b30b..ca60d37dce4 100644
--- a/hotspot/src/share/vm/utilities/utf8.cpp
+++ b/hotspot/src/share/vm/utilities/utf8.cpp
@@ -317,14 +317,16 @@ int UNICODE::utf8_size(jchar c) {
}
int UNICODE::utf8_length(jchar* base, int length) {
- int result = 0;
+ size_t result = 0;
for (int index = 0; index < length; index++) {
jchar c = base[index];
- if ((0x0001 <= c) && (c <= 0x007F)) result += 1;
- else if (c <= 0x07FF) result += 2;
- else result += 3;
+ int sz = utf8_size(c);
+ if (result + sz > INT_MAX-1) {
+ break;
+ }
+ result += sz;
}
- return result;
+ return static_cast(result);
}
char* UNICODE::as_utf8(jchar* base, int length) {
diff --git a/hotspot/test/compiler/loopopts/TestUnrollLimitPreciseType.java b/hotspot/test/compiler/loopopts/TestUnrollLimitPreciseType.java
new file mode 100644
index 00000000000..8a4b7626ba8
--- /dev/null
+++ b/hotspot/test/compiler/loopopts/TestUnrollLimitPreciseType.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test id=test1
+ * @bug 8298935
+ * @summary CMoveI for underflow protection of the limit did not compute a type that was precise enough.
+ * This lead to dead data but zero-trip-guard control did not die -> "malformed control flow".
+ * @run main/othervm
+ * -XX:CompileCommand=compileonly,compiler.loopopts.TestUnrollLimitPreciseType::test1
+ * -XX:CompileCommand=dontinline,compiler.loopopts.TestUnrollLimitPreciseType::*
+ * -XX:MaxVectorSize=64
+ * -Xcomp
+ * -XX:+UnlockExperimentalVMOptions -XX:PerMethodSpecTrapLimit=0 -XX:PerMethodTrapLimit=0
+ * compiler.loopopts.TestUnrollLimitPreciseType test1
+ */
+
+/*
+ * @test id=test2
+ * @bug 8298935
+ * @summary CMoveI for underflow protection of the limit did not compute a type that was precise enough.
+ * This lead to dead data but zero-trip-guard control did not die -> "malformed control flow".
+ * @run main/othervm
+ * -XX:CompileCommand=compileonly,compiler.loopopts.TestUnrollLimitPreciseType::*
+ * -Xcomp
+ * compiler.loopopts.TestUnrollLimitPreciseType test2
+ */
+
+
+package compiler.loopopts;
+
+public class TestUnrollLimitPreciseType {
+ static final int RANGE = 512;
+
+ public static void main(String args[]) {
+ if (args.length != 1) {
+ throw new RuntimeException("Need exactly one argument.");
+ }
+ if (args[0].equals("test1")) {
+ byte[] data = new byte[RANGE];
+ test1(data);
+ } else if (args[0].equals("test2")) {
+ test2();
+ } else {
+ throw new RuntimeException("Do not have: " + args[0]);
+ }
+ }
+
+ public static void test1(byte[] data) {
+ // Did not fully analyze this. But it is also unrolled, SuperWorded,
+ // and further unrolled with vectorlized post loop.
+ // Only seems to reproduce with avx512, and not with avx2.
+ for (int j = 192; j < RANGE; j++) {
+ data[j - 192] = (byte)(data[j] * 11);
+ }
+ }
+
+ static void test2() {
+ // Loop is SuperWord'ed.
+ // We unroll more afterwards, and so add vectorized post loop.
+ // But it turns out that the vectorized post loop is never entered.
+ // This lead to assert, because the zero-trip-guard did not collaspse,
+ // but the CastII with the trip count did die.
+ // Only seems to reproduce with avx512, and not with avx2.
+ double dArr[][] = new double[100][100];
+ for (int i = 2, j = 2; j < 68; j++) {
+ dArr[i][j] = 8;
+ }
+ }
+}
diff --git a/hotspot/test/compiler/oracle/TestCompileCommand.java b/hotspot/test/compiler/oracle/TestCompileCommand.java
new file mode 100644
index 00000000000..e2575ed1fa5
--- /dev/null
+++ b/hotspot/test/compiler/oracle/TestCompileCommand.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.PrintWriter;
+import java.io.File;
+
+import com.oracle.java.testlibrary.*;
+
+/*
+ * @test TestCompileCommand
+ * @bug 8069389
+ * @summary "Regression tests of -XX:CompileCommand"
+ * @library /testlibrary
+ * @run main TestCompileCommand
+ */
+
+public class TestCompileCommand {
+
+ private static final String[][] ARGUMENTS = {
+ {
+ "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789,*0123456789012345678901234567890123456789",
+ "-version"
+ }
+ };
+
+ private static final String[][] OUTPUTS = {
+ {
+ "print *01234567890123456789012345678901234567890123456789.*0123456789012345678901234567890123456789"
+ }
+ };
+
+ private static void verifyValidOption(String[] arguments, String[] expected_outputs) throws Exception {
+ ProcessBuilder pb;
+ OutputAnalyzer out;
+
+ pb = ProcessTools.createJavaProcessBuilder(arguments);
+ out = new OutputAnalyzer(pb.start());
+
+ for (String expected_output : expected_outputs) {
+ out.shouldContain(expected_output);
+ }
+
+ out.shouldNotContain("CompileCommand: An error occured during parsing");
+ out.shouldHaveExitValue(0);
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ if (ARGUMENTS.length != OUTPUTS.length) {
+ throw new RuntimeException("Test is set up incorrectly: length of arguments and expected outputs for type (1) options does not match.");
+ }
+
+ // Check if type (1) options are parsed correctly
+ for (int i = 0; i < ARGUMENTS.length; i++) {
+ verifyValidOption(ARGUMENTS[i], OUTPUTS[i]);
+ }
+ }
+}
diff --git a/hotspot/test/compiler/rangechecks/TestRangeCheckLimits.java b/hotspot/test/compiler/rangechecks/TestRangeCheckLimits.java
new file mode 100644
index 00000000000..ba8af6b2104
--- /dev/null
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckLimits.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8262017
+ * @summary Dominator failure because ConvL2I node becomes TOP due to missing overflow/underflow handling in range check elimination
+ * in PhaseIdealLoop::add_constraint().
+ * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,compiler.rangechecks.TestRangeCheckLimits::*
+ * compiler.rangechecks.TestRangeCheckLimits
+ */
+
+ package compiler.rangechecks;
+
+ public class TestRangeCheckLimits {
+ static int a = 400;
+ static volatile int b;
+ static long lFld;
+ static int iFld;
+
+ public static void main(String[] k) {
+ // Test all cases in PhaseIdealLoop::add_constraint().
+ testPositiveCaseMainLoop();
+ testNegativeCaseMainLoop();
+ testPositiveCasePreLoop();
+ testNegativeCasePreLoop();
+ }
+
+ public static void testPositiveCaseMainLoop() {
+ int e, f, g = 0, h[] = new int[a];
+ double i[] = new double[a];
+ long j = 9;
+ Helper.init(h, 3);
+ for (e = 5; e < 154; e++) {
+ for (f = 1; f < 169; f += 2) {
+ b = e;
+ }
+ i[1] = b;
+ for (g = 8; g < 168; g += 2) {
+ j = g - 5;
+ if (j > Integer.MAX_VALUE - 1) {
+ switch (3) {
+ case 3:
+ }
+ }
+ }
+ }
+ if (g != 168) {
+ throw new RuntimeException("fail");
+ }
+ lFld = j;
+ }
+
+
+ public static void testPositiveCasePreLoop() {
+ int e, f, g = 0, h[] = new int[a];
+ double i[] = new double[a];
+ long j = 9;
+ Helper.init(h, 3);
+ for (e = 5; e < 154; e++) {
+ for (f = 1; f < 169; f += 2) {
+ b = e;
+ }
+ i[1] = b;
+ for (g = 8; g < 168; g += 2) {
+ j = g + 5;
+ if (j > 180) {
+ switch (3) {
+ case 3:
+ }
+ }
+ }
+ }
+ if (g != 168) {
+ throw new RuntimeException("fail");
+ }
+ lFld = j;
+ }
+
+ public static void testNegativeCaseMainLoop() {
+ int e, f, g = 0, h[] = new int[a];
+ double i[] = new double[a];
+ long j = 9;
+ Helper.init(h, 3);
+ for (e = 5; e < 154; e++) {
+ for (f = 1; f < 169; f += 2) {
+ b = e;
+ }
+ i[1] = b;
+ for (g = 8; g < 168; g += 2) {
+ j = g;
+ if (j < 5) {
+ switch (3) {
+ case 3:
+ }
+ }
+ }
+ }
+ if (g != 168) {
+ throw new RuntimeException("fail");
+ }
+ lFld = j;
+ }
+
+
+ public static void testNegativeCasePreLoop() {
+ int e, f, g = 0, h[] = new int[a];
+ double i[] = new double[a];
+ long j = 9;
+ Helper.init(h, 3);
+ for (e = 5; e < 154; e++) {
+ for (f = 1; f < 169; f += 2) {
+ b = e;
+ }
+ i[1] = b;
+ for (g = 168; g > 8; g -= 2) {
+ j = g - 5;
+ if (j > Integer.MAX_VALUE - 1) {
+ switch (3) {
+ case 3:
+ }
+ }
+ }
+ }
+ if (g != 8) {
+ throw new RuntimeException("fail");
+ }
+ lFld = j;
+ }
+}
+
+class Helper {
+ public static void init(int[] a, int seed) {
+ for (int j = 0; j < a.length; j++) {
+ a[j] = (j % 2 == 0) ? seed + j : seed - j;
+ }
+ }
+}
diff --git a/hotspot/test/runtime/containers/cgroup/PlainRead.java b/hotspot/test/runtime/containers/cgroup/PlainRead.java
index b6ea0f9e423..eacca5cbdce 100644
--- a/hotspot/test/runtime/containers/cgroup/PlainRead.java
+++ b/hotspot/test/runtime/containers/cgroup/PlainRead.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -73,9 +73,6 @@ public static void main(String[] args) throws Exception {
if (wb.isContainerized()) {
System.out.println("Inside a cgroup, testing...");
isContainer(output);
- } else {
- System.out.println("Not in a cgroup, testing...");
- isNotContainer(output);
}
}
}
diff --git a/jdk/make/data/cacerts/globalsigne46 b/jdk/make/data/cacerts/globalsigne46
new file mode 100644
index 00000000000..50c7dadefdd
--- /dev/null
+++ b/jdk/make/data/cacerts/globalsigne46
@@ -0,0 +1,20 @@
+Owner: CN=GlobalSign Root E46, O=GlobalSign nv-sa, C=BE
+Issuer: CN=GlobalSign Root E46, O=GlobalSign nv-sa, C=BE
+Serial number: 11d2bbba336ed4bce62468c50d841d98e843
+Valid from: Wed Mar 20 00:00:00 GMT 2019 until: Tue Mar 20 00:00:00 GMT 2046
+Signature algorithm name: SHA384withECDSA
+Subject Public Key Algorithm: 384-bit EC (secp384r1) key
+Version: 3
+-----BEGIN CERTIFICATE-----
+MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx
+CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD
+ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw
+MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex
+HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq
+R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd
+yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
+7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8
++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A=
+-----END CERTIFICATE-----
diff --git a/jdk/make/data/cacerts/globalsignr46 b/jdk/make/data/cacerts/globalsignr46
new file mode 100644
index 00000000000..80d7d92d4fb
--- /dev/null
+++ b/jdk/make/data/cacerts/globalsignr46
@@ -0,0 +1,38 @@
+Owner: CN=GlobalSign Root R46, O=GlobalSign nv-sa, C=BE
+Issuer: CN=GlobalSign Root R46, O=GlobalSign nv-sa, C=BE
+Serial number: 11d2bbb9d723189e405f0a9d2dd0df2567d1
+Valid from: Wed Mar 20 00:00:00 GMT 2019 until: Tue Mar 20 00:00:00 GMT 2046
+Signature algorithm name: SHA384withRSA
+Subject Public Key Algorithm: 4096-bit RSA key
+Version: 3
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA
+MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
+VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy
+MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt
+c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ
+OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG
+vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud
+316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo
+0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE
+y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF
+zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE
++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN
+I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs
+x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa
+ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC
+4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4
+7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
+JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti
+2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk
+pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF
+FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt
+rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk
+ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5
+u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP
+4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6
+N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3
+vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
+-----END CERTIFICATE-----
diff --git a/jdk/make/data/charsetmapping/IBM943.c2b b/jdk/make/data/charsetmapping/IBM943.c2b
new file mode 100644
index 00000000000..f5424fd9842
--- /dev/null
+++ b/jdk/make/data/charsetmapping/IBM943.c2b
@@ -0,0 +1,49 @@
+#
+# source: 34B003AF.RPMAP130
+# c->b only entries
+#
+815C 2015
+8160 FF5E
+8161 2225
+817C FF0D
+88A0 555E
+898B 7130
+89A8 9DD7
+8A9A 5699
+8BA0 4FE0
+8BEB 8EC0
+8C71 7E6B
+8C74 8346
+8CB2 9E7C
+8D8D 9EB4
+8DF2 6805
+8EC6 5C62
+8F4A 7E61
+8FD3 8523
+8FDD 91AC
+90E4 87EC
+917E 6414
+9189 7626
+91CB 9A52
+925C 7C1E
+92CD 6451
+9355 5861
+935E 985A
+9398 79B1
+93C0 7006
+9458 56CA
+948D 525D
+94AC 6F51
+94AE 91B1
+966A 9830
+96CB 9EB5
+9789 840A
+9858 881F
+9BA0 5C5B
+9DB7 6522
+9E94 688E
+E379 7E48
+E445 8141
+E8F6 9839
+FA55 FFE4
+FA59 F86F
diff --git a/jdk/make/gensrc/GensrcSwing.gmk b/jdk/make/gensrc/GensrcSwing.gmk
index ba73623ca04..7b4b6971c7d 100644
--- a/jdk/make/gensrc/GensrcSwing.gmk
+++ b/jdk/make/gensrc/GensrcSwing.gmk
@@ -77,7 +77,7 @@ $(JDK_OUTPUTDIR)/gensrc_no_srczip/_the.generated_beaninfo: $(BEANS_SRC) \
$(ECHO) Generating beaninfo
$(MKDIR) -p $(JDK_OUTPUTDIR)/gensrc_no_srczip/javax/swing
$(JAVA) -Djava.awt.headless=true $(NEW_JAVADOC) \
- -sourcepath "$(JDK_TOPDIR)/src/share/classes$(PATH_SEP)$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes$(PATH_SEP)$(JDK_OUTPUTDIR)/gensrc" \
+ -sourcepath "$(JDK_TOPDIR)/src/share/classes$(PATH_SEP)$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes" \
-doclet build.tools.swingbeaninfo.GenDocletBeanInfo \
-x $(SWINGBEAN_DEBUG_FLAG) -d $(JDK_OUTPUTDIR)/gensrc_no_srczip/javax/swing \
-t $(DOCLET_DATA_DIR)/SwingBeanInfo.template -docletpath $(JDK_OUTPUTDIR)/btclasses \
diff --git a/jdk/make/mapfiles/libmanagement/mapfile-vers b/jdk/make/mapfiles/libmanagement/mapfile-vers
index 7ef8f3ad514..1e1f52578df 100644
--- a/jdk/make/mapfiles/libmanagement/mapfile-vers
+++ b/jdk/make/mapfiles/libmanagement/mapfile-vers
@@ -89,6 +89,7 @@ SUNWprivate_1.1 {
Java_sun_management_ThreadImpl_getThreadUserCpuTime1;
Java_sun_management_ThreadImpl_getThreadAllocatedMemory0;
Java_sun_management_ThreadImpl_getThreadAllocatedMemory1;
+ Java_sun_management_ThreadImpl_getTotalThreadAllocatedMemory;
Java_sun_management_ThreadImpl_resetContentionTimes0;
Java_sun_management_ThreadImpl_resetPeakThreadCount0;
Java_sun_management_ThreadImpl_setThreadContentionMonitoringEnabled0;
diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CTextPipe.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CTextPipe.java
index 797e26f3156..30bae2b256a 100644
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CTextPipe.java
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CTextPipe.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2022, 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
@@ -81,10 +81,57 @@ public void drawString(final SunGraphics2D sg2d, final String s, final double x,
}
}
- public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) {
- final Font prevFont = sg2d.getFont();
- sg2d.setFont(gV.getFont());
+ private boolean hasSlotData(GlyphVector gv) {
+ final int length = gv.getNumGlyphs();
+ for (int i = 0; i < length; i++) {
+ if ((gv.getGlyphCode(i) & CompositeGlyphMapper.SLOTMASK) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private Font getSlotFont(Font font, int slot) {
+ Font2D f2d = FontUtilities.getFont2D(font);
+ if (f2d instanceof CFont) {
+ CompositeFont cf = ((CFont)f2d).getCompositeFont2D();
+ PhysicalFont pf = cf.getSlotFont(slot);
+ Font f = new Font(pf.getFontName(null),
+ font.getStyle(), font.getSize());
+ return f;
+ }
+ return null;
+ }
+
+ private GlyphVector getGlyphVectorWithRange(final Font font, final GlyphVector gV, int start, int count) {
+ int[] glyphs = new int[count];
+ for (int i = 0; i < count; i++) {
+ glyphs[i] = gV.getGlyphCode(start+i) & CompositeGlyphMapper.GLYPHMASK;
+ }
+ // Positions should be null to recalculate by native methods,
+ // if GV was segmented.
+ StandardGlyphVector sgv = new StandardGlyphVector(font,
+ gV.getFontRenderContext(),
+ glyphs,
+ null, // positions
+ null, // indices
+ gV.getLayoutFlags());
+ return sgv;
+ }
+
+ private int getLengthOfSameSlot(final GlyphVector gV, final int targetSlot, final int start, final int length) {
+ int count = 1;
+ for (; start + count < length; count++) {
+ int slot = (gV.getGlyphCode(start + count) &
+ CompositeGlyphMapper.SLOTMASK) >> 24;
+ if (targetSlot != slot) {
+ break;
+ }
+ }
+ return count;
+ }
+ private void drawGlyphVectorImpl(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) {
final long nativeStrikePtr = getNativeStrikePtr(sg2d);
if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) {
final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData();
@@ -92,6 +139,31 @@ public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, fina
} else {
drawGlyphVectorAsShape(sg2d, gV, x, y);
}
+ }
+
+ public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) {
+ final Font prevFont = sg2d.getFont();
+ sg2d.setFont(gV.getFont());
+
+ if (hasSlotData(gV)) {
+ final int length = gV.getNumGlyphs();
+ float[] positions = gV.getGlyphPositions(0, length, null);
+ int start = 0;
+ while (start < length) {
+ int slot = (gV.getGlyphCode(start) &
+ CompositeGlyphMapper.SLOTMASK) >> 24;
+ sg2d.setFont(getSlotFont(gV.getFont(), slot));
+ int count = getLengthOfSameSlot(gV, slot, start, length);
+ GlyphVector rangeGV = getGlyphVectorWithRange(sg2d.getFont(),
+ gV, start, count);
+ drawGlyphVectorImpl(sg2d, rangeGV,
+ x + positions[start * 2],
+ y + positions[start * 2 + 1]);
+ start += count;
+ }
+ } else {
+ drawGlyphVectorImpl(sg2d, gV, x, y);
+ }
sg2d.setFont(prevFont);
}
diff --git a/jdk/src/share/classes/com/sun/management/ThreadMXBean.java b/jdk/src/share/classes/com/sun/management/ThreadMXBean.java
index b1868d5e592..10091860a56 100644
--- a/jdk/src/share/classes/com/sun/management/ThreadMXBean.java
+++ b/jdk/src/share/classes/com/sun/management/ThreadMXBean.java
@@ -109,6 +109,42 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
*/
public long[] getThreadUserTime(long[] ids);
+ /**
+ * Returns an approximation of the total amount of memory, in bytes, allocated
+ * in heap memory by all threads since the Java virtual machine started.
+ * The returned value is an approximation because some Java virtual machine
+ * implementations may use object allocation mechanisms that result in a
+ * delay between the time an object is allocated and the time its size is
+ * recorded.
+ *
+ * @implSpec The default implementation throws {@code UnsupportedOperationException}
+ * if the Java virtual machine implementation does not support thread
+ * memory allocation measurement, and otherwise acts as though thread
+ * memory allocation measurement is disabled.
+ *
+ * @return an approximation of the total memory allocated, in bytes, in
+ * heap memory since the Java virtual machine was started,
+ * if thread memory allocation measurement is enabled;
+ * {@code -1} otherwise.
+ *
+ * @throws UnsupportedOperationException if the Java virtual
+ * machine implementation does not support thread memory allocation
+ * measurement.
+ *
+ * @see #isThreadAllocatedMemorySupported
+ * @see #isThreadAllocatedMemoryEnabled
+ * @see #setThreadAllocatedMemoryEnabled
+ *
+ * @since 8u412
+ */
+ public default long getTotalThreadAllocatedBytes() {
+ if (!isThreadAllocatedMemorySupported()) {
+ throw new UnsupportedOperationException(
+ "Thread allocated memory measurement is not supported.");
+ }
+ return -1;
+ }
+
/**
* Returns an approximation of the total amount of memory, in bytes,
* allocated in heap memory for the current thread.
diff --git a/jdk/src/share/classes/java/net/doc-files/net-properties.html b/jdk/src/share/classes/java/net/doc-files/net-properties.html
index 5aac0c8e3bd..2d25e1b9f34 100644
--- a/jdk/src/share/classes/java/net/doc-files/net-properties.html
+++ b/jdk/src/share/classes/java/net/doc-files/net-properties.html
@@ -172,6 +172,16 @@ Misc HTTP properties
If HTTP keepalive is enabled (see above) this value determines the
maximum number of idle connections that will be simultaneously kept
alive, per destination.
+ http.keepAlive.time.server and
+ http.keepAlive.time.proxy
+ These properties modify the behavior of the HTTP keepalive cache in the case
+ where the server (or proxy) has not specified a keepalive time. If the
+ property is set in this case, then idle connections will be closed after the
+ specified number of seconds. If the property is set, and the server does
+ specify a keepalive time in a "Keep-Alive" response header, then the time specified
+ by the server is used. If the property is not set and also the server
+ does not specify a keepalive time, then connections are kept alive for an
+ implementation defined time, assuming {@code http.keepAlive} is {@code true}.
http.maxRedirects (default: 20)
This integer value determines the maximum number, for a given request,
of HTTP redirects that will be automatically followed by the
diff --git a/jdk/src/share/classes/sun/java2d/SunGraphics2D.java b/jdk/src/share/classes/sun/java2d/SunGraphics2D.java
index 2cec864966b..590b53de389 100644
--- a/jdk/src/share/classes/sun/java2d/SunGraphics2D.java
+++ b/jdk/src/share/classes/sun/java2d/SunGraphics2D.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2152,27 +2152,33 @@ private void doCopyArea(int x, int y, int w, int h, int dx, int dy) {
}
Blit ob = lastCAblit;
- if (dy == 0 && dx > 0 && dx < w) {
- while (w > 0) {
- int partW = Math.min(w, dx);
- w -= partW;
- int sx = x + w;
- ob.Blit(theData, theData, comp, clip,
- sx, y, sx+dx, y+dy, partW, h);
+ try {
+ if (dy == 0 && dx > 0 && dx < w) {
+ while (w > 0) {
+ int partW = Math.min(w, dx);
+ w -= partW;
+ int sx = Math.addExact(x, w);
+ ob.Blit(theData, theData, comp, clip,
+ sx, y, sx+dx, y+dy, partW, h);
+ }
+ return;
}
- return;
- }
- if (dy > 0 && dy < h && dx > -w && dx < w) {
- while (h > 0) {
- int partH = Math.min(h, dy);
- h -= partH;
- int sy = y + h;
- ob.Blit(theData, theData, comp, clip,
- x, sy, x+dx, sy+dy, w, partH);
+ if (dy > 0 && dy < h && dx > -w && dx < w) {
+ while (h > 0) {
+ int partH = Math.min(h, dy);
+ h -= partH;
+ int sy = Math.addExact(y, h);
+ ob.Blit(theData, theData, comp, clip,
+ x, sy, Math.addExact(x, dx), sy+dy, w, partH);
+ }
+ return;
}
+ ob.Blit(theData, theData, comp, clip, x, y,
+ Math.addExact(x, dx), Math.addExact(y, dy), w, h);
+ } catch (ArithmeticException ex) {
+ // We are hitting integer overflow in Math.addExact()
return;
}
- ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h);
}
/*
diff --git a/jdk/src/share/classes/sun/java2d/pipe/DrawImage.java b/jdk/src/share/classes/sun/java2d/pipe/DrawImage.java
index cfa130b8199..3f439772929 100644
--- a/jdk/src/share/classes/sun/java2d/pipe/DrawImage.java
+++ b/jdk/src/share/classes/sun/java2d/pipe/DrawImage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -367,6 +367,13 @@ protected void renderImageXform(SunGraphics2D sg, Image img,
final AffineTransform itx;
try {
itx = tx.createInverse();
+ double[] mat = new double[6];
+ itx.getMatrix(mat);
+ for (double d : mat) {
+ if (!Double.isFinite(d)) {
+ return;
+ }
+ }
} catch (final NoninvertibleTransformException ignored) {
// Non-invertible transform means no output
return;
diff --git a/jdk/src/share/classes/sun/management/ThreadImpl.java b/jdk/src/share/classes/sun/management/ThreadImpl.java
index 4d25d7daddb..612821552a5 100644
--- a/jdk/src/share/classes/sun/management/ThreadImpl.java
+++ b/jdk/src/share/classes/sun/management/ThreadImpl.java
@@ -331,6 +331,13 @@ public void setThreadCpuTimeEnabled(boolean enable) {
}
}
+ public long getTotalThreadAllocatedBytes() {
+ if (isThreadAllocatedMemoryEnabled()) {
+ return getTotalThreadAllocatedMemory();
+ }
+ return -1;
+ }
+
public long getCurrentThreadAllocatedBytes() {
if (isThreadAllocatedMemoryEnabled()) {
return getThreadAllocatedMemory0(0);
@@ -507,6 +514,7 @@ private static native void getThreadInfo1(long[] ids,
private static native void getThreadUserCpuTime1(long[] ids, long[] result);
private static native long getThreadAllocatedMemory0(long id);
private static native void getThreadAllocatedMemory1(long[] ids, long[] result);
+ private static native long getTotalThreadAllocatedMemory();
private static native void setThreadCpuTimeEnabled0(boolean enable);
private static native void setThreadAllocatedMemoryEnabled0(boolean enable);
private static native void setThreadContentionMonitoringEnabled0(boolean enable);
diff --git a/jdk/src/share/classes/sun/net/www/HeaderParser.java b/jdk/src/share/classes/sun/net/www/HeaderParser.java
index 3f1629fa8c6..5e41605ea03 100644
--- a/jdk/src/share/classes/sun/net/www/HeaderParser.java
+++ b/jdk/src/share/classes/sun/net/www/HeaderParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2022, 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
@@ -26,6 +26,7 @@
package sun.net.www;
import java.util.Iterator;
+import java.util.OptionalInt;
/* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
* sensibly:
@@ -244,6 +245,19 @@ public int findInt(String k, int Default) {
return Default;
}
}
+
+ public OptionalInt findInt(String k) {
+ try {
+ String s = findValue(k);
+ if (s == null) {
+ return OptionalInt.empty();
+ }
+ return OptionalInt.of(Integer.parseInt(s));
+ } catch (Throwable t) {
+ return OptionalInt.empty();
+ }
+ }
+
/*
public static void main(String[] a) throws Exception {
System.out.print("enter line to parse> ");
diff --git a/jdk/src/share/classes/sun/net/www/http/HttpClient.java b/jdk/src/share/classes/sun/net/www/http/HttpClient.java
index dd6384efe88..e7440f0b655 100644
--- a/jdk/src/share/classes/sun/net/www/http/HttpClient.java
+++ b/jdk/src/share/classes/sun/net/www/http/HttpClient.java
@@ -28,6 +28,7 @@
import java.io.*;
import java.net.*;
import java.util.Locale;
+import java.util.OptionalInt;
import sun.net.NetworkClient;
import sun.net.ProgressSource;
import sun.net.www.MessageHeader;
@@ -114,13 +115,14 @@ static private int getDefaultPort(String proto) {
recomputing the value of keepingAlive */
int keepAliveConnections = -1; /* number of keep-alives left */
- /**Idle timeout value, in milliseconds. Zero means infinity,
- * iff keepingAlive=true.
- * Unfortunately, we can't always believe this one. If I'm connected
- * through a Netscape proxy to a server that sent me a keep-alive
- * time of 15 sec, the proxy unilaterally terminates my connection
- * after 5 sec. So we have to hard code our effective timeout to
- * 4 sec for the case where we're using a proxy. *SIGH*
+ /*
+ * The timeout if specified by the server. Following values possible
+ * 0: the server specified no keep alive headers
+ * -1: the server provided "Connection: keep-alive" but did not specify a
+ * a particular time in a "Keep-Alive:" headers
+ * -2: the server provided "Connection: keep-alive" and timeout=0
+ * Positive values are the number of seconds specified by the server
+ * in a "Keep-Alive" header
*/
int keepAliveTimeout = 0;
@@ -816,7 +818,23 @@ private boolean parseHTTPHeader(MessageHeader responses, ProgressSource pi, Http
responses.findValue("Keep-Alive"));
/* default should be larger in case of proxy */
keepAliveConnections = p.findInt("max", usingProxy?50:5);
- keepAliveTimeout = p.findInt("timeout", usingProxy?60:5);
+ if (keepAliveConnections < 0) {
+ keepAliveConnections = usingProxy?50:5;
+ }
+ OptionalInt timeout = p.findInt("timeout");
+ if (!timeout.isPresent()) {
+ keepAliveTimeout = -1;
+ } else {
+ keepAliveTimeout = timeout.getAsInt();
+ if (keepAliveTimeout < 0) {
+ // if the server specified a negative (invalid) value
+ // then we set to -1, which is equivalent to no value
+ keepAliveTimeout = -1;
+ } else if (keepAliveTimeout == 0) {
+ // handled specially to mean close connection immediately
+ keepAliveTimeout = -2;
+ }
+ }
}
} else if (b[7] != '0') {
/*
@@ -1070,6 +1088,10 @@ public String getProxyHostUsed() {
}
}
+ public boolean getUsingProxy() {
+ return usingProxy;
+ }
+
/**
* @return the proxy port being used for this client. Meaningless
* if getProxyHostUsed() gives null.
diff --git a/jdk/src/share/classes/sun/net/www/http/KeepAliveCache.java b/jdk/src/share/classes/sun/net/www/http/KeepAliveCache.java
index d6548e0c531..b93653e70e2 100644
--- a/jdk/src/share/classes/sun/net/www/http/KeepAliveCache.java
+++ b/jdk/src/share/classes/sun/net/www/http/KeepAliveCache.java
@@ -38,6 +38,8 @@
import java.util.List;
import sun.security.action.GetIntegerAction;
+import sun.net.www.protocol.http.HttpURLConnection;
+import sun.util.logging.PlatformLogger;
/**
* A class that implements a cache of idle Http connections for keep-alive
@@ -50,6 +52,32 @@ public class KeepAliveCache
implements Runnable {
private static final long serialVersionUID = -2937172892064557949L;
+ // Keep alive time set according to priority specified here:
+ // 1. If server specifies a time with a Keep-Alive header
+ // 2. If user specifies a time with system property below
+ // 3. Default values which depend on proxy vs server and whether
+ // a Connection: keep-alive header was sent by server
+
+ // name suffixed with "server" or "proxy"
+ private static final String keepAliveProp = "http.keepAlive.time.";
+
+ private static final int userKeepAliveServer;
+ private static final int userKeepAliveProxy;
+
+ static final PlatformLogger logger = HttpURLConnection.getHttpLogger();
+
+ @SuppressWarnings("removal")
+ static int getUserKeepAliveSeconds(String type) {
+ int v = AccessController.doPrivileged(
+ new GetIntegerAction(keepAliveProp+type, -1)).intValue();
+ return v < -1 ? -1 : v;
+ }
+
+ static {
+ userKeepAliveServer = getUserKeepAliveSeconds("server");
+ userKeepAliveProxy = getUserKeepAliveSeconds("proxy");
+ }
+
/* maximum # keep-alive connections to maintain at once
* This should be 2 by the HTTP spec, but because we don't support pipe-lining
* a larger value is more appropriate. So we now set a default of 5, and the value
@@ -84,58 +112,96 @@ public KeepAliveCache() {}
* @param url The URL contains info about the host and port
* @param http The HttpClient to be cached
*/
- public synchronized void put(final URL url, Object obj, HttpClient http) {
- boolean startThread = (keepAliveTimer == null);
- if (!startThread) {
- if (!keepAliveTimer.isAlive()) {
- startThread = true;
+ public void put(final URL url, Object obj, HttpClient http) {
+ // this method may need to close an HttpClient, either because
+ // it is not cacheable, or because the cache is at its capacity.
+ // In the latter case, we close the least recently used client.
+ // The client to close is stored in oldClient, and is closed
+ // after cacheLock is released.
+ HttpClient oldClient = null;
+ synchronized (this) {
+ boolean startThread = (keepAliveTimer == null);
+ if (!startThread) {
+ if (!keepAliveTimer.isAlive()) {
+ startThread = true;
+ }
}
- }
- if (startThread) {
- clear();
- /* Unfortunately, we can't always believe the keep-alive timeout we got
- * back from the server. If I'm connected through a Netscape proxy
- * to a server that sent me a keep-alive
- * time of 15 sec, the proxy unilaterally terminates my connection
- * The robustness to get around this is in HttpClient.parseHTTP()
- */
- final KeepAliveCache cache = this;
- AccessController.doPrivileged(new PrivilegedAction() {
- public Void run() {
- // We want to create the Keep-Alive-Timer in the
- // system threadgroup
- ThreadGroup grp = Thread.currentThread().getThreadGroup();
- ThreadGroup parent = null;
- while ((parent = grp.getParent()) != null) {
- grp = parent;
+ if (startThread) {
+ clear();
+ /* Unfortunately, we can't always believe the keep-alive timeout we got
+ * back from the server. If I'm connected through a Netscape proxy
+ * to a server that sent me a keep-alive
+ * time of 15 sec, the proxy unilaterally terminates my connection
+ * The robustness to get around this is in HttpClient.parseHTTP()
+ */
+ final KeepAliveCache cache = this;
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Void run() {
+ // We want to create the Keep-Alive-Timer in the
+ // system threadgroup
+ ThreadGroup grp = Thread.currentThread().getThreadGroup();
+ ThreadGroup parent = null;
+ while ((parent = grp.getParent()) != null) {
+ grp = parent;
+ }
+
+ keepAliveTimer = new Thread(grp, cache, "Keep-Alive-Timer");
+ keepAliveTimer.setDaemon(true);
+ keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2);
+ // Set the context class loader to null in order to avoid
+ // keeping a strong reference to an application classloader.
+ keepAliveTimer.setContextClassLoader(null);
+ keepAliveTimer.start();
+ return null;
}
+ });
+ }
+
+ KeepAliveKey key = new KeepAliveKey(url, obj);
+ ClientVector v = super.get(key);
- keepAliveTimer = new Thread(grp, cache, "Keep-Alive-Timer");
- keepAliveTimer.setDaemon(true);
- keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2);
- // Set the context class loader to null in order to avoid
- // keeping a strong reference to an application classloader.
- keepAliveTimer.setContextClassLoader(null);
- keepAliveTimer.start();
- return null;
+ if (v == null) {
+ int keepAliveTimeout = http.getKeepAliveTimeout();
+ if (keepAliveTimeout == 0) {
+ keepAliveTimeout = getUserKeepAlive(http.getUsingProxy());
+ if (keepAliveTimeout == -1) {
+ // same default for server and proxy
+ keepAliveTimeout = 5;
+ }
+ } else if (keepAliveTimeout == -1) {
+ keepAliveTimeout = getUserKeepAlive(http.getUsingProxy());
+ if (keepAliveTimeout == -1) {
+ // different default for server and proxy
+ keepAliveTimeout = http.getUsingProxy() ? 60 : 5;
+ }
+ } else if (keepAliveTimeout == -2) {
+ keepAliveTimeout = 0;
}
- });
+ // at this point keepAliveTimeout is the number of seconds to keep
+ // alive, which could be 0, if the user specified 0 for the property
+ assert keepAliveTimeout >= 0;
+ if (keepAliveTimeout == 0) {
+ oldClient = http;
+ } else {
+ v = new ClientVector(keepAliveTimeout * 1000);
+ v.put(http);
+ super.put(key, v);
+ }
+ } else {
+ oldClient = v.put(http);
+ }
}
-
- KeepAliveKey key = new KeepAliveKey(url, obj);
- ClientVector v = super.get(key);
-
- if (v == null) {
- int keepAliveTimeout = http.getKeepAliveTimeout();
- v = new ClientVector(keepAliveTimeout > 0 ?
- keepAliveTimeout * 1000 : LIFETIME);
- v.put(http);
- super.put(key, v);
- } else {
- v.put(http);
+ // close after releasing locks
+ if (oldClient != null) {
+ oldClient.closeServer();
}
}
+ // returns the keep alive set by user in system property or -1 if not set
+ private static int getUserKeepAlive(boolean isProxy) {
+ return isProxy ? userKeepAliveProxy : userKeepAliveServer;
+ }
+
/* remove an obsolete HttpClient from its VectorCache */
public synchronized void remove(HttpClient h, Object obj) {
KeepAliveKey key = new KeepAliveKey(h.url, obj);
@@ -159,7 +225,6 @@ synchronized void removeVector(KeepAliveKey k) {
* Check to see if this URL has a cached HttpClient
*/
public synchronized HttpClient get(URL url, Object obj) {
-
KeepAliveKey key = new KeepAliveKey(url, obj);
ClientVector v = super.get(key);
if (v == null) { // nothing in cache yet
@@ -178,6 +243,7 @@ public void run() {
try {
Thread.sleep(LIFETIME);
} catch (InterruptedException e) {}
+ List closeList = null;
// Remove all outdated HttpClients.
synchronized (this) {
@@ -187,15 +253,18 @@ public void run() {
for (KeepAliveKey key : keySet()) {
ClientVector v = get(key);
synchronized (v) {
- KeepAliveEntry e = v.peek();
+ KeepAliveEntry e = v.peekLast();
while (e != null) {
if ((currentTime - e.idleStartTime) > v.nap) {
- v.poll();
- e.hc.closeServer();
+ v.pollLast();
+ if (closeList == null) {
+ closeList = new ArrayList<>();
+ }
+ closeList.add(e.hc);
} else {
break;
}
- e = v.peek();
+ e = v.peekLast();
}
if (v.isEmpty()) {
@@ -208,6 +277,12 @@ public void run() {
removeVector(key);
}
}
+ // close connections outside cacheLock
+ if (closeList != null) {
+ for (HttpClient hc : closeList) {
+ hc.closeServer();
+ }
+ }
} while (!isEmpty());
}
@@ -225,8 +300,8 @@ private void readObject(ObjectInputStream stream)
}
}
-/* FILO order for recycling HttpClients, should run in a thread
- * to time them out. If > maxConns are in use, block.
+/* LIFO order for reusing HttpClients. Most recent entries at the front.
+ * If > maxConns are in use, discard oldest.
*/
class ClientVector extends ArrayDeque {
private static final long serialVersionUID = -8680532108106489459L;
@@ -239,31 +314,37 @@ class ClientVector extends ArrayDeque {
}
synchronized HttpClient get() {
- if (isEmpty()) {
+ // check the most recent connection, use if still valid
+ KeepAliveEntry e = peekFirst();
+ if (e == null) {
return null;
}
- // Loop until we find a connection that has not timed out
- HttpClient hc = null;
long currentTime = System.currentTimeMillis();
- do {
- KeepAliveEntry e = pop();
- if ((currentTime - e.idleStartTime) > nap) {
- e.hc.closeServer();
- } else {
- hc = e.hc;
+ if ((currentTime - e.idleStartTime) > nap) {
+ return null; // all connections stale - will be cleaned up later
+ } else {
+ pollFirst();
+ if (KeepAliveCache.logger.isLoggable(PlatformLogger.Level.FINEST)) {
+ String msg = "cached HttpClient was idle for "
+ + Long.toString(currentTime - e.idleStartTime);
+ KeepAliveCache.logger.finest(msg);
}
- } while ((hc == null) && (!isEmpty()));
- return hc;
+ return e.hc;
+ }
}
/* return a still valid, unused HttpClient */
- synchronized void put(HttpClient h) {
+ synchronized HttpClient put(HttpClient h) {
+ HttpClient staleClient = null;
+ assert KeepAliveCache.getMaxConnections() > 0;
if (size() >= KeepAliveCache.getMaxConnections()) {
- h.closeServer(); // otherwise the connection remains in limbo
- } else {
- push(new KeepAliveEntry(h, System.currentTimeMillis()));
+ // remove oldest connection
+ staleClient = removeLast().hc;
}
+ addFirst(new KeepAliveEntry(h, System.currentTimeMillis()));
+ // close after releasing the locks
+ return staleClient;
}
/* remove an HttpClient */
@@ -291,10 +372,10 @@ private void readObject(ObjectInputStream stream)
}
class KeepAliveKey {
- private String protocol = null;
- private String host = null;
- private int port = 0;
- private Object obj = null; // additional key, such as socketfactory
+ private final String protocol;
+ private final String host;
+ private final int port;
+ private final Object obj; // additional key, such as socketfactory
/**
* Constructor
@@ -335,8 +416,8 @@ public int hashCode() {
}
class KeepAliveEntry {
- HttpClient hc;
- long idleStartTime;
+ final HttpClient hc;
+ final long idleStartTime;
KeepAliveEntry(HttpClient hc, long idleStartTime) {
this.hc = hc;
diff --git a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java
index 98e3fcc3213..590c04e4223 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java
@@ -419,6 +419,14 @@ protected Socket createSocket() throws IOException {
}
}
+ @Override
+ public void closeServer() {
+ try {
+ // SSLSocket.close may block up to timeout. Make sure it's short.
+ serverSocket.setSoTimeout(1);
+ } catch (Exception e) {}
+ super.closeServer();
+ }
@Override
public boolean needsTunneling() {
diff --git a/jdk/src/share/javavm/export/jmm.h b/jdk/src/share/javavm/export/jmm.h
index 23d8fa4061a..508b4c8cb1d 100644
--- a/jdk/src/share/javavm/export/jmm.h
+++ b/jdk/src/share/javavm/export/jmm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -218,7 +218,8 @@ typedef struct {
} dcmdArgInfo;
typedef struct jmmInterface_1_ {
- void* reserved1;
+ jlong (JNICALL *GetTotalThreadAllocatedMemory)
+ (JNIEnv *env);
jlong (JNICALL *GetOneThreadAllocatedMemory)
(JNIEnv *env,
jlong thread_id);
diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h b/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h
index 3d98dd11466..d0ca7fce83d 100644
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h
@@ -86,9 +86,9 @@ extern int assert_failed(const char*);
#define lengthof(array) (sizeof(array)/sizeof(array[0]))
-#define NEW(T, n) (T*) must_malloc((int)(scale_size(n, sizeof(T))))
-#define U_NEW(T, n) (T*) u->alloc(scale_size(n, sizeof(T)))
-#define T_NEW(T, n) (T*) u->temp_alloc(scale_size(n, sizeof(T)))
+#define NEW(T, n) (T*) must_calloc(n, sizeof(T))
+#define U_NEW(T, n) (T*) u->calloc(n, sizeof(T))
+#define T_NEW(T, n) (T*) u->temp_calloc(n, sizeof(T))
// bytes and byte arrays
diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
index 56f391b1e87..a585535c513 100644
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
@@ -507,19 +507,20 @@ static int hash_probes[] = {0, 0};
enum { CHUNK = (1 << 14), SMALL = (1 << 9) };
-// Call malloc. Try to combine small blocks and free much later.
-void* unpacker::alloc_heap(size_t size, bool smallOK, bool temp) {
- if (!smallOK || size > SMALL) {
- void* res = must_malloc((int)size);
+// Call calloc. Try to combine small blocks and free much later.
+void* unpacker::calloc_heap(size_t count, size_t size, bool smallOK, bool temp) {
+ size_t ssize = scale_size(count, size);
+ if (!smallOK || ssize > SMALL) {
+ void* res = must_calloc(count, size);
(temp ? &tmallocs : &mallocs)->add(res);
return res;
}
fillbytes& xsmallbuf = *(temp ? &tsmallbuf : &smallbuf);
- if (!xsmallbuf.canAppend(size+1)) {
+ if (!xsmallbuf.canAppend(ssize+1)) {
xsmallbuf.init(CHUNK);
(temp ? &tmallocs : &mallocs)->add(xsmallbuf.base());
}
- int growBy = (int)size;
+ int growBy = (int)ssize;
growBy += -growBy & 7; // round up mod 8
return xsmallbuf.grow(growBy);
}
@@ -984,10 +985,6 @@ void cpool::init(unpacker* u_, int counts[CONSTANT_Limit]) {
tag_index[tag].init(tag_count[tag], cpMap, tag);
}
- // Initialize *all* our entries once
- for (int i = 0 ; i < maxentries ; i++)
- entries[i].outputIndex = REQUESTED_NONE;
-
initGroupIndexes();
// Initialize hashTab to a generous power-of-two size.
uint pow2 = 1;
@@ -1057,7 +1054,7 @@ static int compare_Utf8_chars(bytes& b1, bytes& b2) {
// Cf. PackageReader.readUtf8Bands
local_inline
-void unpacker::read_Utf8_values(entry* cpMap, int len) {
+void unpacker::read_Utf8_values(entry* cpMap, int len, byte tag) {
// Implicit first Utf8 string is the empty string.
enum {
// certain bands begin with implicit zeroes
@@ -1083,10 +1080,11 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) {
int nbigsuf = 0;
fillbytes charbuf; // buffer to allocate small strings
charbuf.init();
-
// Third band: Read the char values in the unshared suffixes:
cp_Utf8_chars.readData(cp_Utf8_suffix.getIntTotal());
for (i = 0; i < len; i++) {
+ cp.initValues(cpMap[i], tag, i);
+
int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();
if (suffix < 0) {
abort("bad utf8 suffix");
@@ -1235,28 +1233,32 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) {
}
local_inline
-void unpacker::read_single_words(band& cp_band, entry* cpMap, int len) {
+void unpacker::read_single_words(band& cp_band, entry* cpMap, int len, byte tag, int loadable_base) {
cp_band.readData(len);
for (int i = 0; i < len; i++) {
- cpMap[i].value.i = cp_band.getInt(); // coding handles signs OK
+ entry& e = cpMap[i];
+ cp.initValues(e, tag, i, loadable_base);
+ e.value.i = cp_band.getInt(); // coding handles signs OK
}
}
maybe_inline
-void unpacker::read_double_words(band& cp_bands, entry* cpMap, int len) {
+void unpacker::read_double_words(band& cp_bands, entry* cpMap, int len, byte tag, int loadable_base) {
band& cp_band_hi = cp_bands;
band& cp_band_lo = cp_bands.nextBand();
cp_band_hi.readData(len);
cp_band_lo.readData(len);
for (int i = 0; i < len; i++) {
- cpMap[i].value.l = cp_band_hi.getLong(cp_band_lo, true);
+ entry& e = cpMap[i];
+ cp.initValues(e, tag, i, loadable_base);
+ e.value.l = cp_band_hi.getLong(cp_band_lo, true);
}
//cp_band_hi.done();
//cp_band_lo.done();
}
maybe_inline
-void unpacker::read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len) {
+void unpacker::read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len, byte tag, int loadable_base) {
assert(refTag == CONSTANT_Utf8);
cp_band.setIndexByTag(refTag);
cp_band.readData(len);
@@ -1264,6 +1266,7 @@ void unpacker::read_single_refs(band& cp_band, byte refTag, entry* cpMap, int le
int indexTag = (cp_band.bn == e_cp_Class) ? CONSTANT_Class : 0;
for (int i = 0; i < len; i++) {
entry& e = cpMap[i];
+ cp.initValues(e, tag, i, loadable_base);
e.refs = U_NEW(entry*, e.nrefs = 1);
entry* utf = cp_band.getRef();
CHECK;
@@ -1284,7 +1287,7 @@ void unpacker::read_single_refs(band& cp_band, byte refTag, entry* cpMap, int le
maybe_inline
void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag,
- entry* cpMap, int len) {
+ entry* cpMap, int len, byte tag) {
band& cp_band1 = cp_band;
band& cp_band2 = cp_band.nextBand();
cp_band1.setIndexByTag(ref1Tag);
@@ -1294,6 +1297,7 @@ void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag,
CHECK;
for (int i = 0; i < len; i++) {
entry& e = cpMap[i];
+ cp.initValues(e, tag, i);
e.refs = U_NEW(entry*, e.nrefs = 2);
e.refs[0] = cp_band1.getRef();
CHECK;
@@ -1306,7 +1310,7 @@ void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag,
// Cf. PackageReader.readSignatureBands
maybe_inline
-void unpacker::read_signature_values(entry* cpMap, int len) {
+void unpacker::read_signature_values(entry* cpMap, int len, byte tag) {
cp_Signature_form.setIndexByTag(CONSTANT_Utf8);
cp_Signature_form.readData(len);
CHECK;
@@ -1314,6 +1318,7 @@ void unpacker::read_signature_values(entry* cpMap, int len) {
int i;
for (i = 0; i < len; i++) {
entry& e = cpMap[i];
+ cp.initValues(e, tag, i);
entry& form = *cp_Signature_form.getRef();
CHECK;
int nc = 0;
@@ -1350,7 +1355,7 @@ void unpacker::checkLegacy(const char* name) {
}
maybe_inline
-void unpacker::read_method_handle(entry* cpMap, int len) {
+void unpacker::read_method_handle(entry* cpMap, int len, byte tag, int loadable_base) {
if (len > 0) {
checkLegacy(cp_MethodHandle_refkind.name);
}
@@ -1359,6 +1364,7 @@ void unpacker::read_method_handle(entry* cpMap, int len) {
cp_MethodHandle_member.readData(len);
for (int i = 0 ; i < len ; i++) {
entry& e = cpMap[i];
+ cp.initValues(e, tag, i, loadable_base);
e.value.i = cp_MethodHandle_refkind.getInt();
e.refs = U_NEW(entry*, e.nrefs = 1);
e.refs[0] = cp_MethodHandle_member.getRef();
@@ -1367,7 +1373,7 @@ void unpacker::read_method_handle(entry* cpMap, int len) {
}
maybe_inline
-void unpacker::read_method_type(entry* cpMap, int len) {
+void unpacker::read_method_type(entry* cpMap, int len, byte tag, int loadable_base) {
if (len > 0) {
checkLegacy(cp_MethodType.name);
}
@@ -1375,6 +1381,7 @@ void unpacker::read_method_type(entry* cpMap, int len) {
cp_MethodType.readData(len);
for (int i = 0 ; i < len ; i++) {
entry& e = cpMap[i];
+ cp.initValues(e, tag, i, loadable_base);
e.refs = U_NEW(entry*, e.nrefs = 1);
e.refs[0] = cp_MethodType.getRef();
CHECK;
@@ -1382,7 +1389,7 @@ void unpacker::read_method_type(entry* cpMap, int len) {
}
maybe_inline
-void unpacker::read_bootstrap_methods(entry* cpMap, int len) {
+void unpacker::read_bootstrap_methods(entry* cpMap, int len, byte tag) {
if (len > 0) {
checkLegacy(cp_BootstrapMethod_ref.name);
}
@@ -1396,6 +1403,7 @@ void unpacker::read_bootstrap_methods(entry* cpMap, int len) {
for (int i = 0; i < len; i++) {
entry& e = cpMap[i];
int argc = cp_BootstrapMethod_arg_count.getInt();
+ cp.initValues(e, tag, i);
e.value.i = argc;
e.refs = U_NEW(entry*, e.nrefs = argc + 1);
e.refs[0] = cp_BootstrapMethod_ref.getRef();
@@ -1405,23 +1413,22 @@ void unpacker::read_bootstrap_methods(entry* cpMap, int len) {
}
}
}
+
+static bool isLoadableValue(int tag);
// Cf. PackageReader.readConstantPool
void unpacker::read_cp() {
byte* rp0 = rp;
-
- int i;
+ uint cpentries = 0;
+ int loadable_count = 0;
for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
byte tag = TAGS_IN_ORDER[k];
int len = cp.tag_count[tag];
int base = cp.tag_base[tag];
+ int loadable_base = -1;
PRINTCR((1,"Reading %d %s entries...", len, NOT_PRODUCT(TAG_NAME[tag])+0));
entry* cpMap = &cp.entries[base];
- for (i = 0; i < len; i++) {
- cpMap[i].tag = tag;
- cpMap[i].inord = i;
- }
// Initialize the tag's CP index right away, since it might be needed
// in the next pass to initialize the CP for another tag.
#ifndef PRODUCT
@@ -1431,67 +1438,73 @@ void unpacker::read_cp() {
assert(ix->base1 == cpMap);
#endif
+ if (isLoadableValue(tag)) {
+ loadable_base = loadable_count;
+ loadable_count += len;
+ }
+
+ cpentries += len;
switch (tag) {
case CONSTANT_Utf8:
- read_Utf8_values(cpMap, len);
+ read_Utf8_values(cpMap, len, tag);
break;
case CONSTANT_Integer:
- read_single_words(cp_Int, cpMap, len);
+ read_single_words(cp_Int, cpMap, len, tag, loadable_base);
break;
case CONSTANT_Float:
- read_single_words(cp_Float, cpMap, len);
+ read_single_words(cp_Float, cpMap, len, tag, loadable_base);
break;
case CONSTANT_Long:
- read_double_words(cp_Long_hi /*& cp_Long_lo*/, cpMap, len);
+ read_double_words(cp_Long_hi /*& cp_Long_lo*/, cpMap, len, tag, loadable_base);
break;
case CONSTANT_Double:
- read_double_words(cp_Double_hi /*& cp_Double_lo*/, cpMap, len);
+ read_double_words(cp_Double_hi /*& cp_Double_lo*/, cpMap, len, tag, loadable_base);
break;
case CONSTANT_String:
- read_single_refs(cp_String, CONSTANT_Utf8, cpMap, len);
+ read_single_refs(cp_String, CONSTANT_Utf8, cpMap, len, tag, loadable_base);
break;
case CONSTANT_Class:
- read_single_refs(cp_Class, CONSTANT_Utf8, cpMap, len);
+ read_single_refs(cp_Class, CONSTANT_Utf8, cpMap, len, tag, loadable_base);
break;
case CONSTANT_Signature:
- read_signature_values(cpMap, len);
+ read_signature_values(cpMap, len, tag);
break;
case CONSTANT_NameandType:
read_double_refs(cp_Descr_name /*& cp_Descr_type*/,
CONSTANT_Utf8, CONSTANT_Signature,
- cpMap, len);
+ cpMap, len, tag);
break;
case CONSTANT_Fieldref:
read_double_refs(cp_Field_class /*& cp_Field_desc*/,
CONSTANT_Class, CONSTANT_NameandType,
- cpMap, len);
+ cpMap, len, tag);
break;
case CONSTANT_Methodref:
read_double_refs(cp_Method_class /*& cp_Method_desc*/,
CONSTANT_Class, CONSTANT_NameandType,
- cpMap, len);
+ cpMap, len, tag);
break;
case CONSTANT_InterfaceMethodref:
read_double_refs(cp_Imethod_class /*& cp_Imethod_desc*/,
CONSTANT_Class, CONSTANT_NameandType,
- cpMap, len);
+ cpMap, len, tag);
break;
case CONSTANT_MethodHandle:
// consumes cp_MethodHandle_refkind and cp_MethodHandle_member
- read_method_handle(cpMap, len);
+ read_method_handle(cpMap, len, tag, loadable_base);
break;
case CONSTANT_MethodType:
// consumes cp_MethodType
- read_method_type(cpMap, len);
+ read_method_type(cpMap, len, tag, loadable_base);
break;
case CONSTANT_InvokeDynamic:
read_double_refs(cp_InvokeDynamic_spec, CONSTANT_BootstrapMethod,
CONSTANT_NameandType,
- cpMap, len);
+ cpMap, len, tag);
break;
case CONSTANT_BootstrapMethod:
// consumes cp_BootstrapMethod_ref, cp_BootstrapMethod_arg_count and cp_BootstrapMethod_arg
- read_bootstrap_methods(cpMap, len);
+ read_bootstrap_methods(cpMap, len, tag);
break;
default:
assert(false);
@@ -1500,6 +1513,11 @@ void unpacker::read_cp() {
CHECK;
}
+ // Initialize extra entries
+ for (; cpentries < cp.maxentries; cpentries++) {
+ cp.entries[cpentries].outputIndex = REQUESTED_NONE;
+ }
+
cp.expandSignatures();
CHECK;
cp.initMemberIndexes();
@@ -3372,25 +3390,15 @@ bool isLoadableValue(int tag) {
return false;
}
}
-/*
- * this method can be used to size an array using null as the parameter,
- * thereafter can be reused to initialize the array using a valid pointer
- * as a parameter.
- */
-int cpool::initLoadableValues(entry** loadable_entries) {
- int loadable_count = 0;
- for (int i = 0; i < (int)N_TAGS_IN_ORDER; i++) {
- int tag = TAGS_IN_ORDER[i];
- if (!isLoadableValue(tag))
- continue;
- if (loadable_entries != NULL) {
- for (int n = 0 ; n < tag_count[tag] ; n++) {
- loadable_entries[loadable_count + n] = &entries[tag_base[tag] + n];
- }
- }
- loadable_count += tag_count[tag];
+
+void cpool::initValues(entry& e, byte tag, int n, int loadable_base) {
+ e.tag = tag;
+ e.inord = n;
+ e.outputIndex = REQUESTED_NONE;
+ if (loadable_base >= 0) {
+ entry** loadable_entries = tag_group_index[CONSTANT_LoadableValue - CONSTANT_All].base2;
+ loadable_entries[loadable_base + n] = &e;
}
- return loadable_count;
}
// Initialize various views into the constant pool.
@@ -3405,9 +3413,14 @@ void cpool::initGroupIndexes() {
tag_group_index[CONSTANT_All - CONSTANT_All].init(all_count, all_entries, CONSTANT_All);
// Initialize LoadableValues
- int loadable_count = initLoadableValues(NULL);
+ int loadable_count = 0;
+ for (int i = 0; i < (int)N_TAGS_IN_ORDER; i++) {
+ int tag = TAGS_IN_ORDER[i];
+ if (isLoadableValue(tag)) {
+ loadable_count += tag_count[tag];
+ }
+ }
entry** loadable_entries = U_NEW(entry*, loadable_count);
- initLoadableValues(loadable_entries);
tag_group_count[CONSTANT_LoadableValue - CONSTANT_All] = loadable_count;
tag_group_index[CONSTANT_LoadableValue - CONSTANT_All].init(loadable_count,
loadable_entries, CONSTANT_LoadableValue);
diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h
index cec7a88b24e..4ec595333c4 100644
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h
@@ -130,7 +130,7 @@ struct cpool {
void expandSignatures();
void initGroupIndexes();
void initMemberIndexes();
- int initLoadableValues(entry** loadable_entries);
+ void initValues(entry& e, byte tag, int n, int loadable_base=-1);
void computeOutputOrder();
void computeOutputIndexes();
@@ -411,9 +411,9 @@ struct unpacker {
file* get_next_file(); // returns null on last file
// General purpose methods
- void* alloc(size_t size) { return alloc_heap(size, true); }
- void* temp_alloc(size_t size) { return alloc_heap(size, true, true); }
- void* alloc_heap(size_t size, bool smallOK = false, bool temp = false);
+ void* calloc(size_t count, size_t size) { return calloc_heap(count, size, true); }
+ void* temp_calloc(size_t count, size_t size) { return calloc_heap(count, size, true, true); }
+ void* calloc_heap(size_t count, size_t size, bool smallOK = false, bool temp = false);
void saveTo(bytes& b, const char* str) { saveTo(b, (byte*)str, strlen(str)); }
void saveTo(bytes& b, bytes& data) { saveTo(b, data.ptr, data.len); }
void saveTo(bytes& b, byte* ptr, size_t len); //{ b.ptr = U_NEW...}
@@ -494,15 +494,15 @@ struct unpacker {
void read_bcs();
void read_bc_ops();
void read_files();
- void read_Utf8_values(entry* cpMap, int len);
- void read_single_words(band& cp_band, entry* cpMap, int len);
- void read_double_words(band& cp_bands, entry* cpMap, int len);
- void read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len);
- void read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry* cpMap, int len);
- void read_signature_values(entry* cpMap, int len);
- void read_method_handle(entry* cpMap, int len);
- void read_method_type(entry* cpMap, int len);
- void read_bootstrap_methods(entry* cpMap, int len);
+ void read_Utf8_values(entry* cpMap, int len, byte tag);
+ void read_single_words(band& cp_band, entry* cpMap, int len, byte tag, int loadable_base);
+ void read_double_words(band& cp_bands, entry* cpMap, int len, byte tag, int loadable_base);
+ void read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len, byte tag, int loadable_base);
+ void read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry* cpMap, int len, byte tag);
+ void read_signature_values(entry* cpMap, int len, byte tag);
+ void read_method_handle(entry* cpMap, int len, byte tag, int loadable_base);
+ void read_method_type(entry* cpMap, int len, byte tag, int loadable_base);
+ void read_bootstrap_methods(entry* cpMap, int len, byte tag);
};
inline void cpool::abort(const char* msg) { u->abort(msg); }
diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp
index e5197e1a3f1..da39a589545 100644
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp
@@ -46,19 +46,19 @@
#include "unpack.h"
-void* must_malloc(size_t size) {
- size_t msize = size;
+void* must_calloc(size_t count, size_t size) {
+ size_t msize = scale_size(count, size);
#ifdef USE_MTRACE
- if (msize >= 0 && msize < sizeof(int))
- msize = sizeof(int); // see 0xbaadf00d below
+ if (msize >= 0 && msize < sizeof(int)) {
+ size = msize = sizeof(int); // see 0xbaadf00d below
+ count = 1;
+ }
#endif
- void* ptr = (msize > PSIZE_MAX || msize <= 0) ? null : malloc(msize);
- if (ptr != null) {
- memset(ptr, 0, size);
- } else {
+ void* ptr = (msize > PSIZE_MAX || msize <= 0) ? null : calloc(count, size);
+ if (ptr == null) {
unpack_abort(ERROR_ENOMEM);
}
- mtrace('m', ptr, size);
+ mtrace('m', ptr, msize);
return ptr;
}
diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h
index 89619316a0e..ffe0acded4e 100644
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h
@@ -25,7 +25,7 @@
//Definitions of our util functions
-void* must_malloc(size_t size);
+void* must_calloc(size_t count, size_t size);
#ifndef USE_MTRACE
#define mtrace(c, ptr, size)
#else
diff --git a/jdk/src/share/native/sun/java2d/SurfaceData.h b/jdk/src/share/native/sun/java2d/SurfaceData.h
index 349aad1b2e2..5083ae5de1e 100644
--- a/jdk/src/share/native/sun/java2d/SurfaceData.h
+++ b/jdk/src/share/native/sun/java2d/SurfaceData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
#define _Included_SurfaceData
#include
+#include
#ifdef __cplusplus
extern "C" {
@@ -53,6 +54,14 @@ typedef struct {
#define SD_RASINFO_PRIVATE_SIZE 64
+#define UNSAFE_TO_ADD(a, b) \
+ (((a >= 0) && (b >= 0) && (a > (INT_MAX - b))) || \
+ ((a < 0) && (b < 0) && (a < (INT_MIN - b)))) \
+
+#define UNSAFE_TO_SUB(a, b) \
+ (((b >= 0) && (a < 0) && (a < (INT_MIN + b))) || \
+ ((b < 0) && (a >= 0) && (-b > (INT_MAX - a)))) \
+
/*
* The SurfaceDataRasInfo structure is used to pass in and return various
* pieces of information about the destination drawable. In particular:
diff --git a/jdk/src/share/native/sun/java2d/loops/MaskBlit.c b/jdk/src/share/native/sun/java2d/loops/MaskBlit.c
index 21b716e3bcd..e8c8765dd2c 100644
--- a/jdk/src/share/native/sun/java2d/loops/MaskBlit.c
+++ b/jdk/src/share/native/sun/java2d/loops/MaskBlit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -68,14 +68,28 @@ Java_sun_java2d_loops_MaskBlit_MaskBlit
return;
}
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+
srcInfo.bounds.x1 = srcx;
srcInfo.bounds.y1 = srcy;
+ if (UNSAFE_TO_ADD(srcx, width) ||
+ UNSAFE_TO_ADD(srcy, height) ||
+ UNSAFE_TO_ADD(dstx, width) ||
+ UNSAFE_TO_ADD(dsty, height)) {
+ return;
+ }
srcInfo.bounds.x2 = srcx + width;
srcInfo.bounds.y2 = srcy + height;
dstInfo.bounds.x1 = dstx;
dstInfo.bounds.y1 = dsty;
dstInfo.bounds.x2 = dstx + width;
dstInfo.bounds.y2 = dsty + height;
+ if (UNSAFE_TO_SUB(srcx, dstx) ||
+ UNSAFE_TO_SUB(srcy, dsty)) {
+ return;
+ }
srcx -= dstx;
srcy -= dsty;
SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
diff --git a/jdk/src/share/native/sun/java2d/loops/MaskFill.c b/jdk/src/share/native/sun/java2d/loops/MaskFill.c
index 354934069c0..fe0bc406860 100644
--- a/jdk/src/share/native/sun/java2d/loops/MaskFill.c
+++ b/jdk/src/share/native/sun/java2d/loops/MaskFill.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -467,7 +467,7 @@ storePgram(EdgeInfo *pLeftEdge, EdgeInfo *pRightEdge,
#define INSERT_ACCUM(pACCUM, IMIN, IMAX, X0, Y0, X1, Y1, CX1, CX2, MULT) \
do { \
jdouble xmid = ((X0) + (X1)) * 0.5; \
- if (xmid <= (CX2)) { \
+ if (xmid < (CX2)) { \
jdouble sliceh = ((Y1) - (Y0)); \
jdouble slicearea; \
jint i; \
@@ -556,7 +556,7 @@ fillAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
jint cy2 = pRasInfo->bounds.y2;
jint width = cx2 - cx1;
EdgeInfo edges[4];
- jfloat localaccum[MASK_BUF_LEN + 1];
+ jfloat localaccum[MASK_BUF_LEN + 2];
jfloat *pAccum;
if (!storePgram(edges + 0, edges + 2,
@@ -568,12 +568,12 @@ fillAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
}
pAccum = ((width > MASK_BUF_LEN)
- ? malloc((width + 1) * sizeof(jfloat))
+ ? malloc((width + 2) * sizeof(jfloat))
: localaccum);
if (pAccum == NULL) {
return;
}
- memset(pAccum, 0, (width+1) * sizeof(jfloat));
+ memset(pAccum, 0, (width + 2) * sizeof(jfloat));
while (cy1 < cy2) {
jint lmin, lmax, rmin, rmax;
@@ -794,7 +794,7 @@ drawAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
jint cy2 = pRasInfo->bounds.y2;
jint width = cx2 - cx1;
EdgeInfo edges[8];
- jfloat localaccum[MASK_BUF_LEN + 1];
+ jfloat localaccum[MASK_BUF_LEN + 2];
jfloat *pAccum;
if (!storePgram(edges + 0, edges + 6,
@@ -815,12 +815,12 @@ drawAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
JNI_TRUE);
pAccum = ((width > MASK_BUF_LEN)
- ? malloc((width + 1) * sizeof(jfloat))
+ ? malloc((width + 2) * sizeof(jfloat))
: localaccum);
if (pAccum == NULL) {
return;
}
- memset(pAccum, 0, (width+1) * sizeof(jfloat));
+ memset(pAccum, 0, (width + 2) * sizeof(jfloat));
while (cy1 < cy2) {
jint lmin, lmax, rmin, rmax;
diff --git a/jdk/src/share/native/sun/java2d/loops/TransformHelper.c b/jdk/src/share/native/sun/java2d/loops/TransformHelper.c
index dc4ab2fe3e6..4e2b06e6ff2 100644
--- a/jdk/src/share/native/sun/java2d/loops/TransformHelper.c
+++ b/jdk/src/share/native/sun/java2d/loops/TransformHelper.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -120,7 +120,12 @@ TransformInterpFunc *pBicubicFunc = BicubicInterp;
/* We reject coordinates not less than 1<<30 so that the distance between */
/* any 2 of them is less than 1<<31 which would overflow into the sign */
/* bit of a signed long value used to represent fixed point coordinates. */
-#define TX_FIXED_UNSAFE(v) (fabs(v) >= (1<<30))
+#if !defined(_MSC_VER) && (defined(__STDC_VERSION__) && __STDC_VERSION__ <= 199409)
+ #if !defined(isinf)
+ #define isinf(x) (!finite(x))
+ #endif
+#endif
+#define TX_FIXED_UNSAFE(v) (isinf(v) || isnan(v) || fabs(v) >= (1<<30))
static jboolean
checkOverflow(jint dxoff, jint dyoff,
SurfaceDataBounds *pBounds,
diff --git a/jdk/src/share/native/sun/management/ThreadImpl.c b/jdk/src/share/native/sun/management/ThreadImpl.c
index b696f2f7de9..c92ec381d10 100644
--- a/jdk/src/share/native/sun/management/ThreadImpl.c
+++ b/jdk/src/share/native/sun/management/ThreadImpl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -98,7 +98,7 @@ JNIEXPORT jlong JNICALL
Java_sun_management_ThreadImpl_getThreadAllocatedMemory0
(JNIEnv *env, jclass cls, jlong tid)
{
- return jmm_interface->GetOneThreadAllocatedMemory(env, tid);
+ return jmm_interface->GetOneThreadAllocatedMemory(env, tid);
}
JNIEXPORT void JNICALL
@@ -108,6 +108,13 @@ Java_sun_management_ThreadImpl_getThreadAllocatedMemory1
jmm_interface->GetThreadAllocatedMemory(env, ids, sizeArray);
}
+JNIEXPORT jlong JNICALL
+Java_sun_management_ThreadImpl_getTotalThreadAllocatedMemory
+ (JNIEnv *env, jclass cls)
+{
+ return jmm_interface->GetTotalThreadAllocatedMemory(env);
+}
+
JNIEXPORT jobjectArray JNICALL
Java_sun_management_ThreadImpl_findMonitorDeadlockedThreads0
(JNIEnv *env, jclass cls)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index ded5b265426..019e6739618 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -386,8 +386,12 @@ sample/chatserver/ChatTest.java 8178912 generic-all
############################################################################
-# china mainland network
+# cacerts tests
############################################################################
+security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java#certignarootca 8331883 generic-all
+security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java 8314509 generic-all
+
+# china mainland network
security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java generic-all
diff --git a/jdk/test/com/sun/awt/SecurityWarning/GetSizeShouldNotReturnZero.java b/jdk/test/com/sun/awt/SecurityWarning/GetSizeShouldNotReturnZero.java
index bf4cdc5bb3a..2c4e8f54459 100644
--- a/jdk/test/com/sun/awt/SecurityWarning/GetSizeShouldNotReturnZero.java
+++ b/jdk/test/com/sun/awt/SecurityWarning/GetSizeShouldNotReturnZero.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
@test %W% %E%
+ @key headful
@bug 6818312
@summary The size returned by SecurityWarning.getSize() should not be zero
@author anthony.petrov@sun.com: area=awt.toplevel
diff --git a/jdk/test/com/sun/awt/Translucency/WindowOpacity.java b/jdk/test/com/sun/awt/Translucency/WindowOpacity.java
index a8391503238..f10182131f3 100644
--- a/jdk/test/com/sun/awt/Translucency/WindowOpacity.java
+++ b/jdk/test/com/sun/awt/Translucency/WindowOpacity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
@test %W% %E%
+ @key headful
@bug 6594131
@summary Tests the AWTUtilities.get/setWindowOpacity() methods
@author anthony.petrov@...: area=awt.toplevel
diff --git a/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemory.java b/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemory.java
index 9d954f92a85..16d8eb04325 100644
--- a/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemory.java
+++ b/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, 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
@@ -22,10 +22,19 @@
*/
/*
- * @test
- * @bug 6173675 8231209
+ * @test id=G1
+ * @bug 6173675 8231209 8304074 8313081
* @summary Basic test of ThreadMXBean.getThreadAllocatedBytes
- * @author Paul Hohensee
+ * @requires vm.gc == "G1"
+ * @run main/othervm -XX:+UseG1GC ThreadAllocatedMemory
+ */
+
+/*
+ * @test id=Serial
+ * @bug 6173675 8231209 8304074 8313081
+ * @summary Basic test of ThreadMXBean.getThreadAllocatedBytes
+ * @requires vm.gc == "Serial"
+ * @run main/othervm -XX:+UseSerialGC ThreadAllocatedMemory
*/
import java.lang.management.*;
@@ -33,6 +42,7 @@
public class ThreadAllocatedMemory {
private static com.sun.management.ThreadMXBean mbean =
(com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean();
+ private static boolean testFailed = false;
private static volatile boolean done = false;
private static volatile boolean done1 = false;
private static Object obj = new Object();
@@ -55,6 +65,13 @@ public static void main(String[] argv)
// Test many threads that are not this one
testGetThreadsAllocatedBytes();
+ // Test cumulative Java thread allocation since JVM launch
+ testGetTotalThreadAllocatedBytes();
+
+ if (testFailed) {
+ throw new RuntimeException("TEST FAILED");
+ }
+
System.out.println("Test passed");
}
@@ -92,13 +109,15 @@ private static void testSupportEnableDisable() {
}
private static void testGetCurrentThreadAllocatedBytes() {
+ Thread curThread = Thread.currentThread();
+
long size = mbean.getCurrentThreadAllocatedBytes();
- ensureValidSize(size);
+ ensureValidSize(curThread, size);
// do some more allocation
doit();
- checkResult(Thread.currentThread(), size,
+ checkResult(curThread, size,
mbean.getCurrentThreadAllocatedBytes());
}
@@ -107,7 +126,7 @@ private static void testCurrentThreadGetThreadAllocatedBytes() {
long id = curThread.getId();
long size = mbean.getThreadAllocatedBytes(id);
- ensureValidSize(size);
+ ensureValidSize(curThread, size);
// do some more allocation
doit();
@@ -119,7 +138,8 @@ private static void testGetThreadAllocatedBytes()
throws Exception {
// start a thread
- done = false; done1 = false;
+ done = false;
+ done1 = false;
Thread curThread = new MyThread("MyThread");
curThread.start();
long id = curThread.getId();
@@ -128,7 +148,7 @@ private static void testGetThreadAllocatedBytes()
waitUntilThreadBlocked(curThread);
long size = mbean.getThreadAllocatedBytes(id);
- ensureValidSize(size);
+ ensureValidSize(curThread, size);
// let thread go to do some more allocation
synchronized (obj) {
@@ -152,8 +172,7 @@ private static void testGetThreadAllocatedBytes()
try {
curThread.join();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
+ reportUnexpected(e, "during join");
}
}
@@ -161,7 +180,8 @@ private static void testGetThreadsAllocatedBytes()
throws Exception {
// start threads
- done = false; done1 = false;
+ done = false;
+ done1 = false;
for (int i = 0; i < NUM_THREADS; i++) {
threads[i] = new MyThread("MyThread-" + i);
threads[i].start();
@@ -172,7 +192,7 @@ private static void testGetThreadsAllocatedBytes()
for (int i = 0; i < NUM_THREADS; i++) {
sizes[i] = mbean.getThreadAllocatedBytes(threads[i].getId());
- ensureValidSize(sizes[i]);
+ ensureValidSize(threads[i], sizes[i]);
}
// let threads go to do some more allocation
@@ -201,38 +221,106 @@ private static void testGetThreadsAllocatedBytes()
try {
threads[i].join();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
+ reportUnexpected(e, "during join");
break;
}
}
}
- private static void ensureValidSize(long size) {
+ private static void testGetTotalThreadAllocatedBytes()
+ throws Exception {
+
+ // baseline should be positive
+ Thread curThread = Thread.currentThread();
+ long cumulativeSize = mbean.getTotalThreadAllocatedBytes();
+ if (cumulativeSize <= 0) {
+ throw new RuntimeException(
+ "Invalid allocated bytes returned for " + curThread.getName() + " = " + cumulativeSize);
+ }
+
+ // start threads
+ done = false;
+ done1 = false;
+ for (int i = 0; i < NUM_THREADS; i++) {
+ threads[i] = new MyThread("MyThread-" + i);
+ threads[i].start();
+ }
+
+ // wait for threads to block after doing some allocation
+ waitUntilThreadsBlocked();
+
+ // check after threads are blocked
+ cumulativeSize = checkResult(curThread, cumulativeSize, mbean.getTotalThreadAllocatedBytes());
+
+ // let threads go to do some more allocation
+ synchronized (obj) {
+ done = true;
+ obj.notifyAll();
+ }
+
+ // wait for threads to get going again. we don't care if we
+ // catch them in mid-execution or if some of them haven't
+ // restarted after we're done sleeping.
+ goSleep(400);
+
+ System.out.println("Done sleeping");
+
+ // check while threads are running
+ cumulativeSize = checkResult(curThread, cumulativeSize, mbean.getTotalThreadAllocatedBytes());
+
+ // let threads exit
+ synchronized (obj) {
+ done1 = true;
+ obj.notifyAll();
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ try {
+ threads[i].join();
+ } catch (InterruptedException e) {
+ reportUnexpected(e, "during join");
+ break;
+ }
+ }
+
+ // check after threads exit
+ checkResult(curThread, cumulativeSize, mbean.getTotalThreadAllocatedBytes());
+ }
+
+ private static void ensureValidSize(Thread curThread, long size) {
// implementation could have started measurement when
// measurement was enabled, in which case size can be 0
if (size < 0) {
throw new RuntimeException(
- "Invalid allocated bytes returned = " + size);
+ "Invalid allocated bytes returned for thread " +
+ curThread.getName() + " = " + size);
}
}
- private static void checkResult(Thread curThread,
- long prev_size, long curr_size) {
- if (curr_size < prev_size) {
- throw new RuntimeException("Allocated bytes " + curr_size +
- " expected >= " + prev_size);
- }
+ private static long checkResult(Thread curThread,
+ long prevSize, long currSize) {
System.out.println(curThread.getName() +
- " Previous allocated bytes = " + prev_size +
- " Current allocated bytes = " + curr_size);
+ " Previous allocated bytes = " + prevSize +
+ " Current allocated bytes = " + currSize);
+ if (currSize < prevSize) {
+ throw new RuntimeException("TEST FAILED: " +
+ curThread.getName() +
+ " previous allocated bytes = " + prevSize +
+ " > current allocated bytes = " + currSize);
+ }
+ return currSize;
+ }
+
+ private static void reportUnexpected(Exception e, String when) {
+ System.out.println("Unexpected exception thrown " + when + ".");
+ e.printStackTrace(System.out);
+ testFailed = true;
}
private static void goSleep(long ms) throws Exception {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
throw e;
}
}
@@ -287,34 +375,23 @@ public void run() {
try {
obj.wait();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
+ reportUnexpected(e, "while !done");
break;
}
}
}
- long size1 = mbean.getThreadAllocatedBytes(getId());
+ long prevSize = mbean.getThreadAllocatedBytes(getId());
ThreadAllocatedMemory.doit();
- long size2 = mbean.getThreadAllocatedBytes(getId());
-
- System.out.println(getName() + ": " +
- "ThreadAllocatedBytes = " + size1 +
- " ThreadAllocatedBytes = " + size2);
-
- if (size1 > size2) {
- throw new RuntimeException(getName() +
- " ThreadAllocatedBytes = " + size1 +
- " > ThreadAllocatedBytes = " + size2);
- }
+ long currSize = mbean.getThreadAllocatedBytes(getId());
+ checkResult(this, prevSize, currSize);
synchronized (obj) {
while (!done1) {
try {
obj.wait();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
+ reportUnexpected(e, "while !done1");
break;
}
}
diff --git a/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemoryArray.java b/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemoryArray.java
index 980189098cb..d325d1dda66 100644
--- a/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemoryArray.java
+++ b/jdk/test/com/sun/management/ThreadMXBean/ThreadAllocatedMemoryArray.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, 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
@@ -47,7 +47,6 @@ public static void main(String[] argv)
return;
}
-
// start threads, wait for them to block
long[] ids = new long[NUM_THREADS];
@@ -59,7 +58,6 @@ public static void main(String[] argv)
waitUntilThreadBlocked();
-
// disable allocated memory measurement
if (mbean.isThreadAllocatedMemoryEnabled()) {
mbean.setThreadAllocatedMemoryEnabled(false);
@@ -117,19 +115,9 @@ public static void main(String[] argv)
// restarted after we're done sleeping.
goSleep(400);
- long[] sizes1 = mbean.getThreadAllocatedBytes(ids);
-
+ long[] afterSizes = mbean.getThreadAllocatedBytes(ids);
for (int i = 0; i < NUM_THREADS; i++) {
- long newSize = sizes1[i];
- if (sizes[i] > newSize) {
- throw new RuntimeException("TEST FAILED: " +
- threads[i].getName() +
- " previous allocated bytes = " + sizes[i] +
- " > current allocated bytes = " + newSize);
- }
- System.out.println(threads[i].getName() +
- " Previous allocated bytes = " + sizes[i] +
- " Current allocated bytes = " + newSize);
+ checkResult(threads[i], sizes[i], afterSizes[i]);
}
try {
@@ -147,7 +135,6 @@ public static void main(String[] argv)
"Caught expected IllegalArgumentException: " + e.getMessage());
}
-
// let threads exit
synchronized (obj) {
done1 = true;
@@ -158,9 +145,7 @@ public static void main(String[] argv)
try {
threads[i].join();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
- testFailed = true;
+ reportUnexpected(e, "during join");
break;
}
}
@@ -173,11 +158,30 @@ public static void main(String[] argv)
}
+ private static void checkResult(Thread curThread,
+ long prevSize, long currSize) {
+ System.out.println(curThread.getName() +
+ " Previous allocated bytes = " + prevSize +
+ " Current allocated bytes = " + currSize);
+ if (currSize < prevSize) {
+ throw new RuntimeException("TEST FAILED: " +
+ curThread.getName() +
+ " previous allocated bytes = " + prevSize +
+ " > current allocated bytes = " + currSize);
+
+ }
+ }
+
+ private static void reportUnexpected(Exception e, String when) {
+ System.out.println("Unexpected exception thrown " + when + ".");
+ e.printStackTrace(System.out);
+ testFailed = true;
+ }
+
private static void goSleep(long ms) throws Exception {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
throw e;
}
}
@@ -221,9 +225,7 @@ public void run() {
try {
obj.wait();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
- testFailed = true;
+ reportUnexpected(e, "while !done");
break;
}
}
@@ -236,9 +238,7 @@ public void run() {
try {
obj.wait();
} catch (InterruptedException e) {
- System.out.println("Unexpected exception is thrown.");
- e.printStackTrace(System.out);
- testFailed = true;
+ reportUnexpected(e, "while !done");
break;
}
}
diff --git a/jdk/test/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html b/jdk/test/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html
index 9b8277d1d16..d1d92a0ac2e 100644
--- a/jdk/test/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html
+++ b/jdk/test/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html
@@ -1,5 +1,5 @@