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 @@