mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-15 17:30:24 +00:00
Merge branch 'master' of https://github.com/openjdk/jdk into fix/vh-adapt-cache
This commit is contained in:
commit
fa80b4ebf7
@ -38,7 +38,7 @@
|
||||
# directory.
|
||||
# - open a terminal program and run these commands:
|
||||
# cd "${JDK_CHECKOUT}"/src/jdk.compiler/share/data/symbols
|
||||
# bash ../../../../../make/scripts/generate-symbol-data.sh "${JDK_N_INSTALL}"
|
||||
# bash ../../../../../bin/generate-symbol-data.sh "${JDK_N_INSTALL}"
|
||||
# - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols
|
||||
# directory, updating all registration necessary. If the goal was to update the data, and there are no
|
||||
# new or changed files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script,
|
||||
|
||||
@ -65,4 +65,4 @@ to be updated for a particular release.
|
||||
* `test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java`
|
||||
update annotation processor extended by `javac` tests to cover the new source version
|
||||
* `test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out` and `test/langtools/tools/javac/preview/classReaderTest/Client.preview.out`: update expected messages for preview errors and warnings
|
||||
|
||||
* `test/langtools/tools/javac/versions/Versions.java`: add new source version to the set of valid sources and add new enum constant for the new class file version.
|
||||
|
||||
@ -79,7 +79,7 @@ TOOL_GENERATEEXTRAPROPERTIES = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_too
|
||||
build.tools.generateextraproperties.GenerateExtraProperties
|
||||
|
||||
TOOL_GENERATECASEFOLDING = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
build.tools.generatecharacter.CaseFolding
|
||||
build.tools.generatecharacter.GenerateCaseFolding
|
||||
|
||||
TOOL_MAKEZIPREPRODUCIBLE = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
build.tools.makezipreproducible.MakeZipReproducible
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package build.tools.generatecharacter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CaseFolding {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (args.length != 3) {
|
||||
System.err.println("Usage: java CaseFolding TemplateFile CaseFolding.txt CaseFolding.java");
|
||||
System.exit(1);
|
||||
}
|
||||
var templateFile = Paths.get(args[0]);
|
||||
var caseFoldingTxt = Paths.get(args[1]);
|
||||
var genSrcFile = Paths.get(args[2]);
|
||||
var supportedTypes = "^.*; [CTS]; .*$";
|
||||
var caseFoldingEntries = Files.lines(caseFoldingTxt)
|
||||
.filter(line -> !line.startsWith("#") && line.matches(supportedTypes))
|
||||
.map(line -> {
|
||||
String[] cols = line.split("; ");
|
||||
return new String[] {cols[0], cols[1], cols[2]};
|
||||
})
|
||||
.filter(cols -> {
|
||||
// the folding case doesn't map back to the original char.
|
||||
var cp1 = Integer.parseInt(cols[0], 16);
|
||||
var cp2 = Integer.parseInt(cols[2], 16);
|
||||
return Character.toUpperCase(cp2) != cp1 && Character.toLowerCase(cp2) != cp1;
|
||||
})
|
||||
.map(cols -> String.format(" entry(0x%s, 0x%s)", cols[0], cols[2]))
|
||||
.collect(Collectors.joining(",\n", "", ""));
|
||||
|
||||
// hack, hack, hack! the logic does not pick 0131. just add manually to support 'I's.
|
||||
// 0049; T; 0131; # LATIN CAPITAL LETTER I
|
||||
final String T_0x0131_0x49 = String.format(" entry(0x%04x, 0x%04x),\n", 0x0131, 0x49);
|
||||
|
||||
// Generate .java file
|
||||
Files.write(
|
||||
genSrcFile,
|
||||
Files.lines(templateFile)
|
||||
.map(line -> line.contains("%%%Entries") ? T_0x0131_0x49 + caseFoldingEntries : line)
|
||||
.collect(Collectors.toList()),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.generatecharacter;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class GenerateCaseFolding {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (args.length != 3) {
|
||||
System.err.println("Usage: java GenerateCaseFolding TemplateFile CaseFolding.txt CaseFolding.java");
|
||||
System.exit(1);
|
||||
}
|
||||
var templateFile = Paths.get(args[0]);
|
||||
var caseFoldingTxt = Paths.get(args[1]);
|
||||
var genSrcFile = Paths.get(args[2]);
|
||||
|
||||
// java.lang
|
||||
var supportedTypes = "^.*; [CF]; .*$"; // full/1:M case folding
|
||||
String[][] caseFoldings = Files.lines(caseFoldingTxt)
|
||||
.filter(line -> !line.startsWith("#") && line.matches(supportedTypes))
|
||||
.map(line -> {
|
||||
var fields = line.split("; ");
|
||||
var cp = fields[0];
|
||||
fields = fields[2].trim().split(" ");
|
||||
var folding = new String[fields.length + 1];
|
||||
folding[0] = cp;
|
||||
System.arraycopy(fields, 0, folding, 1, fields.length);
|
||||
return folding;
|
||||
})
|
||||
.toArray(size -> new String[size][]);
|
||||
|
||||
// util.regex
|
||||
var expandedSupportedTypes = "^.*; [CTS]; .*$";
|
||||
var expanded_caseFoldingEntries = Files.lines(caseFoldingTxt)
|
||||
.filter(line -> !line.startsWith("#") && line.matches(expandedSupportedTypes))
|
||||
.map(line -> {
|
||||
String[] cols = line.split("; ");
|
||||
return new String[]{cols[0], cols[1], cols[2]};
|
||||
})
|
||||
.filter(cols -> {
|
||||
// the folding case doesn't map back to the original char.
|
||||
var cp1 = Integer.parseInt(cols[0], 16);
|
||||
var cp2 = Integer.parseInt(cols[2], 16);
|
||||
return Character.toUpperCase(cp2) != cp1 && Character.toLowerCase(cp2) != cp1;
|
||||
})
|
||||
.map(cols -> String.format(" entry(0x%s, 0x%s)", cols[0], cols[2]))
|
||||
.collect(Collectors.joining(",\n", "", ""));
|
||||
|
||||
// hack, hack, hack! the logic does not pick 0131. just add manually to support 'I's.
|
||||
// 0049; T; 0131; # LATIN CAPITAL LETTER I
|
||||
final String T_0x0131_0x49 = String.format(" entry(0x%04x, 0x%04x),\n", 0x0131, 0x49);
|
||||
|
||||
Files.write(
|
||||
genSrcFile,
|
||||
Files.lines(templateFile)
|
||||
.map(line -> line.contains("%%%Entries") ? genFoldingEntries(caseFoldings) : line)
|
||||
.map(line -> line.contains("%%%Expanded_Case_Map_Entries") ? T_0x0131_0x49 + expanded_caseFoldingEntries : line)
|
||||
.collect(Collectors.toList()),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
}
|
||||
|
||||
private static long foldingToLong(String[] folding) {
|
||||
int cp = Integer.parseInt(folding[0], 16);
|
||||
long value = (long)Integer.parseInt(folding[1], 16);
|
||||
if (!Character.isSupplementaryCodePoint(cp) && folding.length != 2) {
|
||||
var shift = 16;
|
||||
for (int j = 2; j < folding.length; j++) {
|
||||
value |= (long)Integer.parseInt(folding[j], 16) << shift;
|
||||
shift <<= 1;
|
||||
}
|
||||
value = value | (long) (folding.length - 1) << 48;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String genFoldingEntries(String[][] foldings) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(" private static final int[] CASE_FOLDING_CPS = {\n");
|
||||
int width = 10;
|
||||
for (int i = 0; i < foldings.length; i++) {
|
||||
if (i % width == 0)
|
||||
sb.append(" ");
|
||||
sb.append(String.format("0X%s", foldings[i][0]));
|
||||
if (i < foldings.length - 1)
|
||||
sb.append(", ");
|
||||
if (i % width == width - 1 || i == foldings.length - 1)
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(" };\n\n");
|
||||
|
||||
sb.append(" private static final long[] CASE_FOLDING_VALUES = {\n");
|
||||
width = 6;
|
||||
for (int i = 0; i < foldings.length; i++) {
|
||||
if (i % width == 0)
|
||||
sb.append(" "); // indent
|
||||
sb.append(String.format("0x%013xL", foldingToLong(foldings[i])));
|
||||
if (i < foldings.length - 1)
|
||||
sb.append(", ");
|
||||
if (i % width == width - 1 || i == foldings.length - 1) {
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
sb.append(" };\n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -120,3 +120,25 @@ $(INTPOLY_GEN_DONE): $(INTPLOY_HEADER) $(BUILD_TOOLS_JDK)
|
||||
TARGETS += $(INTPOLY_GEN_DONE)
|
||||
|
||||
################################################################################
|
||||
|
||||
RELEASE_FILE_TEMPLATE := $(TOPDIR)/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template
|
||||
RELEASE_FILE_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/jdk/internal/misc/resources/release.txt
|
||||
|
||||
RELEASE_FILE_VARDEPS := $(COMPANY_NAME) $(VERSION_STRING) $(VERSION_DATE)
|
||||
RELEASE_FILE_VARDEPS_FILE := $(call DependOnVariable, RELEASE_FILE_VARDEPS, \
|
||||
$(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/jlink_release_txt.vardeps)
|
||||
|
||||
$(eval $(call SetupTextFileProcessing, BUILD_RELEASE_FILE, \
|
||||
SOURCE_FILES := $(RELEASE_FILE_TEMPLATE), \
|
||||
OUTPUT_FILE := $(RELEASE_FILE_TARGET), \
|
||||
REPLACEMENTS := \
|
||||
@@COMPANY_NAME@@ => $(COMPANY_NAME) ; \
|
||||
@@VERSION_STRING@@ => $(VERSION_STRING) ; \
|
||||
@@VERSION_DATE@@ => $(VERSION_DATE) , \
|
||||
))
|
||||
|
||||
$(BUILD_RELEASE_FILE): $(RELEASE_FILE_VARDEPS_FILE)
|
||||
|
||||
TARGETS += $(BUILD_RELEASE_FILE)
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
DOCLINT += -Xdoclint:all/protected \
|
||||
'-Xdoclint/package:java.*,javax.*'
|
||||
JAVAC_FLAGS += -XDstringConcat=inline
|
||||
COPY += .icu .dat .spp .nrm content-types.properties \
|
||||
COPY += .icu .dat .spp .nrm .txt content-types.properties \
|
||||
hijrah-config-Hijrah-umalqura_islamic-umalqura.properties
|
||||
CLEAN += intrinsic.properties
|
||||
|
||||
|
||||
@ -72,5 +72,22 @@ TARGETS += $(GENSRC_CHARACTERDATA)
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
GENSRC_STRINGCASEFOLDING := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/lang/CaseFolding.java
|
||||
|
||||
STRINGCASEFOLDING_TEMPLATE := $(MODULE_SRC)/share/classes/jdk/internal/lang/CaseFolding.java.template
|
||||
CASEFOLDINGTXT := $(MODULE_SRC)/share/data/unicodedata/CaseFolding.txt
|
||||
|
||||
$(GENSRC_STRINGCASEFOLDING): $(BUILD_TOOLS_JDK) $(STRINGCASEFOLDING_TEMPLATE) $(CASEFOLDINGTXT)
|
||||
$(call LogInfo, Generating $@)
|
||||
$(call MakeTargetDir)
|
||||
$(TOOL_GENERATECASEFOLDING) \
|
||||
$(STRINGCASEFOLDING_TEMPLATE) \
|
||||
$(CASEFOLDINGTXT) \
|
||||
$(GENSRC_STRINGCASEFOLDING)
|
||||
|
||||
TARGETS += $(GENSRC_STRINGCASEFOLDING)
|
||||
|
||||
|
||||
endif # include guard
|
||||
include MakeIncludeEnd.gmk
|
||||
|
||||
@ -50,22 +50,5 @@ TARGETS += $(GENSRC_INDICCONJUNCTBREAK)
|
||||
|
||||
################################################################################
|
||||
|
||||
GENSRC_CASEFOLDING := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/util/regex/CaseFolding.java
|
||||
|
||||
CASEFOLDINGTEMP := $(MODULE_SRC)/share/classes/jdk/internal/util/regex/CaseFolding.java.template
|
||||
CASEFOLDINGTXT := $(MODULE_SRC)/share/data/unicodedata/CaseFolding.txt
|
||||
|
||||
$(GENSRC_CASEFOLDING): $(BUILD_TOOLS_JDK) $(CASEFOLDINGTEMP) $(CASEFOLDINGTXT)
|
||||
$(call LogInfo, Generating $@)
|
||||
$(call MakeTargetDir)
|
||||
$(TOOL_GENERATECASEFOLDING) \
|
||||
$(CASEFOLDINGTEMP) \
|
||||
$(CASEFOLDINGTXT) \
|
||||
$(GENSRC_CASEFOLDING)
|
||||
|
||||
TARGETS += $(GENSRC_CASEFOLDING)
|
||||
|
||||
################################################################################
|
||||
|
||||
endif # include guard
|
||||
include MakeIncludeEnd.gmk
|
||||
|
||||
@ -2879,7 +2879,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
//
|
||||
address generate_aescrypt_encryptBlock() {
|
||||
__ align(CodeEntryAlignment);
|
||||
@ -2912,7 +2912,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKd (key) in little endian int array
|
||||
//
|
||||
address generate_aescrypt_decryptBlock() {
|
||||
assert(UseAES, "need AES cryptographic extension support");
|
||||
@ -2946,7 +2946,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
// c_rarg3 - r vector byte array address
|
||||
// c_rarg4 - input length
|
||||
//
|
||||
@ -3051,7 +3051,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKd (key) in little endian int array
|
||||
// c_rarg3 - r vector byte array address
|
||||
// c_rarg4 - input length
|
||||
//
|
||||
@ -3178,7 +3178,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
// c_rarg3 - counter vector byte array address
|
||||
// c_rarg4 - input length
|
||||
// c_rarg5 - saved encryptedCounter start
|
||||
|
||||
@ -2956,7 +2956,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Arguments for generated stub:
|
||||
// R3_ARG1 - source byte array address
|
||||
// R4_ARG2 - destination byte array address
|
||||
// R5_ARG3 - K (key) in little endian int array
|
||||
// R5_ARG3 - sessionKe (key) in little endian int array
|
||||
address generate_aescrypt_decryptBlock() {
|
||||
assert(UseAES, "need AES instructions and misaligned SSE support");
|
||||
StubId stub_id = StubId::stubgen_aescrypt_decryptBlock_id;
|
||||
|
||||
@ -2463,7 +2463,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
//
|
||||
address generate_aescrypt_encryptBlock() {
|
||||
assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support");
|
||||
@ -2542,7 +2542,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
//
|
||||
address generate_aescrypt_decryptBlock() {
|
||||
assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support");
|
||||
|
||||
@ -480,7 +480,7 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
// c_rarg3 - counter vector byte array address
|
||||
// Linux
|
||||
// c_rarg4 - input length
|
||||
@ -1063,7 +1063,7 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
//
|
||||
address StubGenerator::generate_aescrypt_encryptBlock() {
|
||||
assert(UseAES, "need AES instructions and misaligned SSE support");
|
||||
@ -1158,7 +1158,7 @@ address StubGenerator::generate_aescrypt_encryptBlock() {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKd (key) in little endian int array
|
||||
//
|
||||
address StubGenerator::generate_aescrypt_decryptBlock() {
|
||||
assert(UseAES, "need AES instructions and misaligned SSE support");
|
||||
@ -1255,7 +1255,7 @@ address StubGenerator::generate_aescrypt_decryptBlock() {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKe (key) in little endian int array
|
||||
// c_rarg3 - r vector byte array address
|
||||
// c_rarg4 - input length
|
||||
//
|
||||
@ -1407,7 +1407,7 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() {
|
||||
// Inputs:
|
||||
// c_rarg0 - source byte array address
|
||||
// c_rarg1 - destination byte array address
|
||||
// c_rarg2 - K (key) in little endian int array
|
||||
// c_rarg2 - sessionKd (key) in little endian int array
|
||||
// c_rarg3 - r vector byte array address
|
||||
// c_rarg4 - input length
|
||||
//
|
||||
|
||||
@ -50,7 +50,14 @@ ProcSmapsParser::~ProcSmapsParser() {
|
||||
|
||||
bool ProcSmapsParser::read_line() {
|
||||
_line[0] = '\0';
|
||||
return ::fgets(_line, _linelen, _f) != nullptr;
|
||||
|
||||
if (::fgets(_line, _linelen, _f) == nullptr) {
|
||||
// On error or EOF, ensure deterministic empty buffer
|
||||
_line[0] = '\0';
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcSmapsParser::is_header_line() {
|
||||
@ -101,8 +108,6 @@ void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) {
|
||||
}
|
||||
}
|
||||
|
||||
// Starts or continues parsing. Returns true on success,
|
||||
// false on EOF or on error.
|
||||
bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) {
|
||||
|
||||
// Information about a single mapping reaches across several lines.
|
||||
@ -117,15 +122,13 @@ bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) {
|
||||
assert(is_header_line(), "Not a header line: \"%s\".", _line);
|
||||
scan_header_line(out);
|
||||
|
||||
// Now read until we encounter the next header line or EOF or an error.
|
||||
bool ok = false, stop = false;
|
||||
do {
|
||||
ok = read_line();
|
||||
stop = !ok || is_header_line();
|
||||
if (!stop) {
|
||||
scan_additional_line(out);
|
||||
while (true) {
|
||||
bool ok = read_line();
|
||||
if (!ok || is_header_line()) {
|
||||
break; // EOF or next header
|
||||
}
|
||||
} while (!stop);
|
||||
scan_additional_line(out);
|
||||
}
|
||||
|
||||
return ok;
|
||||
return true; // always return true if a mapping was parsed
|
||||
}
|
||||
|
||||
@ -84,8 +84,7 @@ public:
|
||||
ProcSmapsParser(FILE* f);
|
||||
~ProcSmapsParser();
|
||||
|
||||
// Starts or continues parsing. Returns true on success,
|
||||
// false on EOF or on error.
|
||||
// Starts or continues parsing. Returns true iff a mapping was parsed.
|
||||
bool parse_next(ProcSmapsInfo& out);
|
||||
};
|
||||
|
||||
|
||||
@ -50,11 +50,9 @@ double SharedRuntime::fmod_winx64(double x, double y)
|
||||
hx ^= sx; /* |x| */
|
||||
hy &= 0x7fffffff; /* |y| */
|
||||
|
||||
#pragma warning( disable : 4146 )
|
||||
/* purge off exception values */
|
||||
if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */
|
||||
((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */
|
||||
#pragma warning( default : 4146 )
|
||||
((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */
|
||||
return (x*y) / (x*y);
|
||||
if (hx <= hy) {
|
||||
if ((hx<hy) || (lx<ly)) return x; /* |x|<|y| return x */
|
||||
|
||||
@ -77,10 +77,11 @@ void G1Arguments::initialize_alignments() {
|
||||
}
|
||||
|
||||
size_t G1Arguments::conservative_max_heap_alignment() {
|
||||
if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
|
||||
return G1HeapRegion::max_ergonomics_size();
|
||||
}
|
||||
return G1HeapRegion::max_region_size();
|
||||
const size_t region_size = FLAG_IS_DEFAULT(G1HeapRegionSize)
|
||||
? G1HeapRegion::max_ergonomics_size()
|
||||
: G1HeapRegion::max_region_size();
|
||||
|
||||
return calculate_heap_alignment(region_size);
|
||||
}
|
||||
|
||||
void G1Arguments::initialize_verification_types() {
|
||||
|
||||
@ -307,9 +307,13 @@ HeapWord* ParallelScavengeHeap::mem_allocate_cas_noexpand(size_t size, bool is_t
|
||||
|
||||
HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) {
|
||||
for (uint loop_count = 0; /* empty */; ++loop_count) {
|
||||
HeapWord* result = mem_allocate_cas_noexpand(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
HeapWord* result;
|
||||
{
|
||||
ConditionalMutexLocker locker(Heap_lock, !is_init_completed());
|
||||
result = mem_allocate_cas_noexpand(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Read total_collections() under the lock so that multiple
|
||||
@ -326,10 +330,15 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) {
|
||||
}
|
||||
|
||||
if (!is_init_completed()) {
|
||||
// Can't do GC; try heap expansion to satisfy the request.
|
||||
result = expand_heap_and_allocate(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
// Double checked locking, this ensure that is_init_completed() does not
|
||||
// transition while expanding the heap.
|
||||
MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag);
|
||||
if (!is_init_completed()) {
|
||||
// Can't do GC; try heap expansion to satisfy the request.
|
||||
result = expand_heap_and_allocate(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -304,9 +304,12 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) {
|
||||
HeapWord* result = nullptr;
|
||||
|
||||
for (uint try_count = 1; /* break */; try_count++) {
|
||||
result = mem_allocate_cas_noexpand(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
break;
|
||||
{
|
||||
ConditionalMutexLocker locker(Heap_lock, !is_init_completed());
|
||||
result = mem_allocate_cas_noexpand(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint gc_count_before; // Read inside the Heap_lock locked region.
|
||||
{
|
||||
@ -320,10 +323,15 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) {
|
||||
}
|
||||
|
||||
if (!is_init_completed()) {
|
||||
// Can't do GC; try heap expansion to satisfy the request.
|
||||
result = expand_heap_and_allocate(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
// Double checked locking, this ensure that is_init_completed() does not
|
||||
// transition while expanding the heap.
|
||||
MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag);
|
||||
if (!is_init_completed()) {
|
||||
// Can't do GC; try heap expansion to satisfy the request.
|
||||
result = expand_heap_and_allocate(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -326,7 +326,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) {
|
||||
|
||||
// First, cut the simple case of fallthrough region when NONE of
|
||||
// region's phis references itself directly or through a data node.
|
||||
if (is_possible_unsafe_loop(phase)) {
|
||||
if (is_possible_unsafe_loop()) {
|
||||
// If we have a possible unsafe loop, check if the region node is actually unreachable from root.
|
||||
if (is_unreachable_from_root(phase)) {
|
||||
_is_unreachable_region = true;
|
||||
@ -336,7 +336,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RegionNode::is_possible_unsafe_loop(const PhaseGVN* phase) const {
|
||||
bool RegionNode::is_possible_unsafe_loop() const {
|
||||
uint max = outcnt();
|
||||
uint i;
|
||||
for (i = 0; i < max; i++) {
|
||||
@ -634,8 +634,8 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
} else if (can_reshape && cnt == 1) {
|
||||
// Is it dead loop?
|
||||
// If it is LoopNopde it had 2 (+1 itself) inputs and
|
||||
// one of them was cut. The loop is dead if it was EntryContol.
|
||||
// If it is LoopNode it had 2 (+1 itself) inputs and
|
||||
// one of them was cut. The loop is dead if it was EntryControl.
|
||||
// Loop node may have only one input because entry path
|
||||
// is removed in PhaseIdealLoop::Dominators().
|
||||
assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs");
|
||||
@ -1392,7 +1392,7 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) {
|
||||
}
|
||||
assert(is_diamond_phi() > 0, "sanity");
|
||||
assert(req() == 3, "same as region");
|
||||
const Node* region = in(0);
|
||||
RegionNode* region = in(0)->as_Region();
|
||||
for (uint i = 1; i < 3; i++) {
|
||||
Node* phi_input = in(i);
|
||||
if (phi_input != nullptr && phi_input->is_MergeMem() && region->in(i)->outcnt() == 1) {
|
||||
@ -1400,8 +1400,9 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) {
|
||||
MergeMemNode* merge_mem = phi_input->as_MergeMem();
|
||||
uint j = 3 - i;
|
||||
Node* other_phi_input = in(j);
|
||||
if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory()) {
|
||||
if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory() && !is_data_loop(region, phi_input, igvn)) {
|
||||
// merge_mem is a successor memory to other_phi_input, and is not pinned inside the diamond, so push it out.
|
||||
// Only proceed if the transformation doesn't create a data loop
|
||||
// This will allow the diamond to collapse completely if there are no other phis left.
|
||||
igvn->replace_node(this, merge_mem);
|
||||
return true;
|
||||
|
||||
@ -84,7 +84,7 @@ private:
|
||||
bool _is_unreachable_region;
|
||||
LoopStatus _loop_status;
|
||||
|
||||
bool is_possible_unsafe_loop(const PhaseGVN* phase) const;
|
||||
bool is_possible_unsafe_loop() const;
|
||||
bool is_unreachable_from_root(const PhaseGVN* phase) const;
|
||||
public:
|
||||
// Node layout (parallels PhiNode):
|
||||
|
||||
@ -1059,14 +1059,19 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
|
||||
assert(!stopped(), "you should return if you finish the chain");
|
||||
|
||||
// Oops, need to call into the VM to resolve the klasses at runtime.
|
||||
// Note: This call must not deoptimize, since it is not a real at this bci!
|
||||
kill_dead_locals();
|
||||
|
||||
make_runtime_call(RC_NO_LEAF | RC_MUST_THROW,
|
||||
OptoRuntime::rethrow_Type(),
|
||||
OptoRuntime::rethrow_stub(),
|
||||
nullptr, nullptr,
|
||||
ex_node);
|
||||
{ PreserveReexecuteState preexecs(this);
|
||||
// When throwing an exception, set the reexecute flag for deoptimization.
|
||||
// This is mostly needed to pass -XX:+VerifyStack sanity checks.
|
||||
jvms()->set_should_reexecute(true);
|
||||
|
||||
make_runtime_call(RC_NO_LEAF | RC_MUST_THROW,
|
||||
OptoRuntime::rethrow_Type(),
|
||||
OptoRuntime::rethrow_stub(),
|
||||
nullptr, nullptr,
|
||||
ex_node);
|
||||
}
|
||||
|
||||
// Rethrow is a pure call, no side effects, only a result.
|
||||
// The result cannot be allocated, so we use I_O
|
||||
|
||||
@ -7173,6 +7173,7 @@ Node * LibraryCallKit::field_address_from_object(Node * fromObj, const char * fi
|
||||
bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) {
|
||||
address stubAddr = nullptr;
|
||||
const char *stubName;
|
||||
bool is_decrypt = false;
|
||||
assert(UseAES, "need AES instruction support");
|
||||
|
||||
switch(id) {
|
||||
@ -7183,6 +7184,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_aescrypt_decryptBlock:
|
||||
stubAddr = StubRoutines::aescrypt_decryptBlock();
|
||||
stubName = "aescrypt_decryptBlock";
|
||||
is_decrypt = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -7216,7 +7218,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) {
|
||||
|
||||
// now need to get the start of its expanded key array
|
||||
// this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt);
|
||||
if (k_start == nullptr) return false;
|
||||
|
||||
// Call the stub.
|
||||
@ -7231,7 +7233,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) {
|
||||
bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) {
|
||||
address stubAddr = nullptr;
|
||||
const char *stubName = nullptr;
|
||||
|
||||
bool is_decrypt = false;
|
||||
assert(UseAES, "need AES instruction support");
|
||||
|
||||
switch(id) {
|
||||
@ -7242,6 +7244,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
|
||||
stubAddr = StubRoutines::cipherBlockChaining_decryptAESCrypt();
|
||||
stubName = "cipherBlockChaining_decryptAESCrypt";
|
||||
is_decrypt = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -7295,7 +7298,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) {
|
||||
aescrypt_object = _gvn.transform(aescrypt_object);
|
||||
|
||||
// we need to get the start of the aescrypt_object's expanded key array
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt);
|
||||
if (k_start == nullptr) return false;
|
||||
|
||||
// similarly, get the start address of the r vector
|
||||
@ -7319,7 +7322,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) {
|
||||
bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) {
|
||||
address stubAddr = nullptr;
|
||||
const char *stubName = nullptr;
|
||||
|
||||
bool is_decrypt = false;
|
||||
assert(UseAES, "need AES instruction support");
|
||||
|
||||
switch (id) {
|
||||
@ -7330,6 +7333,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_electronicCodeBook_decryptAESCrypt:
|
||||
stubAddr = StubRoutines::electronicCodeBook_decryptAESCrypt();
|
||||
stubName = "electronicCodeBook_decryptAESCrypt";
|
||||
is_decrypt = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -7381,7 +7385,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) {
|
||||
aescrypt_object = _gvn.transform(aescrypt_object);
|
||||
|
||||
// we need to get the start of the aescrypt_object's expanded key array
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt);
|
||||
if (k_start == nullptr) return false;
|
||||
|
||||
// Call the stub, passing src_start, dest_start, k_start, r_start and src_len
|
||||
@ -7449,7 +7453,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) {
|
||||
Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype);
|
||||
aescrypt_object = _gvn.transform(aescrypt_object);
|
||||
// we need to get the start of the aescrypt_object's expanded key array
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, /* is_decrypt */ false);
|
||||
if (k_start == nullptr) return false;
|
||||
// similarly, get the start address of the r vector
|
||||
Node* obj_counter = load_field_from_object(counterMode_object, "counter", "[B");
|
||||
@ -7474,25 +7478,21 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) {
|
||||
}
|
||||
|
||||
//------------------------------get_key_start_from_aescrypt_object-----------------------
|
||||
Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) {
|
||||
#if defined(PPC64) || defined(S390) || defined(RISCV64)
|
||||
Node* LibraryCallKit::get_key_start_from_aescrypt_object(Node* aescrypt_object, bool is_decrypt) {
|
||||
// MixColumns for decryption can be reduced by preprocessing MixColumns with round keys.
|
||||
// Intel's extension is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns.
|
||||
// However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption.
|
||||
// The ppc64 and riscv64 stubs of encryption and decryption use the same round keys (sessionK[0]).
|
||||
Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I");
|
||||
assert (objSessionK != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt");
|
||||
if (objSessionK == nullptr) {
|
||||
return (Node *) nullptr;
|
||||
}
|
||||
Node* objAESCryptKey = load_array_element(objSessionK, intcon(0), TypeAryPtr::OOPS, /* set_ctrl */ true);
|
||||
// The following platform specific stubs of encryption and decryption use the same round keys.
|
||||
#if defined(PPC64) || defined(S390) || defined(RISCV64)
|
||||
bool use_decryption_key = false;
|
||||
#else
|
||||
Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I");
|
||||
#endif // PPC64
|
||||
assert (objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt");
|
||||
bool use_decryption_key = is_decrypt;
|
||||
#endif
|
||||
Node* objAESCryptKey = load_field_from_object(aescrypt_object, use_decryption_key ? "sessionKd" : "sessionKe", "[I");
|
||||
assert(objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt");
|
||||
if (objAESCryptKey == nullptr) return (Node *) nullptr;
|
||||
|
||||
// now have the array, need to get the start address of the K array
|
||||
// now have the array, need to get the start address of the selected key array
|
||||
Node* k_start = array_element_address(objAESCryptKey, intcon(0), T_INT);
|
||||
return k_start;
|
||||
}
|
||||
@ -8628,7 +8628,7 @@ bool LibraryCallKit::inline_galoisCounterMode_AESCrypt() {
|
||||
Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype);
|
||||
aescrypt_object = _gvn.transform(aescrypt_object);
|
||||
// we need to get the start of the aescrypt_object's expanded key array
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
|
||||
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, /* is_decrypt */ false);
|
||||
if (k_start == nullptr) return false;
|
||||
// similarly, get the start address of the r vector
|
||||
Node* cnt_start = array_element_address(counter, intcon(0), T_BYTE);
|
||||
|
||||
@ -338,7 +338,7 @@ class LibraryCallKit : public GraphKit {
|
||||
Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting);
|
||||
Node* inline_electronicCodeBook_AESCrypt_predicate(bool decrypting);
|
||||
Node* inline_counterMode_AESCrypt_predicate();
|
||||
Node* get_key_start_from_aescrypt_object(Node* aescrypt_object);
|
||||
Node* get_key_start_from_aescrypt_object(Node* aescrypt_object, bool is_decrypt);
|
||||
bool inline_ghash_processBlocks();
|
||||
bool inline_chacha20Block();
|
||||
bool inline_kyberNtt();
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
*/
|
||||
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "opto/c2_globals.hpp"
|
||||
#include "opto/compile.hpp"
|
||||
#include "opto/connode.hpp"
|
||||
#include "opto/convertnode.hpp"
|
||||
#include "opto/mulnode.hpp"
|
||||
@ -1145,7 +1147,14 @@ Node* LoadVectorMaskedNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
if (ty && ty->is_con()) {
|
||||
BasicType mask_bt = Matcher::vector_element_basic_type(in(3));
|
||||
int load_sz = type2aelembytes(mask_bt) * ty->get_con();
|
||||
assert(load_sz <= MaxVectorSize, "Unexpected load size");
|
||||
if (load_sz > MaxVectorSize) {
|
||||
// After loop opts, cast nodes are aggressively removed, if the input is then transformed
|
||||
// into a constant that is outside the range of the removed cast, we may encounter it here.
|
||||
// This should be a dead node then.
|
||||
assert(Compile::current()->post_loop_opts_phase(), "Unexpected load size");
|
||||
return phase->C->top();
|
||||
}
|
||||
|
||||
if (load_sz == MaxVectorSize) {
|
||||
Node* ctr = in(MemNode::Control);
|
||||
Node* mem = in(MemNode::Memory);
|
||||
@ -1164,7 +1173,14 @@ Node* StoreVectorMaskedNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
if (ty && ty->is_con()) {
|
||||
BasicType mask_bt = Matcher::vector_element_basic_type(in(4));
|
||||
int load_sz = type2aelembytes(mask_bt) * ty->get_con();
|
||||
assert(load_sz <= MaxVectorSize, "Unexpected store size");
|
||||
if (load_sz > MaxVectorSize) {
|
||||
// After loop opts, cast nodes are aggressively removed, if the input is then transformed
|
||||
// into a constant that is outside the range of the removed cast, we may encounter it here.
|
||||
// This should be a dead node then.
|
||||
assert(Compile::current()->post_loop_opts_phase(), "Unexpected store size");
|
||||
return phase->C->top();
|
||||
}
|
||||
|
||||
if (load_sz == MaxVectorSize) {
|
||||
Node* ctr = in(MemNode::Control);
|
||||
Node* mem = in(MemNode::Memory);
|
||||
|
||||
@ -40,38 +40,76 @@ void VTransformGraph::add_vtnode(VTransformNode* vtnode) {
|
||||
} \
|
||||
)
|
||||
|
||||
// This is similar to IGVN optimization. But we are a bit lazy, and don't care about
|
||||
// notification / worklist, since the list of nodes is rather small, and we don't
|
||||
// expect optimizations that trickle over the whole graph.
|
||||
void VTransformGraph::optimize(VTransform& vtransform) {
|
||||
TRACE_OPTIMIZE( tty->print_cr("\nVTransformGraph::optimize"); )
|
||||
|
||||
bool progress = true;
|
||||
DEBUG_ONLY(int pass_count = 0;)
|
||||
while (progress) {
|
||||
progress = false;
|
||||
assert(++pass_count < 10, "ensure we do not have endless loops");
|
||||
for (int i = 0; i < _vtnodes.length(); i++) {
|
||||
VTransformNode* vtn = _vtnodes.at(i);
|
||||
if (!vtn->is_alive()) { continue; }
|
||||
progress |= vtn->optimize(_vloop_analyzer, vtransform);
|
||||
|
||||
// Nodes that have no use any more are dead.
|
||||
if (vtn->out_strong_edges() == 0 &&
|
||||
// There are some exceptions:
|
||||
// 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive.
|
||||
// 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive.
|
||||
// 3. Outer node with strong inputs: is a use after the loop that we must keep alive.
|
||||
!(vtn->isa_PhiScalar() != nullptr ||
|
||||
vtn->is_load_or_store_in_loop() ||
|
||||
(vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) {
|
||||
vtn->mark_dead();
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
void VTransformOptimize::worklist_push(VTransformNode* vtn) {
|
||||
if (!_worklist_set.test_set(vtn->_idx)) {
|
||||
_worklist.push(vtn);
|
||||
}
|
||||
}
|
||||
|
||||
VTransformNode* VTransformOptimize::worklist_pop() {
|
||||
VTransformNode* vtn = _worklist.pop();
|
||||
_worklist_set.remove(vtn->_idx);
|
||||
return vtn;
|
||||
}
|
||||
|
||||
void VTransform::optimize() {
|
||||
NOT_PRODUCT( if (vloop().is_trace_optimization()) { tty->print_cr("\nVTransform::optimize"); } )
|
||||
ResourceMark rm;
|
||||
VTransformOptimize vtoptimize(_vloop_analyzer, *this);
|
||||
vtoptimize.optimize();
|
||||
}
|
||||
|
||||
void VTransformOptimize::optimize() {
|
||||
// Initialize: push all nodes to worklist.
|
||||
for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) {
|
||||
VTransformNode* vtn = _vtransform.graph().vtnodes().at(i);
|
||||
worklist_push(vtn);
|
||||
}
|
||||
|
||||
// We don't want to iterate too many times. We set some arbitrary limit,
|
||||
// just to catch infinite loops.
|
||||
DEBUG_ONLY( int allowed_steps = 100 * _worklist.length(); )
|
||||
|
||||
// Optimize iteratively.
|
||||
while (_worklist.is_nonempty()) {
|
||||
VTransformNode* vtn = worklist_pop();
|
||||
optimize_step(vtn);
|
||||
assert(--allowed_steps > 0, "no endless loop");
|
||||
}
|
||||
|
||||
DEBUG_ONLY( verify(); )
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void VTransformOptimize::verify() {
|
||||
for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) {
|
||||
VTransformNode* vtn = _vtransform.graph().vtnodes().at(i);
|
||||
assert(!optimize_step(vtn), "Missed optimization during VTransform::optimize for %s", vtn->name());
|
||||
assert(_worklist.is_empty(), "vtnode on worklist despite no progress for %s", vtn->name());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return true if (and only if) we made progress.
|
||||
bool VTransformOptimize::optimize_step(VTransformNode* vtn) {
|
||||
if (!vtn->is_alive()) { return false; }
|
||||
bool progress = vtn->optimize(*this);
|
||||
|
||||
// Nodes that have no use any more are dead.
|
||||
if (vtn->out_strong_edges() == 0 &&
|
||||
// There are some exceptions:
|
||||
// 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive.
|
||||
// 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive.
|
||||
// 3. Outer node with strong inputs: is a use after the loop that we must keep alive.
|
||||
!(vtn->isa_PhiScalar() != nullptr ||
|
||||
vtn->is_load_or_store_in_loop() ||
|
||||
(vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) {
|
||||
vtn->mark_dead(*this);
|
||||
return true;
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
// Compute a linearization of the graph. We do this with a reverse-post-order of a DFS.
|
||||
// This only works if the graph is a directed acyclic graph (DAG). The C2 graph, and
|
||||
// the VLoopDependencyGraph are both DAGs, but after introduction of vectors/packs, the
|
||||
@ -1141,8 +1179,8 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl
|
||||
return VTransformApplyResult::make_vector(vn);
|
||||
}
|
||||
|
||||
bool VTransformReductionVectorNode::optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) {
|
||||
return optimize_move_non_strict_order_reductions_out_of_loop(vloop_analyzer, vtransform);
|
||||
bool VTransformReductionVectorNode::optimize(VTransformOptimize& vtoptimize) {
|
||||
return optimize_move_non_strict_order_reductions_out_of_loop(vtoptimize);
|
||||
}
|
||||
|
||||
int VTransformReductionVectorNode::vector_reduction_opcode() const {
|
||||
@ -1213,7 +1251,7 @@ bool VTransformReductionVectorNode::requires_strict_order() const {
|
||||
// become profitable, since the expensive reduction node is moved
|
||||
// outside the loop, and instead cheaper element-wise vector accumulations
|
||||
// are performed inside the loop.
|
||||
bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform) {
|
||||
bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform) {
|
||||
// We have a phi with a single use.
|
||||
VTransformPhiScalarNode* phi = in_req(1)->isa_PhiScalar();
|
||||
if (phi == nullptr) {
|
||||
@ -1260,13 +1298,13 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou
|
||||
current_red->element_basic_type() != bt ||
|
||||
current_red->vector_length() != vlen) {
|
||||
TRACE_OPTIMIZE(
|
||||
tty->print(" Cannot move out of loop, other reduction node does not match:");
|
||||
tty->print(" Cannot move out of loop, other reduction node does not match: ");
|
||||
print();
|
||||
tty->print(" other: ");
|
||||
if (current_red != nullptr) {
|
||||
current_red->print();
|
||||
} else {
|
||||
tty->print("nullptr");
|
||||
tty->print_cr("nullptr");
|
||||
}
|
||||
)
|
||||
return false; // not compatible
|
||||
@ -1314,7 +1352,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou
|
||||
return true; // success
|
||||
}
|
||||
|
||||
bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) {
|
||||
bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize) {
|
||||
VTransform& vtransform = vtoptimize.vtransform();
|
||||
if (!optimize_move_non_strict_order_reductions_out_of_loop_preconditions(vtransform)) {
|
||||
return false;
|
||||
}
|
||||
@ -1328,7 +1367,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou
|
||||
const uint vlen = vector_length();
|
||||
const BasicType bt = element_basic_type();
|
||||
const int vopc = VectorNode::opcode(sopc, bt);
|
||||
PhaseIdealLoop* phase = vloop_analyzer.vloop().phase();
|
||||
PhaseIdealLoop* phase = vtoptimize.vloop_analyzer().vloop().phase();
|
||||
|
||||
// Create a vector of identity values.
|
||||
Node* identity = ReductionNode::make_identity_con_scalar(phase->igvn(), sopc, bt);
|
||||
@ -1341,6 +1380,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou
|
||||
// Look at old scalar phi.
|
||||
VTransformPhiScalarNode* phi_scalar = in_req(1)->isa_PhiScalar();
|
||||
PhiNode* old_phi = phi_scalar->node();
|
||||
vtoptimize.worklist_push(phi_scalar);
|
||||
VTransformNode* init = phi_scalar->in_req(1);
|
||||
|
||||
TRACE_OPTIMIZE(
|
||||
@ -1354,6 +1394,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou
|
||||
phi_vector->init_req(0, phi_scalar->in_req(0));
|
||||
phi_vector->init_req(1, vtn_identity_vector);
|
||||
// Note: backedge comes later
|
||||
vtoptimize.worklist_push(phi_vector);
|
||||
|
||||
// Traverse down the chain of reductions, and replace them with vector_accumulators.
|
||||
VTransformReductionVectorNode* first_red = this;
|
||||
@ -1365,6 +1406,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou
|
||||
VTransformVectorNode* vector_accumulator = new (vtransform.arena()) VTransformElementWiseVectorNode(vtransform, 3, current_red->properties(), vopc);
|
||||
vector_accumulator->init_req(1, current_vector_accumulator);
|
||||
vector_accumulator->init_req(2, vector_input);
|
||||
vtoptimize.worklist_push(current_red);
|
||||
vtoptimize.worklist_push(vector_accumulator);
|
||||
TRACE_OPTIMIZE(
|
||||
tty->print(" replace ");
|
||||
current_red->print();
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#ifndef SHARE_OPTO_VTRANSFORM_HPP
|
||||
#define SHARE_OPTO_VTRANSFORM_HPP
|
||||
|
||||
#include "libadt/vectset.hpp"
|
||||
#include "opto/node.hpp"
|
||||
#include "opto/vectorization.hpp"
|
||||
#include "opto/vectornode.hpp"
|
||||
@ -192,7 +193,6 @@ public:
|
||||
const GrowableArray<VTransformNode*>& vtnodes() const { return _vtnodes; }
|
||||
const GrowableArray<VTransformNode*>& get_schedule() const { return _schedule; }
|
||||
|
||||
void optimize(VTransform& vtransform);
|
||||
bool schedule();
|
||||
bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const;
|
||||
float cost_for_vector_loop() const;
|
||||
@ -257,7 +257,7 @@ public:
|
||||
DEBUG_ONLY( bool has_graph() const { return !_graph.is_empty(); } )
|
||||
VTransformGraph& graph() { return _graph; }
|
||||
|
||||
void optimize() { return _graph.optimize(*this); }
|
||||
void optimize();
|
||||
bool schedule() { return _graph.schedule(); }
|
||||
bool is_profitable() const;
|
||||
float cost_for_vector_loop() const { return _graph.cost_for_vector_loop(); }
|
||||
@ -291,6 +291,36 @@ private:
|
||||
void apply_vectorization() const;
|
||||
};
|
||||
|
||||
// We keep track of the worklist during optimizations.
|
||||
// The concept is somewhat parallel to IGVN: we keep on
|
||||
// optimizing vtnodes on the worklist, which may in turn
|
||||
// add more nodes to the list. We keep on optimizing until
|
||||
// no more nodes are on the worklist.
|
||||
class VTransformOptimize : public StackObj {
|
||||
private:
|
||||
const VLoopAnalyzer& _vloop_analyzer;
|
||||
VTransform& _vtransform;
|
||||
|
||||
GrowableArray<VTransformNode*> _worklist;
|
||||
VectorSet _worklist_set;
|
||||
|
||||
public:
|
||||
VTransformOptimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) :
|
||||
_vloop_analyzer(vloop_analyzer),
|
||||
_vtransform(vtransform) {}
|
||||
|
||||
const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; }
|
||||
VTransform& vtransform() { return _vtransform; }
|
||||
|
||||
void worklist_push(VTransformNode* vtn);
|
||||
void optimize();
|
||||
|
||||
private:
|
||||
VTransformNode* worklist_pop();
|
||||
bool optimize_step(VTransformNode* vtn);
|
||||
DEBUG_ONLY( void verify(); )
|
||||
};
|
||||
|
||||
// Keeps track of the state during "VTransform::apply"
|
||||
// -> keep track of the already transformed nodes and the memory state.
|
||||
class VTransformApplyState : public StackObj {
|
||||
@ -531,10 +561,15 @@ public:
|
||||
|
||||
bool is_alive() const { return _is_alive; }
|
||||
|
||||
void mark_dead() {
|
||||
void mark_dead(VTransformOptimize& vtoptimize) {
|
||||
_is_alive = false;
|
||||
// Remove all inputs
|
||||
// Remove all inputs, and put inputs on worklist in
|
||||
// case they are also dead.
|
||||
for (uint i = 0; i < req(); i++) {
|
||||
VTransformNode* in = in_req(i);
|
||||
if (in != nullptr) {
|
||||
vtoptimize.worklist_push(in);
|
||||
}
|
||||
set_req(i, nullptr);
|
||||
}
|
||||
}
|
||||
@ -558,7 +593,7 @@ public:
|
||||
virtual const VPointer& vpointer() const { ShouldNotReachHere(); }
|
||||
virtual bool is_loop_head_phi() const { return false; }
|
||||
|
||||
virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { return false; }
|
||||
virtual bool optimize(VTransformOptimize& vtoptimize) { return false; }
|
||||
|
||||
virtual float cost(const VLoopAnalyzer& vloop_analyzer) const = 0;
|
||||
|
||||
@ -868,7 +903,7 @@ public:
|
||||
VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) :
|
||||
VTransformVectorNode(vtransform, 3, properties) {}
|
||||
virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; }
|
||||
virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) override;
|
||||
virtual bool optimize(VTransformOptimize& vtoptimize) override;
|
||||
virtual float cost(const VLoopAnalyzer& vloop_analyzer) const override;
|
||||
virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override;
|
||||
NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };)
|
||||
@ -876,8 +911,8 @@ public:
|
||||
private:
|
||||
int vector_reduction_opcode() const;
|
||||
bool requires_strict_order() const;
|
||||
bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform);
|
||||
bool optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform);
|
||||
bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform);
|
||||
bool optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize);
|
||||
};
|
||||
|
||||
class VTransformPhiVectorNode : public VTransformVectorNode {
|
||||
|
||||
@ -1077,10 +1077,6 @@ JvmtiEventController::is_global_event(jvmtiEvent event_type) {
|
||||
void
|
||||
JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, oop thread_oop,
|
||||
jvmtiEvent event_type, bool enabled) {
|
||||
if (event_type == JVMTI_EVENT_OBJECT_FREE) {
|
||||
JvmtiEventControllerPrivate::flush_object_free_events(env);
|
||||
}
|
||||
|
||||
if (Threads::number_of_threads() == 0) {
|
||||
// during early VM start-up locks don't exist, but we are safely single threaded,
|
||||
// call the functionality without holding the JvmtiThreadState_lock.
|
||||
@ -1089,6 +1085,11 @@ JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, oo
|
||||
Thread* current = Thread::current();
|
||||
HandleMark hmi(current);
|
||||
Handle thread_oop_h = Handle(current, thread_oop);
|
||||
|
||||
if (event_type == JVMTI_EVENT_OBJECT_FREE) {
|
||||
JvmtiEventControllerPrivate::flush_object_free_events(env);
|
||||
}
|
||||
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
JvmtiEventControllerPrivate::set_user_enabled(env, thread, thread_oop_h, event_type, enabled);
|
||||
}
|
||||
@ -1238,4 +1239,4 @@ JvmtiEventController::vm_death() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -635,7 +635,6 @@ inline void AtomicAccess::dec(D volatile* dest, atomic_memory_order order) {
|
||||
STATIC_ASSERT(std::is_pointer<D>::value || std::is_integral<D>::value);
|
||||
using I = std::conditional_t<std::is_pointer<D>::value, ptrdiff_t, D>;
|
||||
// Assumes two's complement integer representation.
|
||||
#pragma warning(suppress: 4146)
|
||||
AtomicAccess::add(dest, I(-1), order);
|
||||
}
|
||||
|
||||
@ -652,7 +651,6 @@ inline D AtomicAccess::sub(D volatile* dest, I sub_value, atomic_memory_order or
|
||||
STATIC_ASSERT(sizeof(I) <= sizeof(AddendType));
|
||||
AddendType addend = sub_value;
|
||||
// Assumes two's complement integer representation.
|
||||
#pragma warning(suppress: 4146) // In case AddendType is not signed.
|
||||
return AtomicAccess::add(dest, -addend, order);
|
||||
}
|
||||
|
||||
|
||||
@ -54,11 +54,11 @@ final class AES_Crypt extends SymmetricCipher {
|
||||
private int rounds;
|
||||
private byte[] prevKey = null;
|
||||
|
||||
// Following two attributes are specific to Intrinsics where sessionK is
|
||||
// used for PPC64, S390, and RISCV64 architectures, whereas K is used for
|
||||
// everything else.
|
||||
private int[][] sessionK = null;
|
||||
private int[] K = null;
|
||||
// Following attributes are specific to Intrinsics, where sessionKe is the
|
||||
// unprocessed key that is also used for decryption on PPC64, S390 and
|
||||
// RISCV64 architectures. Other ones use sessionKd for decryption.
|
||||
private int[] sessionKe = null; // key for encryption
|
||||
private int[] sessionKd = null; // preprocessed key for decryption
|
||||
|
||||
// Round constant
|
||||
private static final int[] RCON = {
|
||||
@ -904,7 +904,6 @@ final class AES_Crypt extends SymmetricCipher {
|
||||
*/
|
||||
void init(boolean decrypting, String algorithm, byte[] key)
|
||||
throws InvalidKeyException {
|
||||
int decrypt = decrypting ? 1 : 0;
|
||||
|
||||
if (!algorithm.equalsIgnoreCase("AES")
|
||||
&& !algorithm.equalsIgnoreCase("Rijndael")) {
|
||||
@ -920,21 +919,25 @@ final class AES_Crypt extends SymmetricCipher {
|
||||
throw new InvalidKeyException("Invalid key length (" + key.length
|
||||
+ ").");
|
||||
}
|
||||
|
||||
if (!MessageDigest.isEqual(prevKey, key)) {
|
||||
if (sessionK == null) {
|
||||
sessionK = new int[2][];
|
||||
} else {
|
||||
Arrays.fill(sessionK[0], 0);
|
||||
Arrays.fill(sessionK[1], 0);
|
||||
if (sessionKe != null) {
|
||||
Arrays.fill(sessionKe, 0);
|
||||
}
|
||||
sessionKe = genRoundKeys(key, rounds);
|
||||
if (sessionKd != null) {
|
||||
Arrays.fill(sessionKd, 0);
|
||||
sessionKd = null;
|
||||
}
|
||||
sessionK[0] = genRoundKeys(key, rounds);
|
||||
sessionK[1] = genInvRoundKeys(sessionK[0], rounds);
|
||||
if (prevKey != null) {
|
||||
Arrays.fill(prevKey, (byte) 0);
|
||||
}
|
||||
prevKey = key.clone();
|
||||
}
|
||||
K = sessionK[decrypt];
|
||||
|
||||
if (decrypting && (sessionKd == null)) {
|
||||
sessionKd = genInvRoundKeys(sessionKe, rounds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1035,6 +1038,7 @@ final class AES_Crypt extends SymmetricCipher {
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
private void implEncryptBlock(byte[] p, int po, byte[] c, int co) {
|
||||
int[] K = sessionKe;
|
||||
int ti0, ti1, ti2, ti3;
|
||||
int a0, a1, a2, a3;
|
||||
int w = K.length - WB;
|
||||
@ -1213,6 +1217,7 @@ final class AES_Crypt extends SymmetricCipher {
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
private void implDecryptBlock(byte[] c, int co, byte[] p, int po) {
|
||||
int[] K = sessionKd;
|
||||
int ti0, ti1, ti2, ti3;
|
||||
int a0, a1, a2, a3;
|
||||
|
||||
|
||||
@ -117,9 +117,38 @@ import sun.nio.cs.UTF_8;
|
||||
* Unicode code points (i.e., characters), in addition to those for
|
||||
* dealing with Unicode code units (i.e., {@code char} values).
|
||||
*
|
||||
* <p>Unless otherwise noted, methods for comparing Strings do not take locale
|
||||
* into account. The {@link java.text.Collator} class provides methods for
|
||||
* finer-grain, locale-sensitive String comparison.
|
||||
* <p><b>String comparison and case-insensitive matching</b>
|
||||
*
|
||||
* <p>There are several related ways to compare {@code String} values; choose
|
||||
* the one whose semantics fit your purpose:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>Exact content equality</b> — {@link #equals(Object)} checks that two
|
||||
* strings contain the identical char sequence of UTF-16 code units. This is
|
||||
* a strict, case-sensitive comparison suitable for exact matching, hashing
|
||||
* and any situation that requires bit-for-bit stability.</li>
|
||||
*
|
||||
* <li><b>Simple case-insensitive equality</b> — {@link #equalsIgnoreCase(String)}
|
||||
* (and the corresponding {@link #compareToIgnoreCase(String)} and {@link #CASE_INSENSITIVE_ORDER})
|
||||
* performs a per-code-point, locale-independent comparison using
|
||||
* {@link Character#toUpperCase(int)} and {@link Character#toLowerCase(int)}.
|
||||
* It is convenient for many common case-insensitive checks.</li>
|
||||
*
|
||||
* <li><b>Unicode case-folded equivalence</b> — {@link #equalsFoldCase(String)}
|
||||
* (and the corresponding {@link #compareToFoldCase(String)} and {@link #UNICODE_CASEFOLD_ORDER})
|
||||
* implement the Unicode <em>{@index "full case folding"}</em> rules defined in
|
||||
* <a href="https://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt">Unicode CaseFolding.txt</a>.
|
||||
* Case folding is locale-independent and language-neutral and may map a single code
|
||||
* point to multiple code points (1:M mappings). For example, the German sharp
|
||||
* s ({@code U+00DF}) is folded to the sequence {@code "ss"}.
|
||||
* Use these methods when you need Unicode-compliant
|
||||
* <a href="https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790">
|
||||
* caseless matching</a>, searching, or ordering.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Unless otherwise noted, methods for comparing Strings do not take locale into
|
||||
* account. The {@link java.text.Collator} class provides methods for finer-grain,
|
||||
* locale-sensitive String comparison.
|
||||
*
|
||||
* @implNote The implementation of the string concatenation operator is left to
|
||||
* the discretion of a Java compiler, as long as the compiler ultimately conforms
|
||||
@ -2179,6 +2208,7 @@ public final class String
|
||||
* false} otherwise
|
||||
*
|
||||
* @see #equals(Object)
|
||||
* @see #equalsFoldCase(String)
|
||||
* @see #codePoints()
|
||||
*/
|
||||
public boolean equalsIgnoreCase(String anotherString) {
|
||||
@ -2188,6 +2218,57 @@ public final class String
|
||||
&& regionMatches(true, 0, anotherString, 0, length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code String} to another {@code String} for equality,
|
||||
* using <em>{@index "Unicode case folding"}</em>. Two strings are considered equal
|
||||
* by this method if their case-folded forms are identical.
|
||||
* <p>
|
||||
* Case folding is defined by the Unicode Standard in
|
||||
* <a href="https://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt">CaseFolding.txt</a>,
|
||||
* including 1:M mappings. For example, {@code "Fuß".equalsFoldCase("FUSS")}
|
||||
* returns {@code true}, since the character {@code U+00DF} (sharp s) folds
|
||||
* to {@code "ss"}.
|
||||
* <p>
|
||||
* Case folding is locale-independent and language-neutral, unlike
|
||||
* locale-sensitive transformations such as {@link #toLowerCase()} or
|
||||
* {@link #toUpperCase()}. It is intended for caseless matching,
|
||||
* searching, and indexing.
|
||||
*
|
||||
* @apiNote
|
||||
* This method is the Unicode-compliant alternative to
|
||||
* {@link #equalsIgnoreCase(String)}. It implements full case folding as
|
||||
* defined by the Unicode Standard, which may differ from the simpler
|
||||
* per-character mapping performed by {@code equalsIgnoreCase}.
|
||||
* For example:
|
||||
* {@snippet lang=java :
|
||||
* String a = "Fuß";
|
||||
* String b = "FUSS";
|
||||
* boolean equalsFoldCase = a.equalsFoldCase(b); // returns true
|
||||
* boolean equalsIgnoreCase = a.equalsIgnoreCase(b); // returns false
|
||||
* }
|
||||
*
|
||||
* @param anotherString
|
||||
* The {@code String} to compare this {@code String} against
|
||||
*
|
||||
* @return {@code true} if the given object is not {@code null} and represents
|
||||
* the same sequence of characters as this string under Unicode case
|
||||
* folding; {@code false} otherwise.
|
||||
*
|
||||
* @spec https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790 Unicode Caseless Matching
|
||||
* @see #compareToFoldCase(String)
|
||||
* @see #equalsIgnoreCase(String)
|
||||
* @since 26
|
||||
*/
|
||||
public boolean equalsFoldCase(String anotherString) {
|
||||
if (this == anotherString) {
|
||||
return true;
|
||||
}
|
||||
if (anotherString == null) {
|
||||
return false;
|
||||
}
|
||||
return UNICODE_CASEFOLD_ORDER.compare(this, anotherString) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two strings lexicographically.
|
||||
* The comparison is based on the Unicode value of each character in
|
||||
@ -2303,12 +2384,86 @@ public final class String
|
||||
* than this String, ignoring case considerations.
|
||||
* @see java.text.Collator
|
||||
* @see #codePoints()
|
||||
* @see #compareToFoldCase(String)
|
||||
* @since 1.2
|
||||
*/
|
||||
public int compareToIgnoreCase(String str) {
|
||||
return CASE_INSENSITIVE_ORDER.compare(this, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Comparator that orders {@code String} objects as by
|
||||
* {@link #compareToFoldCase(String) compareToFoldCase()}.
|
||||
*
|
||||
* @see #compareToFoldCase(String)
|
||||
* @since 26
|
||||
*/
|
||||
public static final Comparator<String> UNICODE_CASEFOLD_ORDER
|
||||
= new FoldCaseComparator();
|
||||
|
||||
private static class FoldCaseComparator implements Comparator<String> {
|
||||
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
byte[] v1 = s1.value;
|
||||
byte[] v2 = s2.value;
|
||||
if (s1.coder == s2.coder()) {
|
||||
return s1.coder == LATIN1 ? StringLatin1.compareToFC(v1, v2)
|
||||
: StringUTF16.compareToFC(v1, v2);
|
||||
}
|
||||
return s1.coder == LATIN1 ? StringLatin1.compareToFC_UTF16(v1, v2)
|
||||
: StringUTF16.compareToFC_Latin1(v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two strings lexicographically using <em>{@index "Unicode case folding"}</em>.
|
||||
* This method returns an integer whose sign is that of calling {@code compareTo}
|
||||
* on the Unicode case folded version of the strings. Unicode Case folding
|
||||
* eliminates differences in case according to the Unicode Standard, using the
|
||||
* mappings defined in
|
||||
* <a href="https://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt">CaseFolding.txt</a>,
|
||||
* including 1:M mappings, such as {@code"ß"} → {@code }"ss"}.
|
||||
* <p>
|
||||
* Case folding is a locale-independent, language-neutral form of case mapping,
|
||||
* primarily intended for caseless matching. Unlike {@link #compareToIgnoreCase(String)},
|
||||
* which applies a simpler locale-insensitive uppercase mapping. This method
|
||||
* follows the Unicode <em>{@index "full"}</em> case folding, providing stable and
|
||||
* consistent results across all environments.
|
||||
* <p>
|
||||
* Note that this method does <em>not</em> take locale into account, and may
|
||||
* produce results that differ from locale-sensitive ordering. Use
|
||||
* {@link java.text.Collator} for locale-sensitive comparison.
|
||||
*
|
||||
* @apiNote
|
||||
* This method is the Unicode-compliant alternative to
|
||||
* {@link #compareToIgnoreCase(String)}. It implements the
|
||||
* <em>{@index "full case folding"}</em> as defined by the Unicode Standard, which
|
||||
* may differ from the simpler per-character mapping performed by
|
||||
* {@code compareToIgnoreCase}.
|
||||
* For example:
|
||||
* {@snippet lang=java :
|
||||
* String a = "Fuß";
|
||||
* String b = "FUSS";
|
||||
* int cmpFoldCase = a.compareToFoldCase(b); // returns 0
|
||||
* int cmpIgnoreCase = a.compareToIgnoreCase(b); // returns > 0
|
||||
* }
|
||||
*
|
||||
* @param str the {@code String} to be compared.
|
||||
* @return a negative integer, zero, or a positive integer as the specified
|
||||
* String is greater than, equal to, or less than this String,
|
||||
* ignoring case considerations by case folding.
|
||||
*
|
||||
* @spec https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790 Unicode Caseless Matching
|
||||
* @see java.text.Collator
|
||||
* @see #compareToIgnoreCase(String)
|
||||
* @see #equalsFoldCase(String)
|
||||
* @since 26
|
||||
*/
|
||||
public int compareToFoldCase(String str) {
|
||||
return UNICODE_CASEFOLD_ORDER.compare(this, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if two string regions are equal.
|
||||
* <p>
|
||||
|
||||
@ -32,6 +32,8 @@ import java.util.function.Consumer;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.lang.CaseFolding;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
|
||||
@ -179,6 +181,128 @@ final class StringLatin1 {
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
private static int compareToFC0(byte[] value, int off, int last, byte[] other, int ooff, int olast) {
|
||||
int k1 = off, k2 = ooff;
|
||||
boolean lo1 = false, lo2 = false; // true if we have a leftover 's' from u+00df -> ss
|
||||
while ((k1 < last || lo1) && (k2 < olast || lo2)) {
|
||||
int c1, c2;
|
||||
if (lo1) {
|
||||
c1 = 0x73; // leftover 's'
|
||||
lo1 = false;
|
||||
} else {
|
||||
c1 = getChar(value, k1++);
|
||||
if (c1 == 0xdf) {
|
||||
c1 = 0x73;
|
||||
lo1 = true;
|
||||
}
|
||||
}
|
||||
if (lo2) {
|
||||
c2 = 0x73; // 's'
|
||||
lo2 = false;
|
||||
} else {
|
||||
c2 = getChar(other, k2++);
|
||||
if (c2 == 0xdf) {
|
||||
c2 = 0x73;
|
||||
lo2 = true;
|
||||
}
|
||||
}
|
||||
if (!CharacterDataLatin1.equalsIgnoreCase((byte)c1, (byte)c2)) {
|
||||
return Character.toLowerCase(c1) - Character.toLowerCase(c2);
|
||||
}
|
||||
}
|
||||
if (k1 < last || lo1) {
|
||||
return 1;
|
||||
}
|
||||
if (k2 < olast || lo2) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compareToFC(byte[] value, byte[] other) {
|
||||
int len = value.length;
|
||||
int olen = other.length;
|
||||
int lim = Math.min(len, olen);
|
||||
for (int k = 0; k < lim; k++) {
|
||||
byte b1 = value[k];
|
||||
byte b2 = other[k];
|
||||
if (!CharacterDataLatin1.equalsIgnoreCase(b1, b2)) {
|
||||
int c1 = b1 & 0xff;
|
||||
int c2 = b2 & 0xff;
|
||||
if (c1 == 0xdf || c2 == 0xdf) { // 0xdf is the only 1:M in latin1 range
|
||||
return compareToFC0(value, k, len, other, k, olen);
|
||||
}
|
||||
return Character.toLowerCase(c1) - Character.toLowerCase(c2);
|
||||
}
|
||||
}
|
||||
return len - olen;
|
||||
}
|
||||
|
||||
private static int compareToFC0_UTF16(byte[] value, int off, int last, byte[] other, int ooff, int olast) {
|
||||
int f1 = 0, f2 = 0;
|
||||
int k1 = off, k2 = ooff;
|
||||
while ((k1 < last || f1 != 0) && (k2 < olast || f2 != 0)) {
|
||||
int c1, c2;
|
||||
if (f1 != 0) {
|
||||
c1 = (f1 & 0xffff); f1 >>>= 16;
|
||||
} else {
|
||||
c1 = getChar(value, k1++);
|
||||
var f = CaseFolding.fold(c1);
|
||||
if (CaseFolding.isSingleCodePoint(f)) {
|
||||
c1 = (int)(f & 0xfffff);
|
||||
} else {
|
||||
c1 = (int)f & 0xffff;
|
||||
f1 = (int)(f >>> 16);
|
||||
}
|
||||
}
|
||||
if (f2 != 0) {
|
||||
c2 = f2 & 0xffff; f2 >>>= 16;
|
||||
} else {
|
||||
c2 = StringUTF16.codePointAt(other, k2, olast, true);
|
||||
k2 += Character.charCount(c2);
|
||||
var f = CaseFolding.fold(c2);
|
||||
if (CaseFolding.isSingleCodePoint(f)) {
|
||||
c2 = (int)(f & 0xfffff);
|
||||
} else {
|
||||
c2 = (int)(f & 0xffff);
|
||||
f2 = (int)(f >>> 16);
|
||||
}
|
||||
}
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
if (k1 < last || f1 != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (k2 < olast || f2 != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// latin1 vs utf16
|
||||
static int compareToFC_UTF16(byte[] value, byte[] other) {
|
||||
int last = length(value);
|
||||
int olast = StringUTF16.length(other);
|
||||
int lim = Math.min(last, olast);
|
||||
for (int k = 0; k < lim; k++) {
|
||||
int cp1 = getChar(value, k);
|
||||
int cp2 = StringUTF16.codePointAt(other, k, olast, true);
|
||||
if (cp1 != cp2) {
|
||||
long cf1 = CaseFolding.fold(cp1);
|
||||
long cf2 = CaseFolding.fold(cp2);
|
||||
if (cf1 != cf2) {
|
||||
if (!CaseFolding.isSingleCodePoint(cf1) || !CaseFolding.isSingleCodePoint(cf2)) {
|
||||
return compareToFC0_UTF16(value, k, last, other, k, olast);
|
||||
}
|
||||
return (int)(cf1 - cf2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return last - olast;
|
||||
}
|
||||
|
||||
static int hashCode(byte[] value) {
|
||||
return ArraysSupport.hashCodeOfUnsigned(value, 0, value.length, 0);
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ import java.util.function.IntConsumer;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.lang.CaseFolding;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
@ -93,7 +94,7 @@ final class StringUTF16 {
|
||||
return value.length >> 1;
|
||||
}
|
||||
|
||||
private static int codePointAt(byte[] value, int index, int end, boolean checked) {
|
||||
static int codePointAt(byte[] value, int index, int end, boolean checked) {
|
||||
assert index < end;
|
||||
if (checked) {
|
||||
checkIndex(index, value);
|
||||
@ -592,6 +593,77 @@ final class StringUTF16 {
|
||||
return -StringLatin1.compareToCI_UTF16(other, value);
|
||||
}
|
||||
|
||||
public static int compareToFC_Latin1(byte[] value, byte[] other) {
|
||||
return -StringLatin1.compareToFC_UTF16(other, value);
|
||||
}
|
||||
|
||||
private static int compareToFC0(byte[] value, int off, int last, byte[] other, int ooff, int olast) {
|
||||
int f1 = 0, f2 = 0;
|
||||
int k1 = off, k2 = ooff;
|
||||
while ((k1 < last || f1 != 0) && (k2 < olast || f2 != 0)) {
|
||||
int c1, c2;
|
||||
if (f1 != 0) {
|
||||
c1 = f1 & 0xffff; f1 >>>= 16;
|
||||
} else {
|
||||
c1 = StringUTF16.codePointAt(value, k1, last, true);
|
||||
k1 += Character.charCount(c1);
|
||||
var f = CaseFolding.fold(c1);
|
||||
if (CaseFolding.isSingleCodePoint(f)) {
|
||||
c1 = (int)(f & 0xfffff);
|
||||
} else {
|
||||
c1 = (int)(f & 0xffff);
|
||||
f1 = (int)(f >> 16);
|
||||
}
|
||||
}
|
||||
if (f2 != 0) {
|
||||
c2 = f2 & 0xffff; f2 >>>= 16;
|
||||
} else {
|
||||
c2 = StringUTF16.codePointAt(other, k2, olast, true);
|
||||
k2 += Character.charCount(c2);
|
||||
var f = CaseFolding.fold(c2);
|
||||
if (CaseFolding.isSingleCodePoint(f)) {
|
||||
c2 = (int)(f & 0xfffff);
|
||||
} else {
|
||||
c2 = (int)(f & 0xffff);
|
||||
f2 = (int)(f >>> 16);
|
||||
}
|
||||
}
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
if (k1 < last || f1 != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (k2 < olast || f2 != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int compareToFC(byte[] value, byte[] other) {
|
||||
int tlast = length(value);
|
||||
int olast = length(other);
|
||||
int lim = Math.min(tlast, olast);
|
||||
int k = 0;
|
||||
while (k < lim) {
|
||||
int cp1 = codePointAt(value, k, tlast, true);
|
||||
int cp2 = codePointAt(other, k, olast, true);
|
||||
if (cp1 != cp2) {
|
||||
long cf1 = CaseFolding.fold(cp1);
|
||||
long cf2 = CaseFolding.fold(cp2);
|
||||
if (cf1 != cf2) {
|
||||
if (!CaseFolding.isSingleCodePoint(cf1) || !CaseFolding.isSingleCodePoint(cf2)) {
|
||||
return compareToFC0(value, k, tlast, other, k, olast);
|
||||
}
|
||||
return (int) cf1 - (int) cf2;
|
||||
}
|
||||
}
|
||||
k += Character.charCount(cp1);
|
||||
}
|
||||
return tlast - olast;
|
||||
}
|
||||
|
||||
static int hashCode(byte[] value) {
|
||||
return ArraysSupport.hashCodeOfUTF16(value, 0, value.length >> 1, 0);
|
||||
}
|
||||
|
||||
@ -315,6 +315,18 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the given task to the given executor. If the scheduler is a
|
||||
* ForkJoinPool then the task is first adapted to a ForkJoinTask.
|
||||
*/
|
||||
private void submit(Executor executor, Runnable task) {
|
||||
if (executor instanceof ForkJoinPool pool) {
|
||||
pool.submit(ForkJoinTask.adapt(task));
|
||||
} else {
|
||||
executor.execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the runContinuation task to the scheduler. For the default scheduler,
|
||||
* and calling it on a worker thread, the task will be pushed to the local queue,
|
||||
@ -335,12 +347,12 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
if (currentThread().isVirtual()) {
|
||||
Continuation.pin();
|
||||
try {
|
||||
scheduler.execute(runContinuation);
|
||||
submit(scheduler, runContinuation);
|
||||
} finally {
|
||||
Continuation.unpin();
|
||||
}
|
||||
} else {
|
||||
scheduler.execute(runContinuation);
|
||||
submit(scheduler, runContinuation);
|
||||
}
|
||||
done = true;
|
||||
} catch (RejectedExecutionException ree) {
|
||||
@ -1536,4 +1548,4 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
unblocker.setDaemon(true);
|
||||
unblocker.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ public enum ClassFileFormatVersion {
|
||||
* @since 26
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.oracle.com/javase/specs/jvms/se26/html/index.html">
|
||||
* href="https://docs.oracle.com/en/java/javase/26/docs/specs/jvms/index.html">
|
||||
* <cite>The Java Virtual Machine Specification, Java SE 26 Edition</cite></a>
|
||||
*/
|
||||
RELEASE_26(70),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -72,7 +72,7 @@ public interface TypeVariable<D extends GenericDeclaration> extends Type, Annota
|
||||
Type[] getBounds();
|
||||
|
||||
/**
|
||||
* Returns the {@code GenericDeclaration} object representing the
|
||||
* Returns a {@code GenericDeclaration} object representing the
|
||||
* generic declaration declared for this type variable.
|
||||
*
|
||||
* @return the generic declaration declared for this type variable.
|
||||
|
||||
@ -560,89 +560,70 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* access (which is usually needed anyway).
|
||||
*
|
||||
* Signalling. Signals (in signalWork) cause new or reactivated
|
||||
* workers to scan for tasks. Method signalWork and its callers
|
||||
* try to approximate the unattainable goal of having the right
|
||||
* number of workers activated for the tasks at hand, but must err
|
||||
* on the side of too many workers vs too few to avoid stalls:
|
||||
* workers to scan for tasks. SignalWork is invoked in two cases:
|
||||
* (1) When a task is pushed onto an empty queue, and (2) When a
|
||||
* worker takes a top-level task from a queue that has additional
|
||||
* tasks. Together, these suffice in O(log(#threads)) steps to
|
||||
* fully activate with at least enough workers, and ideally no
|
||||
* more than required. This ideal is unobtainable: Callers do not
|
||||
* know whether another worker will finish its current task and
|
||||
* poll for others without need of a signal (which is otherwise an
|
||||
* advantage of work-stealing vs other schemes), and also must
|
||||
* conservatively estimate the triggering conditions of emptiness
|
||||
* or non-emptiness; all of which usually cause more activations
|
||||
* than necessary (see below). (Method signalWork is also used as
|
||||
* failsafe in case of Thread failures in deregisterWorker, to
|
||||
* activate or create a new worker to replace them).
|
||||
*
|
||||
* * If computations are purely tree structured, it suffices for
|
||||
* every worker to activate another when it pushes a task into
|
||||
* an empty queue, resulting in O(log(#threads)) steps to full
|
||||
* activation. Emptiness must be conservatively approximated,
|
||||
* which may result in unnecessary signals. Also, to reduce
|
||||
* resource usages in some cases, at the expense of slower
|
||||
* startup in others, activation of an idle thread is preferred
|
||||
* over creating a new one, here and elsewhere.
|
||||
*
|
||||
* * At the other extreme, if "flat" tasks (those that do not in
|
||||
* turn generate others) come in serially from only a single
|
||||
* producer, each worker taking a task from a queue should
|
||||
* propagate a signal if there are more tasks in that
|
||||
* queue. This is equivalent to, but generally faster than,
|
||||
* arranging the stealer take multiple tasks, re-pushing one or
|
||||
* more on its own queue, and signalling (because its queue is
|
||||
* empty), also resulting in logarithmic full activation
|
||||
* time. If tasks do not not engage in unbounded loops based on
|
||||
* the actions of other workers with unknown dependencies loop,
|
||||
* this form of proagation can be limited to one signal per
|
||||
* activation (phase change). We distinguish the cases by
|
||||
* further signalling only if the task is an InterruptibleTask
|
||||
* (see below), which are the only supported forms of task that
|
||||
* may do so.
|
||||
*
|
||||
* * Because we don't know about usage patterns (or most commonly,
|
||||
* mixtures), we use both approaches, which present even more
|
||||
* opportunities to over-signal. (Failure to distinguish these
|
||||
* cases in terms of submission methods was arguably an early
|
||||
* design mistake.) Note that in either of these contexts,
|
||||
* signals may be (and often are) unnecessary because active
|
||||
* workers continue scanning after running tasks without the
|
||||
* need to be signalled (which is one reason work stealing is
|
||||
* often faster than alternatives), so additional workers
|
||||
* aren't needed.
|
||||
*
|
||||
* * For rapidly branching tasks that require full pool resources,
|
||||
* oversignalling is OK, because signalWork will soon have no
|
||||
* more workers to create or reactivate. But for others (mainly
|
||||
* externally submitted tasks), overprovisioning may cause very
|
||||
* noticeable slowdowns due to contention and resource
|
||||
* wastage. We reduce impact by deactivating workers when
|
||||
* queues don't have accessible tasks, but reactivating and
|
||||
* rescanning if other tasks remain.
|
||||
*
|
||||
* * Despite these, signal contention and overhead effects still
|
||||
* occur during ramp-up and ramp-down of small computations.
|
||||
* Top-Level scheduling
|
||||
* ====================
|
||||
*
|
||||
* Scanning. Method runWorker performs top-level scanning for (and
|
||||
* execution of) tasks by polling a pseudo-random permutation of
|
||||
* the array (by starting at a given index, and using a constant
|
||||
* cyclically exhaustive stride.) It uses the same basic polling
|
||||
* method as WorkQueue.poll(), but restarts with a different
|
||||
* permutation on each invocation. The pseudorandom generator
|
||||
* need not have high-quality statistical properties in the long
|
||||
* permutation on each rescan. The pseudorandom generator need
|
||||
* not have high-quality statistical properties in the long
|
||||
* term. We use Marsaglia XorShifts, seeded with the Weyl sequence
|
||||
* from ThreadLocalRandom probes, which are cheap and
|
||||
* suffice. Each queue's polling attempts to avoid becoming stuck
|
||||
* when other scanners/pollers stall. Scans do not otherwise
|
||||
* explicitly take into account core affinities, loads, cache
|
||||
* localities, etc, However, they do exploit temporal locality
|
||||
* (which usually approximates these) by preferring to re-poll
|
||||
* from the same queue after a successful poll before trying
|
||||
* others, which also reduces bookkeeping, cache traffic, and
|
||||
* scanning overhead. But it also reduces fairness, which is
|
||||
* partially counteracted by giving up on detected interference
|
||||
* (which also reduces contention when too many workers try to
|
||||
* take small tasks from the same queue).
|
||||
* from ThreadLocalRandom probes, which are cheap and suffice.
|
||||
*
|
||||
* Deactivation. When no tasks are found by a worker in runWorker,
|
||||
* it tries to deactivate()), giving up (and rescanning) on "ctl"
|
||||
* contention. To avoid missed signals during deactivation, the
|
||||
* method rescans and reactivates if there may have been a missed
|
||||
* signal during deactivation. To reduce false-alarm reactivations
|
||||
* while doing so, we scan multiple times (analogously to method
|
||||
* quiescent()) before trying to reactivate. Because idle workers
|
||||
* are often not yet blocked (parked), we use a WorkQueue field to
|
||||
* advertise that a waiter actually needs unparking upon signal.
|
||||
* it invokes deactivate, that first deactivates (to an IDLE
|
||||
* phase). Avoiding missed signals during deactivation requires a
|
||||
* (conservative) rescan, reactivating if there may be tasks to
|
||||
* poll. Because idle workers are often not yet blocked (parked),
|
||||
* we use a WorkQueue field to advertise that a waiter actually
|
||||
* needs unparking upon signal.
|
||||
*
|
||||
* When tasks are constructed as (recursive) DAGs, top-level
|
||||
* scanning is usually infrequent, and doesn't encounter most
|
||||
* of the following problems addressed by runWorker and awaitWork:
|
||||
*
|
||||
* Locality. Polls are organized into "runs", continuing until
|
||||
* empty or contended, while also minimizing interference by
|
||||
* postponing bookeeping to ends of runs. This may reduce
|
||||
* fairness.
|
||||
*
|
||||
* Contention. When many workers try to poll few queues, they
|
||||
* often collide, generating CAS failures and disrupting locality
|
||||
* of workers already running their tasks. This also leads to
|
||||
* stalls when tasks cannot be taken because other workers have
|
||||
* not finished poll operations, which is detected by reading
|
||||
* ahead in queue arrays. In both cases, workers restart scans in a
|
||||
* way that approximates randomized backoff.
|
||||
*
|
||||
* Oversignalling. When many short top-level tasks are present in
|
||||
* a small number of queues, the above signalling strategy may
|
||||
* activate many more workers than needed, worsening locality and
|
||||
* contention problems, while also generating more global
|
||||
* contention (field ctl is CASed on every activation and
|
||||
* deactivation). We filter out (both in runWorker and
|
||||
* signalWork) attempted signals that are surely not needed
|
||||
* because the signalled tasks are already taken.
|
||||
*
|
||||
* Shutdown and Quiescence
|
||||
* =======================
|
||||
*
|
||||
* Quiescence. Workers scan looking for work, giving up when they
|
||||
* don't find any, without being sure that none are available.
|
||||
@ -892,9 +873,7 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* shutdown, runners are interrupted so they can cancel. Since
|
||||
* external joining callers never run these tasks, they must await
|
||||
* cancellation by others, which can occur along several different
|
||||
* paths. The inability to rely on caller-runs may also require
|
||||
* extra signalling (resulting in scanning and contention) so is
|
||||
* done only conditionally in methods push and runworker.
|
||||
* paths.
|
||||
*
|
||||
* Across these APIs, rules for reporting exceptions for tasks
|
||||
* with results accessed via join() differ from those via get(),
|
||||
@ -961,9 +940,13 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* less-contended applications. To help arrange this, some
|
||||
* non-reference fields are declared as "long" even when ints or
|
||||
* shorts would suffice. For class WorkQueue, an
|
||||
* embedded @Contended region segregates fields most heavily
|
||||
* updated by owners from those most commonly read by stealers or
|
||||
* other management.
|
||||
* embedded @Contended isolates the very busy top index, along
|
||||
* with status and bookkeeping fields written (mostly) by owners,
|
||||
* that otherwise interfere with reading array and base
|
||||
* fields. There are other variables commonly contributing to
|
||||
* false-sharing-related performance issues (including fields of
|
||||
* class Thread), but we can't do much about this except try to
|
||||
* minimize access.
|
||||
*
|
||||
* Initial sizing and resizing of WorkQueue arrays is an even more
|
||||
* delicate tradeoff because the best strategy systematically
|
||||
@ -972,13 +955,11 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* direct false-sharing and indirect cases due to GC bookkeeping
|
||||
* (cardmarks etc), and reduce the number of resizes, which are
|
||||
* not especially fast because they require atomic transfers.
|
||||
* Currently, arrays for workers are initialized to be just large
|
||||
* enough to avoid resizing in most tree-structured tasks, but
|
||||
* larger for external queues where both false-sharing problems
|
||||
* and the need for resizing are more common. (Maintenance note:
|
||||
* any changes in fields, queues, or their uses, or JVM layout
|
||||
* policies, must be accompanied by re-evaluation of these
|
||||
* placement and sizing decisions.)
|
||||
* Currently, arrays are initialized to be just large enough to
|
||||
* avoid resizing in most tree-structured tasks, but grow rapidly
|
||||
* until large. (Maintenance note: any changes in fields, queues,
|
||||
* or their uses, or JVM layout policies, must be accompanied by
|
||||
* re-evaluation of these placement and sizing decisions.)
|
||||
*
|
||||
* Style notes
|
||||
* ===========
|
||||
@ -1061,17 +1042,11 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
static final int DEFAULT_COMMON_MAX_SPARES = 256;
|
||||
|
||||
/**
|
||||
* Initial capacity of work-stealing queue array for workers.
|
||||
* Initial capacity of work-stealing queue array.
|
||||
* Must be a power of two, at least 2. See above.
|
||||
*/
|
||||
static final int INITIAL_QUEUE_CAPACITY = 1 << 6;
|
||||
|
||||
/**
|
||||
* Initial capacity of work-stealing queue array for external queues.
|
||||
* Must be a power of two, at least 2. See above.
|
||||
*/
|
||||
static final int INITIAL_EXTERNAL_QUEUE_CAPACITY = 1 << 9;
|
||||
|
||||
// conversions among short, int, long
|
||||
static final int SMASK = 0xffff; // (unsigned) short bits
|
||||
static final long LMASK = 0xffffffffL; // lower 32 bits of long
|
||||
@ -1211,11 +1186,11 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
@jdk.internal.vm.annotation.Contended("w")
|
||||
int stackPred; // pool stack (ctl) predecessor link
|
||||
@jdk.internal.vm.annotation.Contended("w")
|
||||
volatile int parking; // nonzero if parked in awaitWork
|
||||
@jdk.internal.vm.annotation.Contended("w")
|
||||
volatile int source; // source queue id (or DROPPED)
|
||||
@jdk.internal.vm.annotation.Contended("w")
|
||||
int nsteals; // number of steals from other queues
|
||||
@jdk.internal.vm.annotation.Contended("w")
|
||||
volatile int parking; // nonzero if parked in awaitWork
|
||||
|
||||
// Support for atomic operations
|
||||
private static final Unsafe U;
|
||||
@ -1248,11 +1223,11 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
*/
|
||||
WorkQueue(ForkJoinWorkerThread owner, int id, int cfg,
|
||||
boolean clearThreadLocals) {
|
||||
array = new ForkJoinTask<?>[owner == null ?
|
||||
INITIAL_EXTERNAL_QUEUE_CAPACITY :
|
||||
INITIAL_QUEUE_CAPACITY];
|
||||
this.owner = owner;
|
||||
this.config = (clearThreadLocals) ? cfg | CLEAR_TLS : cfg;
|
||||
if ((this.owner = owner) == null) {
|
||||
array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
|
||||
phase = id | IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1279,27 +1254,27 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* @throws RejectedExecutionException if array could not be resized
|
||||
*/
|
||||
final void push(ForkJoinTask<?> task, ForkJoinPool pool, boolean internal) {
|
||||
int s = top, b = base, m, cap, room; ForkJoinTask<?>[] a;
|
||||
if ((a = array) != null && (cap = a.length) > 0 && // else disabled
|
||||
task != null) {
|
||||
int pk = task.noUserHelp() + 1; // prev slot offset
|
||||
if ((room = (m = cap - 1) - (s - b)) >= 0) {
|
||||
int s = top, b = base, m, cap, room; ForkJoinTask<?>[] a, na;
|
||||
if ((a = array) != null && (cap = a.length) > 0) { // else disabled
|
||||
int k = (m = cap - 1) & s;
|
||||
if ((room = m - (s - b)) >= 0) {
|
||||
top = s + 1;
|
||||
long pos = slotOffset(m & s);
|
||||
long pos = slotOffset(k);
|
||||
if (!internal)
|
||||
U.putReference(a, pos, task); // inside lock
|
||||
else
|
||||
U.getAndSetReference(a, pos, task); // fully fenced
|
||||
if (room == 0) // resize
|
||||
growArray(a, cap, s);
|
||||
if (room == 0 && (na = growArray(a, cap, s)) != null)
|
||||
k = ((a = na).length - 1) & s; // resize
|
||||
}
|
||||
if (!internal)
|
||||
unlockPhase();
|
||||
if (room < 0)
|
||||
throw new RejectedExecutionException("Queue capacity exceeded");
|
||||
if ((room == 0 || a[m & (s - pk)] == null) &&
|
||||
pool != null)
|
||||
pool.signalWork(); // may have appeared empty
|
||||
if (pool != null &&
|
||||
(room == 0 ||
|
||||
U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null))
|
||||
pool.signalWork(a, k); // may have appeared empty
|
||||
}
|
||||
}
|
||||
|
||||
@ -1308,11 +1283,12 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* @param a old array
|
||||
* @param cap old array capacity
|
||||
* @param s current top
|
||||
* @return new array, or null on failure
|
||||
*/
|
||||
private void growArray(ForkJoinTask<?>[] a, int cap, int s) {
|
||||
int newCap = cap << 1;
|
||||
private ForkJoinTask<?>[] growArray(ForkJoinTask<?>[] a, int cap, int s) {
|
||||
int newCap = (cap >= 1 << 16) ? cap << 1 : cap << 2;
|
||||
ForkJoinTask<?>[] newArray = null;
|
||||
if (a != null && a.length == cap && cap > 0 && newCap > 0) {
|
||||
ForkJoinTask<?>[] newArray = null;
|
||||
try {
|
||||
newArray = new ForkJoinTask<?>[newCap];
|
||||
} catch (OutOfMemoryError ex) {
|
||||
@ -1329,34 +1305,45 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
updateArray(newArray); // fully fenced
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes next task, if one exists, in order specified by mode,
|
||||
* so acts as either local-pop or local-poll. Called only by owner.
|
||||
* @param fifo nonzero if FIFO mode
|
||||
* Takes next task, if one exists, in lifo order.
|
||||
*/
|
||||
private ForkJoinTask<?> nextLocalTask(int fifo) {
|
||||
private ForkJoinTask<?> localPop() {
|
||||
ForkJoinTask<?> t = null;
|
||||
ForkJoinTask<?>[] a = array;
|
||||
int b = base, p = top, cap;
|
||||
if (p - b > 0 && a != null && (cap = a.length) > 0) {
|
||||
for (int m = cap - 1, s, nb;;) {
|
||||
if (fifo == 0 || (nb = b + 1) == p) {
|
||||
if ((t = (ForkJoinTask<?>)U.getAndSetReference(
|
||||
a, slotOffset(m & (s = p - 1)), null)) != null)
|
||||
updateTop(s); // else lost race for only task
|
||||
break;
|
||||
int s = top - 1, cap; long k; ForkJoinTask<?>[] a;
|
||||
if ((a = array) != null && (cap = a.length) > 0 &&
|
||||
U.getReference(a, k = slotOffset((cap - 1) & s)) != null &&
|
||||
(t = (ForkJoinTask<?>)U.getAndSetReference(a, k, null)) != null)
|
||||
updateTop(s);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes next task, if one exists, in fifo order.
|
||||
*/
|
||||
private ForkJoinTask<?> localPoll() {
|
||||
ForkJoinTask<?> t = null;
|
||||
int p = top, cap; ForkJoinTask<?>[] a;
|
||||
if ((a = array) != null && (cap = a.length) > 0) {
|
||||
for (int b = base; p - b > 0; ) {
|
||||
int nb = b + 1;
|
||||
long k = slotOffset((cap - 1) & b);
|
||||
if (U.getReference(a, k) == null) {
|
||||
if (nb == p)
|
||||
break; // else base is lagging
|
||||
while (b == (b = U.getIntAcquire(this, BASE)))
|
||||
Thread.onSpinWait(); // spin to reduce memory traffic
|
||||
}
|
||||
if ((t = (ForkJoinTask<?>)U.getAndSetReference(
|
||||
a, slotOffset(m & b), null)) != null) {
|
||||
else if ((t = (ForkJoinTask<?>)
|
||||
U.getAndSetReference(a, k, null)) != null) {
|
||||
updateBase(nb);
|
||||
break;
|
||||
}
|
||||
while (b == (b = U.getIntAcquire(this, BASE)))
|
||||
Thread.onSpinWait(); // spin to reduce memory traffic
|
||||
if (p - b <= 0)
|
||||
break;
|
||||
else
|
||||
b = base;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
@ -1364,10 +1351,9 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
|
||||
/**
|
||||
* Takes next task, if one exists, using configured mode.
|
||||
* (Always internal, never called for Common pool.)
|
||||
*/
|
||||
final ForkJoinTask<?> nextLocalTask() {
|
||||
return nextLocalTask(config & FIFO);
|
||||
return (config & FIFO) == 0 ? localPop() : localPoll();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1443,12 +1429,12 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
// specialized execution methods
|
||||
|
||||
/**
|
||||
* Runs the given task, as well as remaining local tasks.
|
||||
* Runs the given task, as well as remaining local tasks
|
||||
*/
|
||||
final void topLevelExec(ForkJoinTask<?> task, int fifo) {
|
||||
while (task != null) {
|
||||
task.doExec();
|
||||
task = nextLocalTask(fifo);
|
||||
task = (fifo != 0) ? localPoll() : localPop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1578,7 +1564,7 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* Cancels all local tasks. Called only by owner.
|
||||
*/
|
||||
final void cancelTasks() {
|
||||
for (ForkJoinTask<?> t; (t = nextLocalTask(0)) != null; ) {
|
||||
for (ForkJoinTask<?> t; (t = localPop()) != null; ) {
|
||||
try {
|
||||
t.cancel(false);
|
||||
} catch (Throwable ignore) {
|
||||
@ -1780,7 +1766,8 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* @param w caller's WorkQueue
|
||||
*/
|
||||
final void registerWorker(WorkQueue w) {
|
||||
if (w != null && (runState & STOP) == 0L) {
|
||||
if (w != null) {
|
||||
w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
|
||||
ThreadLocalRandom.localInit();
|
||||
int seed = w.stackPred = ThreadLocalRandom.getProbe();
|
||||
int phaseSeq = seed & ~((IDLE << 1) - 1); // initial phase tag
|
||||
@ -1858,17 +1845,18 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
}
|
||||
if ((tryTerminate(false, false) & STOP) == 0L &&
|
||||
phase != 0 && w != null && w.source != DROPPED) {
|
||||
signalWork(); // possibly replace
|
||||
w.cancelTasks(); // clean queue
|
||||
signalWork(null, 0); // possibly replace
|
||||
}
|
||||
if (ex != null)
|
||||
ForkJoinTask.rethrow(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases an idle worker, or creates one if not enough exist.
|
||||
* Releases an idle worker, or creates one if not enough exist,
|
||||
* giving up if array a is nonnull and task at a[k] already taken.
|
||||
*/
|
||||
final void signalWork() {
|
||||
final void signalWork(ForkJoinTask<?>[] a, int k) {
|
||||
int pc = parallelism;
|
||||
for (long c = ctl;;) {
|
||||
WorkQueue[] qs = queues;
|
||||
@ -1884,13 +1872,15 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
if (sp == 0) {
|
||||
if ((short)(c >>> TC_SHIFT) >= pc)
|
||||
break;
|
||||
nc = ((c + TC_UNIT) & TC_MASK);
|
||||
nc = ((c + TC_UNIT) & TC_MASK) | ac;
|
||||
}
|
||||
else if ((v = w) == null)
|
||||
break;
|
||||
else
|
||||
nc = (v.stackPred & LMASK) | (c & TC_MASK);
|
||||
if (c == (c = compareAndExchangeCtl(c, nc | ac))) {
|
||||
nc = (v.stackPred & LMASK) | (c & TC_MASK) | ac;
|
||||
if (a != null && k < a.length && k >= 0 && a[k] == null)
|
||||
break;
|
||||
if (c == (c = ctl) && c == (c = compareAndExchangeCtl(c, nc))) {
|
||||
if (v == null)
|
||||
createWorker();
|
||||
else {
|
||||
@ -1973,178 +1963,196 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* @param w caller's WorkQueue (may be null on failed initialization)
|
||||
*/
|
||||
final void runWorker(WorkQueue w) {
|
||||
if (w != null) {
|
||||
int phase = w.phase, r = w.stackPred; // seed from registerWorker
|
||||
int fifo = w.config & FIFO, nsteals = 0, src = -1;
|
||||
for (;;) {
|
||||
WorkQueue[] qs;
|
||||
if (w != null && w.phase != 0) { // else unregistered
|
||||
WorkQueue[] qs;
|
||||
int r = w.stackPred; // seed from registerWorker
|
||||
int fifo = (int)config & FIFO, rescans = 0, inactive = 0, taken = 0, n;
|
||||
while ((runState & STOP) == 0L && (qs = queues) != null &&
|
||||
(n = qs.length) > 0) {
|
||||
int i = r, step = (r >>> 16) | 1;
|
||||
r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
|
||||
if ((runState & STOP) != 0L || (qs = queues) == null)
|
||||
break;
|
||||
int n = qs.length, i = r, step = (r >>> 16) | 1;
|
||||
boolean rescan = false;
|
||||
scan: for (int l = n; l > 0; --l, i += step) { // scan queues
|
||||
int j, cap; WorkQueue q; ForkJoinTask<?>[] a;
|
||||
if ((q = qs[j = i & (n - 1)]) != null &&
|
||||
(a = q.array) != null && (cap = a.length) > 0) {
|
||||
for (int m = cap - 1, pb = -1, b = q.base;;) {
|
||||
ForkJoinTask<?> t; long k;
|
||||
scan: for (int j = n; j != 0; --j, i += step) {
|
||||
WorkQueue q; int qid;
|
||||
if ((q = qs[qid = i & (n - 1)]) != null) {
|
||||
ForkJoinTask<?>[] a; int cap; // poll queue
|
||||
while ((a = q.array) != null && (cap = a.length) > 0) {
|
||||
int b, nb, nk; long bp; ForkJoinTask<?> t;
|
||||
t = (ForkJoinTask<?>)U.getReferenceAcquire(
|
||||
a, k = slotOffset(m & b));
|
||||
if (b != (b = q.base) || t == null ||
|
||||
!U.compareAndSetReference(a, k, t, null)) {
|
||||
if (a[b & m] == null) {
|
||||
if (rescan) // end of run
|
||||
break scan;
|
||||
if (a[(b + 1) & m] == null &&
|
||||
a[(b + 2) & m] == null) {
|
||||
break; // probably empty
|
||||
a, bp = slotOffset((cap - 1) & (b = q.base)));
|
||||
long np = slotOffset(nk = (nb = b + 1) & (cap - 1));
|
||||
if (q.base == b) { // else inconsistent
|
||||
if (t == null) {
|
||||
if (q.array == a) { // else resized
|
||||
if (rescans > 0) // ran or stalled
|
||||
break scan;
|
||||
if (U.getReference(a, np) == null &&
|
||||
(rescans >= 0 ||
|
||||
(U.getReferenceAcquire(a, bp) == null &&
|
||||
q.top == q.base)))
|
||||
break;
|
||||
rescans = 1; // may be stalled
|
||||
}
|
||||
if (pb == (pb = b)) { // track progress
|
||||
rescan = true; // stalled; reorder scan
|
||||
}
|
||||
else if (inactive != 0) {
|
||||
if ((inactive = tryReactivate(w)) != 0) {
|
||||
rescans = 1; // can't take yet
|
||||
break scan;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
boolean propagate;
|
||||
int nb = q.base = b + 1, prevSrc = src;
|
||||
w.nsteals = ++nsteals;
|
||||
w.source = src = j; // volatile
|
||||
rescan = true;
|
||||
int nh = t.noUserHelp();
|
||||
if (propagate =
|
||||
(prevSrc != src || nh != 0) && a[nb & m] != null)
|
||||
signalWork();
|
||||
w.topLevelExec(t, fifo);
|
||||
if ((b = q.base) != nb && !propagate)
|
||||
break scan; // reduce interference
|
||||
else if (U.compareAndSetReference(a, bp, t, null)) {
|
||||
q.base = nb;
|
||||
Object nt = U.getReferenceAcquire(a, np);
|
||||
w.source = qid;
|
||||
rescans = 1;
|
||||
++taken;
|
||||
if (nt != null && // confirm a[nk]
|
||||
U.getReferenceAcquire(a, np) == nt)
|
||||
signalWork(a, nk); // propagate
|
||||
w.topLevelExec(t, fifo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rescan) {
|
||||
if (((phase = deactivate(w, phase)) & IDLE) != 0)
|
||||
break;
|
||||
src = -1; // re-enable propagation
|
||||
if (rescans >= 0)
|
||||
--rescans;
|
||||
else if (inactive == 0) {
|
||||
if ((inactive = deactivate(w, taken)) != 0)
|
||||
taken = 0;
|
||||
}
|
||||
else if (awaitWork(w) == 0)
|
||||
inactive = rescans = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates and if necessary awaits signal or termination.
|
||||
* Tries to deactivate worker, keeping active on contention
|
||||
*
|
||||
* @param w the worker
|
||||
* @param phase current phase
|
||||
* @return current phase, with IDLE set if worker should exit
|
||||
* @param w the work queue
|
||||
* @param taken number of stolen tasks since last deactivation
|
||||
* @return nonzero if inactive
|
||||
*/
|
||||
private int deactivate(WorkQueue w, int phase) {
|
||||
if (w == null) // currently impossible
|
||||
return IDLE;
|
||||
int p = phase | IDLE, activePhase = phase + (IDLE << 1);
|
||||
long pc = ctl, qc = (activePhase & LMASK) | ((pc - RC_UNIT) & UMASK);
|
||||
int sp = w.stackPred = (int)pc; // set ctl stack link
|
||||
w.phase = p;
|
||||
if (!compareAndSetCtl(pc, qc)) // try to enqueue
|
||||
return w.phase = phase; // back out on possible signal
|
||||
int ac = (short)(qc >>> RC_SHIFT), n; long e; WorkQueue[] qs;
|
||||
if (((e = runState) & STOP) != 0L ||
|
||||
((e & SHUTDOWN) != 0L && ac == 0 && quiescent() > 0) ||
|
||||
(qs = queues) == null || (n = qs.length) <= 0)
|
||||
return IDLE; // terminating
|
||||
|
||||
for (int prechecks = Math.min(ac, 2), // reactivation threshold
|
||||
k = Math.max(n + (n << 1), SPIN_WAITS << 1);;) {
|
||||
WorkQueue q; int cap; ForkJoinTask<?>[] a; long c;
|
||||
if (w.phase == activePhase)
|
||||
return activePhase;
|
||||
if (--k < 0)
|
||||
return awaitWork(w, p); // block, drop, or exit
|
||||
if ((q = qs[k & (n - 1)]) == null)
|
||||
Thread.onSpinWait();
|
||||
else if ((a = q.array) != null && (cap = a.length) > 0 &&
|
||||
a[q.base & (cap - 1)] != null && --prechecks < 0 &&
|
||||
(int)(c = ctl) == activePhase &&
|
||||
compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK)))
|
||||
return w.phase = activePhase; // reactivate
|
||||
private int deactivate(WorkQueue w, int taken) {
|
||||
int inactive = 0, phase;
|
||||
if (w != null && (inactive = (phase = w.phase) & IDLE) == 0) {
|
||||
long sp = (phase + (IDLE << 1)) & LMASK, pc, c;
|
||||
w.phase = phase | IDLE;
|
||||
w.stackPred = (int)(pc = ctl); // set ctl stack link
|
||||
if (!compareAndSetCtl( // try to enqueue
|
||||
pc, c = ((pc - RC_UNIT) & UMASK) | sp))
|
||||
w.phase = phase; // back out on contention
|
||||
else {
|
||||
if (taken != 0) {
|
||||
w.nsteals += taken;
|
||||
if ((w.config & CLEAR_TLS) != 0 &&
|
||||
(Thread.currentThread() instanceof ForkJoinWorkerThread f))
|
||||
f.resetThreadLocals(); // (instanceof check always true)
|
||||
}
|
||||
if (((c & RC_MASK) == 0L && quiescent() > 0) || taken == 0)
|
||||
inactive = w.phase & IDLE; // check quiescent termination
|
||||
else { // spin for approx 1 scan cost
|
||||
int tc = (short)(c >>> TC_SHIFT);
|
||||
int spins = Math.max((tc << 1) + tc, SPIN_WAITS);
|
||||
while ((inactive = w.phase & IDLE) != 0 && --spins != 0)
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
}
|
||||
return inactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reactivates worker w if it is currently top of ctl stack
|
||||
*
|
||||
* @param w the work queue
|
||||
* @return 0 if now active
|
||||
*/
|
||||
private int tryReactivate(WorkQueue w) {
|
||||
int inactive = 0;
|
||||
if (w != null) { // always true; hoist checks
|
||||
int sp = w.stackPred, phase, activePhase; long c;
|
||||
if ((inactive = (phase = w.phase) & IDLE) != 0 &&
|
||||
(int)(c = ctl) == (activePhase = phase + IDLE) &&
|
||||
compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) {
|
||||
w.phase = activePhase;
|
||||
inactive = 0;
|
||||
}
|
||||
}
|
||||
return inactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits signal or termination.
|
||||
*
|
||||
* @param w the work queue
|
||||
* @param p current phase (known to be idle)
|
||||
* @return current phase, with IDLE set if worker should exit
|
||||
* @return 0 if now active
|
||||
*/
|
||||
private int awaitWork(WorkQueue w, int p) {
|
||||
if (w != null) {
|
||||
ForkJoinWorkerThread t; long deadline;
|
||||
if ((w.config & CLEAR_TLS) != 0 && (t = w.owner) != null)
|
||||
t.resetThreadLocals(); // clear before reactivate
|
||||
if ((ctl & RC_MASK) > 0L)
|
||||
deadline = 0L;
|
||||
else if ((deadline =
|
||||
(((w.source != INVALID_ID) ? keepAlive : TIMEOUT_SLOP)) +
|
||||
System.currentTimeMillis()) == 0L)
|
||||
deadline = 1L; // avoid zero
|
||||
int activePhase = p + IDLE;
|
||||
if ((p = w.phase) != activePhase && (runState & STOP) == 0L) {
|
||||
private int awaitWork(WorkQueue w) {
|
||||
int inactive = 0, phase;
|
||||
if (w != null) { // always true; hoist checks
|
||||
long waitTime = (w.source == INVALID_ID) ? 0L : keepAlive;
|
||||
if ((inactive = (phase = w.phase) & IDLE) != 0) {
|
||||
LockSupport.setCurrentBlocker(this);
|
||||
w.parking = 1; // enable unpark
|
||||
while ((p = w.phase) != activePhase) {
|
||||
boolean trimmable = false; int trim;
|
||||
Thread.interrupted(); // clear status
|
||||
int activePhase = phase + IDLE;
|
||||
for (long deadline = 0L;;) {
|
||||
Thread.interrupted(); // clear status
|
||||
if ((runState & STOP) != 0L)
|
||||
break;
|
||||
if (deadline != 0L) {
|
||||
if ((trim = tryTrim(w, p, deadline)) > 0)
|
||||
break;
|
||||
else if (trim < 0)
|
||||
deadline = 0L;
|
||||
else
|
||||
trimmable = true;
|
||||
boolean trimmable = false; // use timed wait if trimmable
|
||||
long d = 0L, c;
|
||||
if (((c = ctl) & RC_MASK) == 0L && (int)c == activePhase) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (deadline == 0L)
|
||||
deadline = waitTime + now;
|
||||
if (deadline - now <= TIMEOUT_SLOP) {
|
||||
if (tryTrim(w, c, activePhase))
|
||||
break;
|
||||
continue; // lost race to trim
|
||||
}
|
||||
d = deadline;
|
||||
trimmable = true;
|
||||
}
|
||||
U.park(trimmable, deadline);
|
||||
w.parking = 1; // enable unpark and recheck
|
||||
if ((inactive = w.phase & IDLE) != 0)
|
||||
U.park(trimmable, d);
|
||||
w.parking = 0; // close unpark window
|
||||
if (inactive == 0 || (inactive = w.phase & IDLE) == 0)
|
||||
break;
|
||||
}
|
||||
w.parking = 0;
|
||||
LockSupport.setCurrentBlocker(null);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
return inactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to remove and deregister worker after timeout, and release
|
||||
* another to do the same.
|
||||
* @return > 0: trimmed, < 0 : not trimmable, else 0
|
||||
* another to do the same unless new tasks are found.
|
||||
*/
|
||||
private int tryTrim(WorkQueue w, int phase, long deadline) {
|
||||
long c, nc; int stat, activePhase, vp, i; WorkQueue[] vs; WorkQueue v;
|
||||
if ((activePhase = phase + IDLE) != (int)(c = ctl) || w == null)
|
||||
stat = -1; // no longer ctl top
|
||||
else if (deadline - System.currentTimeMillis() >= TIMEOUT_SLOP)
|
||||
stat = 0; // spurious wakeup
|
||||
else if (!compareAndSetCtl(
|
||||
c, nc = ((w.stackPred & LMASK) | (RC_MASK & c) |
|
||||
(TC_MASK & (c - TC_UNIT)))))
|
||||
stat = -1; // lost race to signaller
|
||||
else {
|
||||
stat = 1;
|
||||
w.source = DROPPED;
|
||||
w.phase = activePhase;
|
||||
if ((vp = (int)nc) != 0 && (vs = queues) != null &&
|
||||
vs.length > (i = vp & SMASK) && (v = vs[i]) != null &&
|
||||
compareAndSetCtl( // try to wake up next waiter
|
||||
nc, ((UMASK & (nc + RC_UNIT)) |
|
||||
(nc & TC_MASK) | (v.stackPred & LMASK)))) {
|
||||
v.source = INVALID_ID; // enable cascaded timeouts
|
||||
v.phase = vp;
|
||||
U.unpark(v.owner);
|
||||
private boolean tryTrim(WorkQueue w, long c, int activePhase) {
|
||||
if (w != null) {
|
||||
int vp, i; WorkQueue[] vs; WorkQueue v;
|
||||
long nc = ((w.stackPred & LMASK) |
|
||||
((RC_MASK & c) | (TC_MASK & (c - TC_UNIT))));
|
||||
if (compareAndSetCtl(c, nc)) {
|
||||
w.source = DROPPED;
|
||||
w.phase = activePhase;
|
||||
if ((vp = (int)nc) != 0 && (vs = queues) != null &&
|
||||
vs.length > (i = vp & SMASK) && (v = vs[i]) != null &&
|
||||
compareAndSetCtl( // try to wake up next waiter
|
||||
nc, ((v.stackPred & LMASK) |
|
||||
((UMASK & (nc + RC_UNIT)) | (nc & TC_MASK))))) {
|
||||
v.source = INVALID_ID; // enable cascaded timeouts
|
||||
v.phase = vp;
|
||||
U.unpark(v.owner);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2561,52 +2569,35 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
|
||||
/**
|
||||
* Finds and locks a WorkQueue for an external submitter, or
|
||||
* throws RejectedExecutionException if shutdown or terminating.
|
||||
* @param r current ThreadLocalRandom.getProbe() value
|
||||
* throws RejectedExecutionException if shutdown
|
||||
* @param rejectOnShutdown true if RejectedExecutionException
|
||||
* should be thrown when shutdown (else only if terminating)
|
||||
* should be thrown when shutdown
|
||||
*/
|
||||
private WorkQueue submissionQueue(int r, boolean rejectOnShutdown) {
|
||||
int reuse; // nonzero if prefer create
|
||||
if ((reuse = r) == 0) {
|
||||
ThreadLocalRandom.localInit(); // initialize caller's probe
|
||||
final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) {
|
||||
int r;
|
||||
if ((r = ThreadLocalRandom.getProbe()) == 0) {
|
||||
ThreadLocalRandom.localInit(); // initialize caller's probe
|
||||
r = ThreadLocalRandom.getProbe();
|
||||
}
|
||||
for (int probes = 0; ; ++probes) {
|
||||
int n, i, id; WorkQueue[] qs; WorkQueue q;
|
||||
if ((qs = queues) == null)
|
||||
break;
|
||||
if ((n = qs.length) <= 0)
|
||||
for (;;) {
|
||||
WorkQueue q; WorkQueue[] qs; int n, id, i;
|
||||
if ((qs = queues) == null || (n = qs.length) <= 0)
|
||||
break;
|
||||
if ((q = qs[i = (id = r & EXTERNAL_ID_MASK) & (n - 1)]) == null) {
|
||||
WorkQueue w = new WorkQueue(null, id, 0, false);
|
||||
w.phase = id;
|
||||
boolean reject = ((lockRunState() & SHUTDOWN) != 0 &&
|
||||
rejectOnShutdown);
|
||||
if (!reject && queues == qs && qs[i] == null)
|
||||
q = qs[i] = w; // else lost race to install
|
||||
WorkQueue newq = new WorkQueue(null, id, 0, false);
|
||||
lockRunState();
|
||||
if (qs[i] == null && queues == qs)
|
||||
q = qs[i] = newq; // else lost race to install
|
||||
unlockRunState();
|
||||
if (q != null)
|
||||
return q;
|
||||
if (reject)
|
||||
}
|
||||
if (q != null && q.tryLockPhase()) {
|
||||
if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) {
|
||||
q.unlockPhase(); // check while q lock held
|
||||
break;
|
||||
reuse = 0;
|
||||
}
|
||||
if (reuse == 0 || !q.tryLockPhase()) { // move index
|
||||
if (reuse == 0) {
|
||||
if (probes >= n >> 1)
|
||||
reuse = r; // stop prefering free slot
|
||||
}
|
||||
else if (q != null)
|
||||
reuse = 0; // probe on collision
|
||||
r = ThreadLocalRandom.advanceProbe(r);
|
||||
}
|
||||
else if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) {
|
||||
q.unlockPhase(); // check while q lock held
|
||||
break;
|
||||
}
|
||||
else
|
||||
return q;
|
||||
}
|
||||
r = ThreadLocalRandom.advanceProbe(r); // move
|
||||
}
|
||||
throw new RejectedExecutionException();
|
||||
}
|
||||
@ -2620,24 +2611,12 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
}
|
||||
else { // find and lock queue
|
||||
internal = false;
|
||||
q = submissionQueue(ThreadLocalRandom.getProbe(), true);
|
||||
q = externalSubmissionQueue(true);
|
||||
}
|
||||
q.push(task, signalIfEmpty ? this : null, internal);
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns queue for an external submission, bypassing call to
|
||||
* submissionQueue if already established and unlocked.
|
||||
*/
|
||||
final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) {
|
||||
WorkQueue[] qs; WorkQueue q; int n;
|
||||
int r = ThreadLocalRandom.getProbe();
|
||||
return (((qs = queues) != null && (n = qs.length) > 0 &&
|
||||
(q = qs[r & EXTERNAL_ID_MASK & (n - 1)]) != null && r != 0 &&
|
||||
q.tryLockPhase()) ? q : submissionQueue(r, rejectOnShutdown));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns queue for an external thread, if one exists that has
|
||||
* possibly ever submitted to the given pool (nonzero probe), or
|
||||
@ -3310,11 +3289,14 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
* @since 19
|
||||
*/
|
||||
public int setParallelism(int size) {
|
||||
int prevSize;
|
||||
if (size < 1 || size > MAX_CAP)
|
||||
throw new IllegalArgumentException();
|
||||
if ((config & PRESET_SIZE) != 0)
|
||||
throw new UnsupportedOperationException("Cannot override System property");
|
||||
return getAndSetParallelism(size);
|
||||
if ((prevSize = getAndSetParallelism(size)) < size)
|
||||
signalWork(null, 0); // trigger worker activation
|
||||
return prevSize;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -43,8 +43,8 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.lang.CaseFolding;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.util.regex.CaseFolding;
|
||||
import jdk.internal.util.regex.Grapheme;
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.internal.lang;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
/**
|
||||
* Utility class that handles Unicode case folding properties defined in
|
||||
* CasingFolding.txt, including 1:M full case folding.
|
||||
*/
|
||||
public final class CaseFolding {
|
||||
|
||||
private CaseFolding() {}
|
||||
|
||||
/**
|
||||
* Tests whether the specified code point has a folding mapping entry defined.
|
||||
*
|
||||
* @param cp
|
||||
* the Unicode code point to test
|
||||
* @return {@code true} if the given code point has a case folding mapping entry
|
||||
* defined in (@code caseFoldingMap}, {@code false} otherwise
|
||||
*/
|
||||
public static boolean isDefined(int cp) {
|
||||
return getDefined(cp) != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the case-folded form of the specified code point according
|
||||
* to the Unicode case folding mappings.
|
||||
* <p>
|
||||
* If the code point has no case folding mapping defined, this method returns
|
||||
* the original code point.
|
||||
*
|
||||
* Possible combinations of the returning case-folding form as a long value
|
||||
*
|
||||
* +---+---------+--------+---------+--------+--------+
|
||||
* | 1:1 mapping | 0000 | 0000 | 000x | xxxx | 0041 => 0061 or 1E921 => 1E943
|
||||
* +---+---------+--------+---------+--------+--------+
|
||||
* | 1:2 mapping | 0002 | 0000 | xxxx | xxxx | FB02 => 0066 006C
|
||||
* +---+---------+--------+---------+--------+--------+
|
||||
* | 1:3 mapping | 0003 | xxxx | xxxx | xxxx | FB03 => 0066 0066 0069
|
||||
* +---+---------+--------+---------+--------+--------+
|
||||
*
|
||||
* @param cp
|
||||
* the Unicode code point to fold
|
||||
* @return a long value representing the case-folded form of the input
|
||||
* code point, encoded as TBD
|
||||
*/
|
||||
public static long fold(int cp) {
|
||||
var fold = getDefined(cp);
|
||||
return fold == -1 ? cp : fold;
|
||||
}
|
||||
|
||||
public static boolean isSingleCodePoint(long fold) {
|
||||
return (fold >> 48) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive
|
||||
* matching, according to the
|
||||
* <a href="https://www.unicode.org/reports/tr18/#Simple_Loose_Matches">Simple Loose Matches</a>
|
||||
* rule defined in Unicode Technical Standard #18: Unicode Regular Expressions.
|
||||
* <p>
|
||||
* To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must
|
||||
* be applied to literals and (optionally) to character classes. When applied to character classes, each
|
||||
* character class is expected to be closed under simple case folding. See the standard for the
|
||||
* detailed explanation and example of "closed".
|
||||
* <p>
|
||||
* RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should
|
||||
* <ol>
|
||||
* <li>Provide at least the simple, default Unicode case-insensitive matching, and</li>
|
||||
* <li>Specify which character properties or constructs are closed under the matching.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching:
|
||||
* back-refs, string slice (sequences), single, family(char-property) and class range. Single and
|
||||
* family may appears independently or within a class.
|
||||
* <p>
|
||||
* For loose/case-insensitive matching, the back-refs, slices and singles apply {@code toUpperCase} and
|
||||
* {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for
|
||||
* matching.
|
||||
* <p>
|
||||
* The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5,
|
||||
* if their behavior is clearly specified.
|
||||
* <p>
|
||||
* This method addresses that requirement for the "range" construct within in character class by computing
|
||||
* the additional characters that should be included to close the range under simple case folding:
|
||||
* <p>
|
||||
* For each character in the input range {@code [start, end]} (inclusive), if the character has a simple
|
||||
* case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped
|
||||
* character is not already in the range, then that mapped character (typically lowercase) is added to
|
||||
* the expansion set.
|
||||
* <p>
|
||||
* This allows regex character class "range" implementation to use the returned expansion set to support
|
||||
* additional case-insensitive matching, without duplicating characters already covered by the existing
|
||||
* regex range implementation. The expectation is the matching is done using both the uppercase and
|
||||
* lowercase forms of the input character, for example
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
|
||||
* inRange(lower, Character.toLower(ch), upper) ||
|
||||
* additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
|
||||
* additionalClosingCharacters.contains(Character.toUpperCase(ch))
|
||||
* }</pre>
|
||||
*
|
||||
* @param start the starting code point of the character range
|
||||
* @param end the ending code point of the character range
|
||||
* @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding
|
||||
* those already in the range
|
||||
* @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches
|
||||
*/
|
||||
public static int[] getClassRangeClosingCharacters(int start, int end) {
|
||||
int[] expanded = new int[expanded_case_cps.length];
|
||||
int off = 0;
|
||||
for (int cp : expanded_case_cps) {
|
||||
if (cp >= start && cp <= end) {
|
||||
int folding = expanded_case_map.get(cp);
|
||||
if (folding < start || folding > end) {
|
||||
expanded[off++] = folding;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Arrays.copyOf(expanded, off);
|
||||
}
|
||||
|
||||
private static final Map<Integer, Integer> expanded_case_map = Map.ofEntries(
|
||||
%%%Expanded_Case_Map_Entries
|
||||
);
|
||||
|
||||
private static final int[] expanded_case_cps = expanded_case_map.keySet()
|
||||
.stream()
|
||||
.mapToInt(Integer::intValue)
|
||||
.toArray();
|
||||
|
||||
private static final int HASH_CP = 0;
|
||||
private static final int HASH_INDEX = 1;
|
||||
private static final int HASH_NEXT = 2;
|
||||
|
||||
private static int[][] hashKeys(int[] keys) {
|
||||
var hashes = new int[keys.length << 1][3]; // cp + hash + next
|
||||
var off = keys.length;
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
var cp = keys[i];
|
||||
var hash = cp % keys.length;
|
||||
while (hashes[hash][HASH_CP] != 0) {
|
||||
var next = hashes[hash][HASH_NEXT];
|
||||
if (next == 0) {
|
||||
hashes[hash][HASH_NEXT] = off;
|
||||
hash = off++;
|
||||
break;
|
||||
} else {
|
||||
hash = next;
|
||||
}
|
||||
}
|
||||
hashes[hash][HASH_CP] = cp;
|
||||
hashes[hash][HASH_INDEX] = i;
|
||||
}
|
||||
return Arrays.copyOf(hashes, off);
|
||||
}
|
||||
|
||||
private static long getDefined(int cp) {
|
||||
var hashes = CASE_FOLDING_HASHES;
|
||||
var length = CASE_FOLDING_CPS.length; // hashed based on total defined.
|
||||
var hash = cp % length;
|
||||
while (hashes[hash][HASH_CP] != cp) {
|
||||
var next = hashes[hash][HASH_NEXT];
|
||||
if (next == 0) {
|
||||
return -1; // hash miss
|
||||
}
|
||||
hash = next;
|
||||
}
|
||||
var index = hashes[hash][HASH_INDEX];
|
||||
return CASE_FOLDING_VALUES[index];
|
||||
}
|
||||
|
||||
%%%Entries
|
||||
|
||||
private static final int[][] CASE_FOLDING_HASHES = hashKeys(CASE_FOLDING_CPS);
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
@@COMPANY_NAME@@-@@VERSION_STRING@@-@@VERSION_DATE@@
|
||||
@ -225,6 +225,7 @@ public final class ModulePatcher {
|
||||
private final ModuleReference mref;
|
||||
private final URL delegateCodeSourceURL;
|
||||
private volatile ModuleReader delegate;
|
||||
private volatile boolean closed;
|
||||
|
||||
/**
|
||||
* Creates the ModuleReader to reads resources in a patched module.
|
||||
@ -291,6 +292,15 @@ public final class ModulePatcher {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an IOException if the ModuleReader is closed.
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("ModuleReader is closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a resources in the patch locations. Returns null if not found
|
||||
* or the name is "module-info.class" as that cannot be overridden.
|
||||
@ -310,7 +320,7 @@ public final class ModulePatcher {
|
||||
* Finds a resource of the given name in the patched module.
|
||||
*/
|
||||
public Resource findResource(String name) throws IOException {
|
||||
|
||||
assert !closed : "module reader is closed";
|
||||
// patch locations
|
||||
Resource r = findResourceInPatch(name);
|
||||
if (r != null)
|
||||
@ -354,6 +364,7 @@ public final class ModulePatcher {
|
||||
|
||||
@Override
|
||||
public Optional<URI> find(String name) throws IOException {
|
||||
ensureOpen();
|
||||
Resource r = findResourceInPatch(name);
|
||||
if (r != null) {
|
||||
URI uri = URI.create(r.getURL().toString());
|
||||
@ -365,6 +376,7 @@ public final class ModulePatcher {
|
||||
|
||||
@Override
|
||||
public Optional<InputStream> open(String name) throws IOException {
|
||||
ensureOpen();
|
||||
Resource r = findResourceInPatch(name);
|
||||
if (r != null) {
|
||||
return Optional.of(r.getInputStream());
|
||||
@ -375,6 +387,7 @@ public final class ModulePatcher {
|
||||
|
||||
@Override
|
||||
public Optional<ByteBuffer> read(String name) throws IOException {
|
||||
ensureOpen();
|
||||
Resource r = findResourceInPatch(name);
|
||||
if (r != null) {
|
||||
ByteBuffer bb = r.getByteBuffer();
|
||||
@ -398,6 +411,7 @@ public final class ModulePatcher {
|
||||
|
||||
@Override
|
||||
public Stream<String> list() throws IOException {
|
||||
ensureOpen();
|
||||
Stream<String> s = delegate().list();
|
||||
for (ResourceFinder finder : finders) {
|
||||
s = Stream.concat(s, finder.list());
|
||||
@ -407,6 +421,10 @@ public final class ModulePatcher {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
closeAll(finders);
|
||||
delegate().close();
|
||||
}
|
||||
|
||||
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.internal.util.regex;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
public final class CaseFolding {
|
||||
|
||||
private static final Map<Integer, Integer> expanded_case_map = Map.ofEntries(
|
||||
%%%Entries
|
||||
);
|
||||
|
||||
private static final int[] expanded_case_cps = expanded_case_map.keySet()
|
||||
.stream()
|
||||
.mapToInt(Integer::intValue)
|
||||
.toArray();
|
||||
|
||||
private CaseFolding() {}
|
||||
|
||||
/**
|
||||
* Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive
|
||||
* matching, according to the
|
||||
* <a href="https://www.unicode.org/reports/tr18/#Simple_Loose_Matches">Simple Loose Matches</a>
|
||||
* rule defined in Unicode Technical Standard #18: Unicode Regular Expressions.
|
||||
* <p>
|
||||
* To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must
|
||||
* be applied to literals and (optionally) to character classes. When applied to character classes, each
|
||||
* character class is expected to be closed under simple case folding. See the standard for the
|
||||
* detailed explanation and example of "closed".
|
||||
* <p>
|
||||
* RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should
|
||||
* <ol>
|
||||
* <li>Provide at least the simple, default Unicode case-insensitive matching, and</li>
|
||||
* <li>Specify which character properties or constructs are closed under the matching.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching:
|
||||
* back-refs, string slice (sequences), single, family(char-property) and class range. Single and
|
||||
* family may appears independently or within a class.
|
||||
* <p>
|
||||
* For loose/case-insensitive matching, the back-refs, slices and singles apply {code toUpperCase} and
|
||||
* {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for
|
||||
* matching.
|
||||
* <p>
|
||||
* The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5,
|
||||
* if their behavior is clearly specified.
|
||||
* <p>
|
||||
* This method addresses that requirement for the "range" construct within in character class by computing
|
||||
* the additional characters that should be included to close the range under simple case folding:
|
||||
* <p>
|
||||
* For each character in the input range {@code [start, end]} (inclusive), if the character has a simple
|
||||
* case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped
|
||||
* character is not already in the range, then that mapped character (typically lowercase) is added to
|
||||
* the expansion set.
|
||||
* <p>
|
||||
* This allows regex character class "range" implementation to use the returned expansion set to support
|
||||
* additional case-insensitive matching, without duplicating characters already covered by the existing
|
||||
* regex range implementation. The expectation is the matching is done using both the uppercase and
|
||||
* lowercase forms of the input character, for example
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
|
||||
* inRange(lower, Character.toLower(ch), upper) ||
|
||||
* additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
|
||||
* additionalClosingCharacters.contains(Character.toUpperCase(ch))
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches
|
||||
* @param start the starting code point of the character range
|
||||
* @param end the ending code point of the character range
|
||||
* @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding
|
||||
* those already in the range
|
||||
*/
|
||||
public static int[] getClassRangeClosingCharacters(int start, int end) {
|
||||
int[] expanded = new int[expanded_case_cps.length];
|
||||
int off = 0;
|
||||
for (int cp : expanded_case_cps) {
|
||||
if (cp >= start && cp <= end) {
|
||||
int folding = expanded_case_map.get(cp);
|
||||
if (folding < start || folding > end) {
|
||||
expanded[off++] = folding;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Arrays.copyOf(expanded, off);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -35,6 +35,8 @@ import java.lang.reflect.TypeVariable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import sun.reflect.annotation.AnnotationSupport;
|
||||
import sun.reflect.annotation.TypeAnnotationParser;
|
||||
import sun.reflect.annotation.AnnotationType;
|
||||
@ -125,18 +127,24 @@ public class TypeVariableImpl<D extends GenericDeclaration>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code GenericDeclaration} object representing the
|
||||
* Returns a {@code GenericDeclaration} object representing the
|
||||
* generic declaration that declared this type variable.
|
||||
*
|
||||
* @return the generic declaration that declared this type variable.
|
||||
* @return a generic declaration that declared this type variable.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public D getGenericDeclaration() {
|
||||
assert genericDeclaration instanceof Class<?> ||
|
||||
genericDeclaration instanceof Method ||
|
||||
genericDeclaration instanceof Constructor : "Unexpected kind of GenericDeclaration";
|
||||
return genericDeclaration;
|
||||
// If the `genericDeclaration` instance is mutable, we need to make a copy.
|
||||
return switch (genericDeclaration) {
|
||||
case Method method -> (D) ReflectionFactory.getReflectionFactory().copyMethod(method);
|
||||
case Constructor<?> ctor -> (D) ReflectionFactory.getReflectionFactory().copyConstructor(ctor);
|
||||
default -> genericDeclaration;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -476,7 +476,7 @@ public enum SourceVersion {
|
||||
* @since 26
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.oracle.com/javase/specs/jls/se26/html/index.html">
|
||||
* href="https://docs.oracle.com/en/java/javase/26/docs/specs/jls/index.html">
|
||||
* <cite>The Java Language Specification, Java SE 26 Edition</cite></a>
|
||||
*/
|
||||
RELEASE_26,
|
||||
|
||||
@ -293,6 +293,9 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return the data for the specified pixel.
|
||||
* @see #setDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code obj} is too small to hold the output.
|
||||
*/
|
||||
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -401,15 +404,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all samples for the specified pixel in an int array.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param iArray If non-null, returns the samples in this array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return the samples for the specified pixel.
|
||||
* @see #setPixel(int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -434,26 +432,19 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all samples for the specified rectangle of pixels in
|
||||
* an int array, one sample per data array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param iArray If non-null, returns the samples in this array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return the samples for the pixels within the specified region.
|
||||
* @see #setPixels(int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or {@code w} or {@code h} is negative.
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
@ -484,16 +475,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns as int the sample in a specified band for the pixel
|
||||
* located at (x,y).
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to return
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return the sample in the specified band for the specified pixel.
|
||||
* @see #setSample(int, int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public int getSample(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -508,16 +493,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sample in a specified band
|
||||
* for the pixel located at (x,y) as a float.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to return
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return a float value that represents the sample in the specified
|
||||
* band for the specified pixel.
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public float getSampleFloat(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -532,16 +511,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sample in a specified band
|
||||
* for a pixel located at (x,y) as a double.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to return
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return a double value that represents the sample in the specified
|
||||
* band for the specified pixel.
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public double getSampleDouble(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -556,25 +529,16 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the samples in a specified band for the specified rectangle
|
||||
* of pixels in an int array, one sample per data array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param b The band to return
|
||||
* @param iArray If non-null, returns the samples in this array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return the samples in the specified band for the pixels within
|
||||
* the specified region.
|
||||
* @see #setSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
|
||||
if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) {
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
}
|
||||
@ -633,6 +597,9 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
* object
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code obj} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code obj} is too small to hold the input.
|
||||
*/
|
||||
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -700,14 +667,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a pixel in the DataBuffer using an int array of samples for input.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param iArray The input samples in an int array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getPixel(int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -722,25 +685,19 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all samples for a rectangle of pixels from an int array containing
|
||||
* one sample per array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param iArray The input samples in an int array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getPixels(int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or {@code w} or {@code h} is negative.
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
@ -763,16 +720,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the DataBuffer using an int for input.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to set
|
||||
* @param s The input sample as an int
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b, int s,
|
||||
DataBuffer data) {
|
||||
@ -786,16 +737,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the DataBuffer using a float for input.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to set
|
||||
* @param s The input sample as a float
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b,
|
||||
float s ,
|
||||
@ -810,16 +755,10 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the DataBuffer using a double for input.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to set
|
||||
* @param s The input sample as a double
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b,
|
||||
double s,
|
||||
@ -834,23 +773,16 @@ public final class BandedSampleModel extends ComponentSampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the samples in the specified band for the specified rectangle
|
||||
* of pixels from an int array containing one sample per data array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param b The band to set
|
||||
* @param iArray The input sample array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
|
||||
if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) {
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -100,10 +100,7 @@ public class BufferedImage extends java.awt.Image
|
||||
* Represents an image with 8-bit RGBA color components packed into
|
||||
* integer pixels. The image has a {@code DirectColorModel}
|
||||
* with alpha. The color data in this image is considered not to be
|
||||
* premultiplied with alpha. When this type is used as the
|
||||
* {@code imageType} argument to a {@code BufferedImage}
|
||||
* constructor, the created image is consistent with images
|
||||
* created in the JDK1.1 and earlier releases.
|
||||
* premultiplied with alpha.
|
||||
*/
|
||||
public static final int TYPE_INT_ARGB = 2;
|
||||
|
||||
|
||||
@ -600,7 +600,7 @@ public class ComponentSampleModel extends SampleModel
|
||||
* @return the data of the specified pixel
|
||||
* @see #setDataElements(int, int, Object, DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the output.
|
||||
*/
|
||||
@ -707,20 +707,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all samples for the specified pixel in an int array,
|
||||
* one sample per array element.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if
|
||||
* the coordinates are not in bounds.
|
||||
* @param x the X coordinate of the pixel location
|
||||
* @param y the Y coordinate of the pixel location
|
||||
* @param iArray If non-null, returns the samples in this array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return the samples of the specified pixel.
|
||||
* @see #setPixel(int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if iArray is too small to hold the output.
|
||||
* not in bounds, or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -742,26 +732,19 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all samples for the specified rectangle of pixels in
|
||||
* an int array, one sample per array element.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if
|
||||
* the coordinates are not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param iArray If non-null, returns the samples in this array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return the samples of the pixels within the specified region.
|
||||
* @see #setPixels(int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || y > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || (w < 0) || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || (h < 0) || y >= height || y > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
@ -790,16 +773,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns as int the sample in a specified band for the pixel
|
||||
* located at (x,y).
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if
|
||||
* the coordinates are not in bounds.
|
||||
* @param x the X coordinate of the pixel location
|
||||
* @param y the Y coordinate of the pixel location
|
||||
* @param b the band to return
|
||||
* @param data the {@code DataBuffer} containing the image data
|
||||
* @return the sample in a specified band for the specified pixel
|
||||
* @see #setSample(int, int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public int getSample(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -814,16 +791,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sample in a specified band
|
||||
* for the pixel located at (x,y) as a float.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be
|
||||
* thrown if the coordinates are not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to return
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return a float value representing the sample in the specified
|
||||
* band for the specified pixel.
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public float getSampleFloat(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -837,18 +808,11 @@ public class ComponentSampleModel extends SampleModel
|
||||
bandOffsets[b]);
|
||||
return sample;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sample in a specified band
|
||||
* for a pixel located at (x,y) as a double.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be
|
||||
* thrown if the coordinates are not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to return
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @return a double value representing the sample in the specified
|
||||
* band for the specified pixel.
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public double getSampleDouble(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -864,25 +828,16 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the samples in a specified band for the specified rectangle
|
||||
* of pixels in an int array, one sample per data array element.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if
|
||||
* the coordinates are not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w the width of the pixel rectangle
|
||||
* @param h the height of the pixel rectangle
|
||||
* @param b the band to return
|
||||
* @param iArray if non-{@code null}, returns the samples
|
||||
* in this array
|
||||
* @param data the {@code DataBuffer} containing the image data
|
||||
* @return the samples in the specified band of the specified pixel
|
||||
* @see #setSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
|
||||
if ((x < 0) || (y < 0) || (w < 0) || ( h < 0) || (x + w > width) || (y + h > height)) {
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
}
|
||||
@ -943,6 +898,9 @@ public class ComponentSampleModel extends SampleModel
|
||||
* @param obj a primitive array containing pixel data
|
||||
* @param data the DataBuffer containing the image data
|
||||
* @see #getDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code obj} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the input.
|
||||
*/
|
||||
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -1011,15 +969,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a pixel in the {@code DataBuffer} using an int array of
|
||||
* samples for input. An {@code ArrayIndexOutOfBoundsException}
|
||||
* might be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param iArray The input samples in an int array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getPixel(int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -1034,25 +987,19 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all samples for a rectangle of pixels from an int array containing
|
||||
* one sample per array element.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if the
|
||||
* coordinates are not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param iArray The input samples in an int array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getPixels(int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
@ -1075,16 +1022,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the {@code DataBuffer} using an int for input.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if the
|
||||
* coordinates are not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b the band to set
|
||||
* @param s the input sample as an int
|
||||
* @param data the DataBuffer containing the image data
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b, int s,
|
||||
DataBuffer data) {
|
||||
@ -1098,16 +1039,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the {@code DataBuffer} using a float for input.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if
|
||||
* the coordinates are not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to set
|
||||
* @param s The input sample as a float
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b,
|
||||
float s ,
|
||||
@ -1123,16 +1058,10 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the {@code DataBuffer} using a double for input.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if
|
||||
* the coordinates are not in bounds.
|
||||
* @param x The X coordinate of the pixel location
|
||||
* @param y The Y coordinate of the pixel location
|
||||
* @param b The band to set
|
||||
* @param s The input sample as a double
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b,
|
||||
double s,
|
||||
@ -1148,23 +1077,16 @@ public class ComponentSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the samples in the specified band for the specified rectangle
|
||||
* of pixels from an int array containing one sample per data array element.
|
||||
* An {@code ArrayIndexOutOfBoundsException} might be thrown if the
|
||||
* coordinates are not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location
|
||||
* @param y The Y coordinate of the upper left pixel location
|
||||
* @param w The width of the pixel rectangle
|
||||
* @param h The height of the pixel rectangle
|
||||
* @param b The band to set
|
||||
* @param iArray The input samples in an int array
|
||||
* @param data The DataBuffer containing the image data
|
||||
* @see #getSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
|
||||
if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) {
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.awt.image;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The {@code Kernel} class defines a matrix that describes how a
|
||||
@ -59,7 +60,7 @@ public class Kernel implements Cloneable {
|
||||
* @param width width of the kernel
|
||||
* @param height height of the kernel
|
||||
* @param data kernel data in row major order
|
||||
* @throws IllegalArgumentException if {@code data} is null
|
||||
* @throws NullPointerException if {@code data} is null
|
||||
* @throws IllegalArgumentException if {@code width} or {@code height}
|
||||
* is not positive
|
||||
* @throws IllegalArgumentException if product of {@code width} and
|
||||
@ -69,9 +70,7 @@ public class Kernel implements Cloneable {
|
||||
* {@code height}
|
||||
*/
|
||||
public Kernel(int width, int height, float[] data) {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Data must not be null");
|
||||
}
|
||||
Objects.requireNonNull(data, "Data must not be null");
|
||||
if ((width <= 0) || (height <= 0)) {
|
||||
throw new IllegalArgumentException("Invalid width or height");
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* coordinates are not in bounds.
|
||||
* @param x the X coordinate of the specified pixel
|
||||
* @param y the Y coordinate of the specified pixel
|
||||
* @param b the band to return, which is assumed to be 0
|
||||
* @param b the band to return, which must be 0
|
||||
* @param data the {@code DataBuffer} containing the image
|
||||
* data
|
||||
* @return the specified band containing the sample of the specified
|
||||
@ -374,7 +374,7 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* coordinates are not in bounds.
|
||||
* @param x the X coordinate of the specified pixel
|
||||
* @param y the Y coordinate of the specified pixel
|
||||
* @param b the band to return, which is assumed to be 0
|
||||
* @param b the band to set, which must be 0
|
||||
* @param s the input sample as an {@code int}
|
||||
* @param data the {@code DataBuffer} where image data is stored
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
@ -448,6 +448,9 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* not in bounds, or if {@code obj} is not {@code null} or
|
||||
* not large enough to hold the pixel data
|
||||
* @see #setDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {code obj} is too small to hold the output.
|
||||
*/
|
||||
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -527,8 +530,11 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* @param data the {@code DataBuffer} where image data is stored
|
||||
* @return an array containing the specified pixel.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates
|
||||
* are not in bounds
|
||||
* are not in bounds, or if {@code iArray} is too small to hold the output.
|
||||
* @see #setPixel(int, int, int[], DataBuffer)
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -588,6 +594,9 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* @param obj a primitive array containing pixel data
|
||||
* @param data the {@code DataBuffer} containing the image data
|
||||
* @see #getDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code obj} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code obj} is too small to hold the input.
|
||||
*/
|
||||
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -638,6 +647,9 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* @param iArray the input pixel in an {@code int} array
|
||||
* @param data the {@code DataBuffer} containing the image data
|
||||
* @see #getPixel(int, int, int[], DataBuffer)
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
|
||||
@ -231,9 +231,9 @@ public abstract class SampleModel
|
||||
* @return the samples for the specified pixel.
|
||||
* @see #setPixel(int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if iArray is too small to hold the output.
|
||||
* not in bounds, or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
|
||||
@ -293,9 +293,9 @@ public abstract class SampleModel
|
||||
* @see java.awt.image.DataBuffer
|
||||
* @see #setDataElements(int, int, Object, DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the output.
|
||||
* not in bounds, or if {@code obj} is too small to hold the output.
|
||||
*/
|
||||
public abstract Object getDataElements(int x, int y,
|
||||
Object obj, DataBuffer data);
|
||||
@ -347,9 +347,10 @@ public abstract class SampleModel
|
||||
* @see #setDataElements(int, int, int, int, Object, DataBuffer)
|
||||
* @see java.awt.image.DataBuffer
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the output.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code obj} is too small to hold the output.
|
||||
*/
|
||||
public Object getDataElements(int x, int y, int w, int h,
|
||||
Object obj, DataBuffer data) {
|
||||
@ -362,8 +363,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -528,7 +529,7 @@ public abstract class SampleModel
|
||||
* @see #getDataElements(int, int, Object, DataBuffer)
|
||||
* @see java.awt.image.DataBuffer
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code obj} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the input.
|
||||
*/
|
||||
@ -577,7 +578,7 @@ public abstract class SampleModel
|
||||
* @see #getDataElements(int, int, int, int, Object, DataBuffer)
|
||||
* @see java.awt.image.DataBuffer
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code obj} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the input.
|
||||
*/
|
||||
@ -592,8 +593,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -695,9 +696,9 @@ public abstract class SampleModel
|
||||
* @return the samples for the specified pixel.
|
||||
* @see #setPixel(int, int, float[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if fArray is too small to hold the output.
|
||||
* not in bounds, or if {@code fArray} is too small to hold the output.
|
||||
*/
|
||||
public float[] getPixel(int x, int y, float[] fArray,
|
||||
DataBuffer data) {
|
||||
@ -726,9 +727,9 @@ public abstract class SampleModel
|
||||
* @return the samples for the specified pixel.
|
||||
* @see #setPixel(int, int, double[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if dArray is too small to hold the output.
|
||||
* not in bounds, or if {@code dArray} is too small to hold the output.
|
||||
*/
|
||||
public double[] getPixel(int x, int y, double[] dArray,
|
||||
DataBuffer data) {
|
||||
@ -760,9 +761,10 @@ public abstract class SampleModel
|
||||
* @return the samples for the specified region of pixels.
|
||||
* @see #setPixels(int, int, int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if iArray is too small to hold the output.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
@ -772,8 +774,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -808,9 +810,10 @@ public abstract class SampleModel
|
||||
* @return the samples for the specified region of pixels.
|
||||
* @see #setPixels(int, int, int, int, float[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if fArray is too small to hold the output.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code fArray} is too small to hold the output.
|
||||
*/
|
||||
public float[] getPixels(int x, int y, int w, int h,
|
||||
float[] fArray, DataBuffer data) {
|
||||
@ -820,8 +823,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -856,9 +859,10 @@ public abstract class SampleModel
|
||||
* @return the samples for the specified region of pixels.
|
||||
* @see #setPixels(int, int, int, int, double[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if dArray is too small to hold the output.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code dArray} is too small to hold the output.
|
||||
*/
|
||||
public double[] getPixels(int x, int y, int w, int h,
|
||||
double[] dArray, DataBuffer data) {
|
||||
@ -867,8 +871,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -903,7 +907,7 @@ public abstract class SampleModel
|
||||
* @return the sample in a specified band for the specified pixel.
|
||||
* @see #setSample(int, int, int, int, DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
@ -921,7 +925,7 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return the sample in a specified band for the specified pixel.
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
@ -943,7 +947,7 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return the sample in a specified band for the specified pixel.
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
@ -971,10 +975,10 @@ public abstract class SampleModel
|
||||
* of pixels.
|
||||
* @see #setSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds, or if iArray is too small to
|
||||
* hold the output.
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
@ -983,8 +987,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x1 < x || x1 > width ||
|
||||
y < 0 || y1 < y || y1 > height)
|
||||
if (x < 0 || w < 0 || x1 < x || x1 > width ||
|
||||
y < 0 || h < 0 || y1 < y || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -1019,10 +1023,10 @@ public abstract class SampleModel
|
||||
* of pixels.
|
||||
* @see #setSamples(int, int, int, int, int, float[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds, or if fArray is too small to
|
||||
* hold the output.
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public float[] getSamples(int x, int y, int w, int h,
|
||||
int b, float[] fArray,
|
||||
@ -1032,8 +1036,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x1 < x || x1 > width ||
|
||||
y < 0 || y1 < y || y1 > height)
|
||||
if (x < 0 || w < 0 || x1 < x || x1 > width ||
|
||||
y < 0 || h < 0 || y1 < y || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates");
|
||||
}
|
||||
@ -1068,10 +1072,10 @@ public abstract class SampleModel
|
||||
* of pixels.
|
||||
* @see #setSamples(int, int, int, int, int, double[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds, or if dArray is too small to
|
||||
* hold the output.
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code dArray} is too small to hold the output.
|
||||
*/
|
||||
public double[] getSamples(int x, int y, int w, int h,
|
||||
int b, double[] dArray,
|
||||
@ -1081,8 +1085,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x1 < x || x1 > width ||
|
||||
y < 0 || y1 < y || y1 > height)
|
||||
if (x < 0 || w < 0 || x1 < x || x1 > width ||
|
||||
y < 0 || h < 0 || y1 < y || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates");
|
||||
}
|
||||
@ -1111,9 +1115,9 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixel(int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if iArray or data is null.
|
||||
* @throws NullPointerException if {@code iArray} or {code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if iArray is too small to hold the input.
|
||||
* not in bounds, or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
|
||||
@ -1131,9 +1135,9 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixel(int, int, float[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if fArray or data is null.
|
||||
* @throws NullPointerException if {@code fArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if fArray is too small to hold the input.
|
||||
* not in bounds, or if {@code fArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y, float[] fArray, DataBuffer data) {
|
||||
|
||||
@ -1150,9 +1154,9 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixel(int, int, double[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if dArray or data is null.
|
||||
* @throws NullPointerException if {@code dArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if fArray is too small to hold the input.
|
||||
* not in bounds, or if {@code dArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y, double[] dArray, DataBuffer data) {
|
||||
|
||||
@ -1173,9 +1177,10 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixels(int, int, int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if iArray or data is null.
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if iArray is too small to hold the input.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
@ -1183,8 +1188,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -1211,9 +1216,10 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixels(int, int, int, int, float[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if fArray or data is null.
|
||||
* @throws NullPointerException if {@code fArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if fArray is too small to hold the input.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code fArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
float[] fArray, DataBuffer data) {
|
||||
@ -1221,8 +1227,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -1249,9 +1255,10 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixels(int, int, int, int, double[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if dArray or data is null.
|
||||
* @throws NullPointerException if {@code dArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if dArray is too small to hold the input.
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code dArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
double[] dArray, DataBuffer data) {
|
||||
@ -1259,8 +1266,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -1286,7 +1293,7 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
@ -1310,7 +1317,7 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
@ -1338,7 +1345,7 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if data is null.
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
@ -1364,10 +1371,10 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if iArray or data is null.
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds, or if iArray is too small to
|
||||
* hold the input.
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
@ -1375,8 +1382,8 @@ public abstract class SampleModel
|
||||
int Offset=0;
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -1402,10 +1409,10 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSamples(int, int, int, int, int, float[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if fArray or data is null.
|
||||
* @throws NullPointerException if {@code fArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds, or if fArray is too small to
|
||||
* hold the input.
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code fArray} is too small to hold the input.
|
||||
*/
|
||||
public void setSamples(int x, int y, int w, int h, int b,
|
||||
float[] fArray, DataBuffer data) {
|
||||
@ -1413,8 +1420,8 @@ public abstract class SampleModel
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
@ -1440,10 +1447,10 @@ public abstract class SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSamples(int, int, int, int, int, double[], DataBuffer)
|
||||
*
|
||||
* @throws NullPointerException if dArray or data is null.
|
||||
* @throws NullPointerException if {@code dArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds, or if dArray is too small to
|
||||
* hold the input.
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code dArray} is too small to hold the input.
|
||||
*/
|
||||
public void setSamples(int x, int y, int w, int h, int b,
|
||||
double[] dArray, DataBuffer data) {
|
||||
@ -1452,8 +1459,8 @@ public abstract class SampleModel
|
||||
int y1 = y + h;
|
||||
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid coordinates.");
|
||||
}
|
||||
|
||||
@ -357,6 +357,9 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return the data for the specified pixel.
|
||||
* @see #setDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the output.
|
||||
*/
|
||||
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -416,15 +419,10 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all samples in for the specified pixel in an int array.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location.
|
||||
* @param y The Y coordinate of the pixel location.
|
||||
* @param iArray If non-null, returns the samples in this array
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return all samples for the specified pixel.
|
||||
* @see #setPixel(int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int [] getPixel(int x, int y, int[] iArray, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -446,26 +444,20 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all samples for the specified rectangle of pixels in
|
||||
* an int array, one sample per array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location.
|
||||
* @param y The Y coordinate of the upper left pixel location.
|
||||
* @param w The width of the pixel rectangle.
|
||||
* @param h The height of the pixel rectangle.
|
||||
* @param iArray If non-null, returns the samples in this array.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return all samples for the specified region of pixels.
|
||||
* @see #setPixels(int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
@Override
|
||||
public int[] getPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
@ -493,17 +485,10 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns as int the sample in a specified band for the pixel
|
||||
* located at (x,y).
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location.
|
||||
* @param y The Y coordinate of the pixel location.
|
||||
* @param b The band to return.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return the sample in a specified band for the specified
|
||||
* pixel.
|
||||
* @see #setSample(int, int, int, int, DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public int getSample(int x, int y, int b, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
@ -516,25 +501,16 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the samples for a specified band for the specified rectangle
|
||||
* of pixels in an int array, one sample per array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location.
|
||||
* @param y The Y coordinate of the upper left pixel location.
|
||||
* @param w The width of the pixel rectangle.
|
||||
* @param h The height of the pixel rectangle.
|
||||
* @param b The band to return.
|
||||
* @param iArray If non-null, returns the samples in this array.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @return the samples for the specified band for the specified
|
||||
* region of pixels.
|
||||
* @see #setSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the output.
|
||||
*/
|
||||
public int[] getSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
|
||||
if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) {
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
}
|
||||
@ -592,6 +568,9 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
* @param obj A primitive array containing pixel data.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getDataElements(int, int, Object, DataBuffer)
|
||||
* @throws NullPointerException if {@code obj} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if obj is too small to hold the input.
|
||||
*/
|
||||
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
|
||||
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
|
||||
@ -624,14 +603,10 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a pixel in the DataBuffer using an int array of samples for input.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location.
|
||||
* @param y The Y coordinate of the pixel location.
|
||||
* @param iArray The input samples in an int array.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixel(int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixel(int x, int y,
|
||||
int[] iArray,
|
||||
@ -650,25 +625,19 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all samples for a rectangle of pixels from an int array containing
|
||||
* one sample per array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location.
|
||||
* @param y The Y coordinate of the upper left pixel location.
|
||||
* @param w The width of the pixel rectangle.
|
||||
* @param h The height of the pixel rectangle.
|
||||
* @param iArray The input samples in an int array.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getPixels(int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates are
|
||||
* not in bounds, or {@code w} or {@code h} is negative
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
int[] iArray, DataBuffer data) {
|
||||
int x1 = x + w;
|
||||
int y1 = y + h;
|
||||
|
||||
if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
|
||||
y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
@ -692,17 +661,11 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a sample in the specified band for the pixel located at (x,y)
|
||||
* in the DataBuffer using an int for input.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the pixel location.
|
||||
* @param y The Y coordinate of the pixel location.
|
||||
* @param b The band to set.
|
||||
* @param s The input sample as an int.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSample(int, int, int, DataBuffer)
|
||||
/*
|
||||
* {inheritDoc}
|
||||
* @throws NullPointerException if {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* the band index are not in bounds.
|
||||
*/
|
||||
public void setSample(int x, int y, int b, int s,
|
||||
DataBuffer data) {
|
||||
@ -718,23 +681,16 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the samples in the specified band for the specified rectangle
|
||||
* of pixels from an int array containing one sample per array element.
|
||||
* ArrayIndexOutOfBoundsException may be thrown if the coordinates are
|
||||
* not in bounds.
|
||||
* @param x The X coordinate of the upper left pixel location.
|
||||
* @param y The Y coordinate of the upper left pixel location.
|
||||
* @param w The width of the pixel rectangle.
|
||||
* @param h The height of the pixel rectangle.
|
||||
* @param b The band to set.
|
||||
* @param iArray The input samples in an int array.
|
||||
* @param data The DataBuffer containing the image data.
|
||||
* @see #getSamples(int, int, int, int, int, int[], DataBuffer)
|
||||
* {@inheritDoc}
|
||||
* @throws NullPointerException if {@code iArray} or {@code data} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if the coordinates or
|
||||
* band index are not in bounds, or {@code w} or {@code h} is negative,
|
||||
* or if {@code iArray} is too small to hold the input.
|
||||
*/
|
||||
public void setSamples(int x, int y, int w, int h, int b,
|
||||
int[] iArray, DataBuffer data) {
|
||||
// Bounds check for 'b' will be performed automatically
|
||||
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
|
||||
if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) {
|
||||
throw new ArrayIndexOutOfBoundsException
|
||||
("Coordinate out of bounds!");
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@ import java.io.UncheckedIOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpResponse.BodyHandler;
|
||||
import java.net.http.HttpResponse.ResponseInfo;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -973,36 +972,6 @@ class Stream<T> extends ExchangeImpl<T> {
|
||||
return headers;
|
||||
}
|
||||
|
||||
private static HttpHeaders createPseudoHeaders(HttpRequest request) {
|
||||
HttpHeadersBuilder hdrs = new HttpHeadersBuilder();
|
||||
String method = request.method();
|
||||
hdrs.setHeader(":method", method);
|
||||
URI uri = request.uri();
|
||||
hdrs.setHeader(":scheme", uri.getScheme());
|
||||
String host = uri.getHost();
|
||||
int port = uri.getPort();
|
||||
assert host != null;
|
||||
if (port != -1) {
|
||||
hdrs.setHeader(":authority", host + ":" + port);
|
||||
} else {
|
||||
hdrs.setHeader(":authority", host);
|
||||
}
|
||||
String query = uri.getRawQuery();
|
||||
String path = uri.getRawPath();
|
||||
if (path == null || path.isEmpty()) {
|
||||
if (method.equalsIgnoreCase("OPTIONS")) {
|
||||
path = "*";
|
||||
} else {
|
||||
path = "/";
|
||||
}
|
||||
}
|
||||
if (query != null) {
|
||||
path += "?" + query;
|
||||
}
|
||||
hdrs.setHeader(":path", Utils.encode(path));
|
||||
return hdrs.build();
|
||||
}
|
||||
|
||||
HttpHeaders getRequestPseudoHeaders() {
|
||||
return requestPseudoHeaders;
|
||||
}
|
||||
|
||||
@ -577,7 +577,6 @@ public class QuicPacketEncoder {
|
||||
final byte[] encodedPacketNumber;
|
||||
final List<QuicFrame> frames;
|
||||
final int payloadSize;
|
||||
private int tagSize;
|
||||
|
||||
OutgoingHandshakePacket(QuicConnectionId sourceId,
|
||||
QuicConnectionId destinationId,
|
||||
@ -590,7 +589,6 @@ public class QuicPacketEncoder {
|
||||
this.encodedPacketNumber = encodedPacketNumber;
|
||||
this.frames = List.copyOf(frames);
|
||||
this.payloadSize = frames.stream().mapToInt(QuicFrame::size).reduce(0, Math::addExact);
|
||||
this.tagSize = tagSize;
|
||||
this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize);
|
||||
this.size = computeSize(length);
|
||||
}
|
||||
@ -676,7 +674,6 @@ public class QuicPacketEncoder {
|
||||
final int size;
|
||||
final byte[] encodedPacketNumber;
|
||||
final List<QuicFrame> frames;
|
||||
private int tagSize;
|
||||
final int payloadSize;
|
||||
|
||||
OutgoingZeroRttPacket(QuicConnectionId sourceId,
|
||||
@ -689,7 +686,6 @@ public class QuicPacketEncoder {
|
||||
this.packetNumber = packetNumber;
|
||||
this.encodedPacketNumber = encodedPacketNumber;
|
||||
this.frames = List.copyOf(frames);
|
||||
this.tagSize = tagSize;
|
||||
this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size)
|
||||
.reduce(0, Math::addExact);
|
||||
this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize);
|
||||
@ -778,7 +774,6 @@ public class QuicPacketEncoder {
|
||||
final int size;
|
||||
final byte[] encodedPacketNumber;
|
||||
final List<QuicFrame> frames;
|
||||
private int tagSize;
|
||||
final int payloadSize;
|
||||
|
||||
OutgoingOneRttPacket(QuicConnectionId destinationId,
|
||||
@ -789,7 +784,6 @@ public class QuicPacketEncoder {
|
||||
this.packetNumber = packetNumber;
|
||||
this.encodedPacketNumber = encodedPacketNumber;
|
||||
this.frames = List.copyOf(frames);
|
||||
this.tagSize = tagSize;
|
||||
this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size)
|
||||
.reduce(0, Math::addExact);
|
||||
this.size = computeSize(payloadSize, encodedPacketNumber.length, tagSize);
|
||||
@ -853,7 +847,6 @@ public class QuicPacketEncoder {
|
||||
final int size;
|
||||
final byte[] encodedPacketNumber;
|
||||
final List<QuicFrame> frames;
|
||||
private int tagSize;
|
||||
final int payloadSize;
|
||||
|
||||
private record InitialPacketVariableComponents(int length, byte[] token, QuicConnectionId sourceId,
|
||||
@ -873,7 +866,6 @@ public class QuicPacketEncoder {
|
||||
this.packetNumber = packetNumber;
|
||||
this.encodedPacketNumber = encodedPacketNumber;
|
||||
this.frames = List.copyOf(frames);
|
||||
this.tagSize = tagSize;
|
||||
this.payloadSize = this.frames.stream()
|
||||
.mapToInt(QuicFrame::size)
|
||||
.reduce(0, Math::addExact);
|
||||
|
||||
@ -226,6 +226,8 @@ public final class SourceLauncher {
|
||||
|
||||
Object instance = null;
|
||||
|
||||
// Similar to sun.launcher.LauncherHelper#checkAndLoadMain, including
|
||||
// checks performed in LauncherHelper#validateMainMethod
|
||||
if (!isStatic) {
|
||||
if (Modifier.isAbstract(mainClass.getModifiers())) {
|
||||
throw new Fault(Errors.CantInstantiate(mainClassName));
|
||||
@ -238,6 +240,10 @@ public final class SourceLauncher {
|
||||
throw new Fault(Errors.CantFindConstructor(mainClassName));
|
||||
}
|
||||
|
||||
if (Modifier.isPrivate(constructor.getModifiers())) {
|
||||
throw new Fault(Errors.CantUsePrivateConstructor(mainClassName));
|
||||
}
|
||||
|
||||
try {
|
||||
constructor.setAccessible(true);
|
||||
instance = constructor.newInstance();
|
||||
|
||||
@ -33,6 +33,8 @@ import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.Collator;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@ -45,7 +47,6 @@ import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -323,12 +324,13 @@ public enum Option {
|
||||
|
||||
@Override
|
||||
protected void help(Log log) {
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
List<String> releases = new ArrayList<>();
|
||||
for(Source source : Source.values()) {
|
||||
if (source.isSupported())
|
||||
sj.add(source.name);
|
||||
releases.add(source.name);
|
||||
}
|
||||
super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString()));
|
||||
String formatted = formatAbbreviatedList(releases);
|
||||
super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted));
|
||||
}
|
||||
},
|
||||
|
||||
@ -344,12 +346,13 @@ public enum Option {
|
||||
|
||||
@Override
|
||||
protected void help(Log log) {
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
List<String> releases = new ArrayList<>();
|
||||
for(Target target : Target.values()) {
|
||||
if (target.isSupported())
|
||||
sj.add(target.name);
|
||||
releases.add(target.name);
|
||||
}
|
||||
super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString()));
|
||||
String formatted = formatAbbreviatedList(releases);
|
||||
super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted));
|
||||
}
|
||||
},
|
||||
|
||||
@ -364,15 +367,8 @@ public enum Option {
|
||||
false))
|
||||
.collect(Collectors.toCollection(LinkedHashSet :: new));
|
||||
|
||||
StringBuilder targets = new StringBuilder();
|
||||
String delim = "";
|
||||
for (String platform : platforms) {
|
||||
targets.append(delim);
|
||||
targets.append(platform);
|
||||
delim = ", ";
|
||||
}
|
||||
|
||||
super.help(log, log.localize(PrefixKind.JAVAC, descrKey, targets.toString()));
|
||||
String formatted = formatAbbreviatedList(platforms);
|
||||
super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted));
|
||||
}
|
||||
},
|
||||
|
||||
@ -1369,6 +1365,41 @@ public enum Option {
|
||||
log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a collection of values as an abbreviated, comma separated list
|
||||
* for use in javac help output.
|
||||
*
|
||||
* This helper assumes that the supported values form a dense sequence
|
||||
* between the fourth and the (n - 3)rd entries.
|
||||
* That matches the current policy for these values but is not
|
||||
* guaranteed, and should be reconsidered if the structure of the values changes.
|
||||
*
|
||||
* @param values the values to format
|
||||
* @return a comma separated representation of the values
|
||||
*/
|
||||
private static String formatAbbreviatedList(Collection<String> values) {
|
||||
List<String> list = (values instanceof List)
|
||||
? (List<String>) values
|
||||
: new ArrayList<>(values);
|
||||
|
||||
int size = list.size();
|
||||
if (size == 0) {
|
||||
return "";
|
||||
}
|
||||
if (size <= 6) {
|
||||
return String.join(", ", list);
|
||||
}
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
sj.add(list.get(i));
|
||||
}
|
||||
sj.add("...");
|
||||
for (int i = size - 3; i < size; i++) {
|
||||
sj.add(list.get(i));
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes the initial synopsis of one of the forms for this option.
|
||||
* @param name the name of this form of the option
|
||||
|
||||
@ -100,7 +100,8 @@ javac.opt.arg.Werror=\
|
||||
<key>(,<key>)*
|
||||
javac.opt.Werror.custom=\
|
||||
Specify lint categories for which warnings should terminate compilation,\n\
|
||||
separated by comma. Precede a key by ''-'' to exclude the specified category.\n\
|
||||
separated by comma.\n\
|
||||
Precede a key by ''-'' to exclude the specified category.\n\
|
||||
Use --help-lint to see the supported keys.
|
||||
javac.opt.A=\
|
||||
Options to pass to annotation processors
|
||||
@ -358,7 +359,8 @@ javac.opt.prefer=\
|
||||
are found for an implicitly compiled class
|
||||
# L10N: do not localize: ''preview''
|
||||
javac.opt.preview=\
|
||||
Enable preview language features. Also disables the ''preview'' lint category.\n\
|
||||
Enable preview language features.\n\
|
||||
Also disables the ''preview'' lint category.\n\
|
||||
To be used in conjunction with either -source or --release.
|
||||
javac.opt.AT=\
|
||||
Read options and filenames from file
|
||||
|
||||
@ -124,6 +124,12 @@ launcher.err.cant.access.main.method=\
|
||||
launcher.err.cant.find.constructor=\
|
||||
can''t find no argument constructor in class: {0}
|
||||
|
||||
# 0: string
|
||||
launcher.err.cant.use.private.constructor=\
|
||||
no non-private zero argument constructor found in class {0}\n\
|
||||
remove private from existing constructor or define as:\n\
|
||||
\ public {0}()
|
||||
|
||||
# 0: string
|
||||
launcher.err.cant.access.constructor=\
|
||||
can''t access no argument constructor in class: {0}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
This directory contains history data for -release.
|
||||
|
||||
Please see $JDK_TOP_DIR/make/scripts/generate-symbol-data.sh for main usage.
|
||||
Please see $JDK_TOP_DIR/bin/generate-symbol-data.sh for main usage.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,9 @@
|
||||
package sun.jvm.hotspot.debugger.bsd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import sun.jvm.hotspot.debugger.Address;
|
||||
import sun.jvm.hotspot.debugger.DebuggerBase;
|
||||
@ -75,10 +77,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
|
||||
// CDebugger support
|
||||
private BsdCDebugger cdbg;
|
||||
|
||||
// threadList and loadObjectList are filled by attach0 method
|
||||
private List<ThreadProxy> threadList;
|
||||
// loadObjectList is filled by attach0 method
|
||||
private List<LoadObject> loadObjectList;
|
||||
|
||||
private List<JavaThread> javaThreadList;
|
||||
|
||||
// called by native method lookupByAddress0
|
||||
private ClosestSymbol createClosestSymbol(String name, long offset) {
|
||||
return new ClosestSymbol(name, offset);
|
||||
@ -241,10 +244,21 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
private void fillJavaThreadList() {
|
||||
// TODO: thread list on macOS is now supported for corefile only.
|
||||
if (!isCore && isDarwin) {
|
||||
javaThreadList = Collections.emptyList();
|
||||
} else {
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
javaThreadList = IntStream.range(0, threads.getNumberOfThreads())
|
||||
.mapToObj(threads::getJavaThreadAt)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
/** From the Debugger interface via JVMDebugger */
|
||||
public synchronized void attach(int processID) throws DebuggerException {
|
||||
checkAttached();
|
||||
threadList = new ArrayList<>();
|
||||
loadObjectList = new ArrayList<>();
|
||||
class AttachTask implements WorkerThreadTask {
|
||||
int pid;
|
||||
@ -264,7 +278,6 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
|
||||
/** From the Debugger interface via JVMDebugger */
|
||||
public synchronized void attach(String execName, String coreName) {
|
||||
checkAttached();
|
||||
threadList = new ArrayList<>();
|
||||
loadObjectList = new ArrayList<>();
|
||||
attach0(execName, coreName);
|
||||
attached = true;
|
||||
@ -278,7 +291,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
|
||||
return false;
|
||||
}
|
||||
|
||||
threadList = null;
|
||||
javaThreadList = null;
|
||||
loadObjectList = null;
|
||||
|
||||
if (isCore) {
|
||||
@ -492,7 +505,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
|
||||
/** From the BsdCDebugger interface */
|
||||
public List<ThreadProxy> getThreadList() {
|
||||
requireAttach();
|
||||
return threadList;
|
||||
if (javaThreadList == null) {
|
||||
fillJavaThreadList();
|
||||
}
|
||||
return javaThreadList.stream()
|
||||
.map(JavaThread::getThreadProxy)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/** From the BsdCDebugger interface */
|
||||
@ -561,21 +579,19 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
|
||||
/** this functions used for core file reading and called from native attach0,
|
||||
it returns an array of long integers as
|
||||
[thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for
|
||||
all java threads recorded in Threads. Also adds the ThreadProxy to threadList */
|
||||
all java threads recorded in Threads. */
|
||||
public long[] getJavaThreadsInfo() {
|
||||
requireAttach();
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
int len = threads.getNumberOfThreads();
|
||||
long[] result = new long[len * 3]; // triple
|
||||
if (javaThreadList == null) {
|
||||
fillJavaThreadList();
|
||||
}
|
||||
long[] result = new long[javaThreadList.size() * 3]; // triple
|
||||
long beg, end;
|
||||
int i = 0;
|
||||
for (int k = 0; k < threads.getNumberOfThreads(); k++) {
|
||||
JavaThread t = threads.getJavaThreadAt(k);
|
||||
for (var t : javaThreadList) {
|
||||
end = t.getStackBaseValue();
|
||||
beg = end - t.getStackSize();
|
||||
BsdThread bsdt = (BsdThread)t.getThreadProxy();
|
||||
long uid = bsdt.getUniqueThreadId();
|
||||
if (threadList != null) threadList.add(bsdt);
|
||||
long uid = ((BsdThread)t.getThreadProxy()).getUniqueThreadId();
|
||||
result[i] = uid;
|
||||
result[i + 1] = beg;
|
||||
result[i + 2] = end;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
package sun.jvm.hotspot.debugger.cdbg;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.utilities.*;
|
||||
|
||||
/** Models a "C" programming language frame on the stack -- really
|
||||
just an arbitrary frame with hooks to access C and C++ debug
|
||||
@ -37,7 +39,7 @@ public interface CFrame {
|
||||
public CFrame sender(ThreadProxy th);
|
||||
|
||||
/** Find sender frame with given FP and PC */
|
||||
public default CFrame sender(ThreadProxy th, Address fp, Address pc) {
|
||||
public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) {
|
||||
return sender(th);
|
||||
}
|
||||
|
||||
@ -70,4 +72,9 @@ public interface CFrame {
|
||||
/** Visit all local variables in this frame if debug information is
|
||||
available. Automatically descends into compound types and arrays. */
|
||||
public void iterateLocals(ObjectVisitor v);
|
||||
|
||||
/** Get Frame instance assosiated with this CFrame. */
|
||||
public default Frame toFrame() {
|
||||
throw new UnsupportedPlatformException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -81,9 +81,11 @@ class LinuxCDebugger implements CDebugger {
|
||||
String cpu = dbg.getCPU();
|
||||
if (cpu.equals("amd64")) {
|
||||
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
|
||||
Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
|
||||
if (sp == null) return null;
|
||||
Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP);
|
||||
if (pc == null) return null;
|
||||
return LinuxAMD64CFrame.getTopFrame(dbg, pc, context);
|
||||
return LinuxAMD64CFrame.getTopFrame(dbg, sp, pc, context);
|
||||
} else if (cpu.equals("ppc64")) {
|
||||
PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext();
|
||||
Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP);
|
||||
@ -93,18 +95,22 @@ class LinuxCDebugger implements CDebugger {
|
||||
return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
|
||||
} else if (cpu.equals("aarch64")) {
|
||||
AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
|
||||
Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
|
||||
if (sp == null) return null;
|
||||
Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP);
|
||||
if (fp == null) return null;
|
||||
Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC);
|
||||
if (pc == null) return null;
|
||||
return new LinuxAARCH64CFrame(dbg, fp, pc);
|
||||
return new LinuxAARCH64CFrame(dbg, sp, fp, pc);
|
||||
} else if (cpu.equals("riscv64")) {
|
||||
RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext();
|
||||
Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP);
|
||||
if (sp == null) return null;
|
||||
Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP);
|
||||
if (fp == null) return null;
|
||||
Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC);
|
||||
if (pc == null) return null;
|
||||
return new LinuxRISCV64CFrame(dbg, fp, pc);
|
||||
return new LinuxRISCV64CFrame(dbg, sp, fp, pc);
|
||||
} else {
|
||||
// Runtime exception thrown by LinuxThreadContextFactory if unknown cpu
|
||||
ThreadContext context = thread.getContext();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -30,10 +30,14 @@ import sun.jvm.hotspot.debugger.aarch64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.code.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.runtime.aarch64.*;
|
||||
|
||||
public final class LinuxAARCH64CFrame extends BasicCFrame {
|
||||
public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) {
|
||||
public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) {
|
||||
super(dbg.getCDebugger());
|
||||
this.sp = sp;
|
||||
this.fp = fp;
|
||||
this.pc = pc;
|
||||
this.dbg = dbg;
|
||||
@ -55,11 +59,11 @@ public final class LinuxAARCH64CFrame extends BasicCFrame {
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
return sender(thread, null, null);
|
||||
return sender(thread, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) {
|
||||
public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) {
|
||||
// Check fp
|
||||
// Skip if both nextFP and nextPC are given - do not need to load from fp.
|
||||
if (nextFP == null && nextPC == null) {
|
||||
@ -86,7 +90,32 @@ public final class LinuxAARCH64CFrame extends BasicCFrame {
|
||||
if (nextPC == null) {
|
||||
return null;
|
||||
}
|
||||
return new LinuxAARCH64CFrame(dbg, nextFP, nextPC);
|
||||
|
||||
if (nextSP == null) {
|
||||
CodeCache cc = VM.getVM().getCodeCache();
|
||||
CodeBlob currentBlob = cc.findBlobUnsafe(pc());
|
||||
|
||||
// This case is different from HotSpot. See JDK-8371194 for details.
|
||||
if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) {
|
||||
// Use FP since it should always be valid for these cases.
|
||||
// TODO: These should be walked as Frames not CFrames.
|
||||
nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE);
|
||||
} else {
|
||||
CodeBlob codeBlob = cc.findBlobUnsafe(nextPC);
|
||||
boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0;
|
||||
nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP;
|
||||
}
|
||||
}
|
||||
if (nextSP == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame toFrame() {
|
||||
return new AARCH64Frame(sp, fp, pc);
|
||||
}
|
||||
|
||||
// package/class internals only
|
||||
|
||||
@ -29,10 +29,12 @@ import sun.jvm.hotspot.debugger.amd64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.runtime.amd64.*;
|
||||
|
||||
public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
|
||||
public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) {
|
||||
public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rsp, Address rip, ThreadContext context) {
|
||||
Address libptr = dbg.findLibPtrByAddress(rip);
|
||||
Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
|
||||
DwarfParser dwarf = null;
|
||||
@ -45,7 +47,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
// DWARF processing should succeed when the frame is native
|
||||
// but it might fail if Common Information Entry (CIE) has language
|
||||
// personality routine and/or Language Specific Data Area (LSDA).
|
||||
return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true);
|
||||
return new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf, true);
|
||||
}
|
||||
|
||||
cfa = context.getRegisterAsAddress(dwarf.getCFARegister())
|
||||
@ -53,19 +55,20 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
}
|
||||
|
||||
return (cfa == null) ? null
|
||||
: new LinuxAMD64CFrame(dbg, cfa, rip, dwarf);
|
||||
: new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf);
|
||||
}
|
||||
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) {
|
||||
this(dbg, cfa, rip, dwarf, false);
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf) {
|
||||
this(dbg, rsp, cfa, rip, dwarf, false);
|
||||
}
|
||||
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) {
|
||||
this(dbg, cfa, rip, dwarf, finalFrame, false);
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) {
|
||||
this(dbg, rsp, cfa, rip, dwarf, finalFrame, false);
|
||||
}
|
||||
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) {
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) {
|
||||
super(dbg.getCDebugger());
|
||||
this.rsp = rsp;
|
||||
this.cfa = cfa;
|
||||
this.rip = rip;
|
||||
this.dbg = dbg;
|
||||
@ -107,7 +110,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
(!isNative || (isNative && nextCFA.greaterThan(cfa)));
|
||||
}
|
||||
|
||||
private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP) {
|
||||
private Address getNextRSP() {
|
||||
// next RSP should be previous slot of return address.
|
||||
var bp = dwarf == null ? cfa.addOffsetTo(ADDRESS_SIZE) // top of BP points callser BP
|
||||
: cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA());
|
||||
return bp.addOffsetTo(ADDRESS_SIZE);
|
||||
}
|
||||
|
||||
private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP, Address senderPC) {
|
||||
Address nextCFA;
|
||||
boolean isNative = false;
|
||||
|
||||
@ -115,13 +125,17 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
senderFP = cfa.getAddressAt(0); // RBP by default
|
||||
}
|
||||
|
||||
if (nextDwarf == null) { // Next frame is Java
|
||||
if (VM.getVM().getCodeCache().contains(senderPC)) { // Next frame is Java
|
||||
nextCFA = (dwarf == null) ? senderFP // Current frame is Java
|
||||
: cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); // Current frame is Native
|
||||
} else { // Next frame is Native
|
||||
if (dwarf == null) { // Current frame is Java
|
||||
if (VM.getVM().getCodeCache().contains(pc())) { // Current frame is Java
|
||||
nextCFA = senderFP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA());
|
||||
} else { // Current frame is Native
|
||||
if (nextDwarf == null) { // maybe runtime entrypoint (_start())
|
||||
throw new DebuggerException("nextDwarf is null even though native call");
|
||||
}
|
||||
|
||||
isNative = true;
|
||||
int nextCFAReg = nextDwarf.getCFARegister();
|
||||
if (nextCFAReg == AMD64ThreadContext.RBP) {
|
||||
@ -130,10 +144,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
Address nextRBP = rbp.getAddressAt(0);
|
||||
nextCFA = nextRBP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA());
|
||||
} else if (nextCFAReg == AMD64ThreadContext.RSP) {
|
||||
// next RSP should be previous slot of return address.
|
||||
Address nextRSP = cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA())
|
||||
.addOffsetTo(ADDRESS_SIZE);
|
||||
nextCFA = nextRSP.addOffsetTo(nextDwarf.getCFAOffset());
|
||||
nextCFA = getNextRSP().addOffsetTo(nextDwarf.getCFAOffset());
|
||||
} else {
|
||||
throw new DebuggerException("Unsupported CFA register: " + nextCFAReg);
|
||||
}
|
||||
@ -153,17 +164,22 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy th) {
|
||||
return sender(th, null, null);
|
||||
return sender(th, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy th, Address fp, Address pc) {
|
||||
public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) {
|
||||
if (finalFrame) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ThreadContext context = th.getContext();
|
||||
|
||||
Address nextRSP = sp != null ? sp : getNextRSP();
|
||||
if (nextRSP == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Address nextPC = pc != null ? pc : getNextPC(dwarf != null);
|
||||
if (nextPC == null) {
|
||||
return null;
|
||||
@ -183,13 +199,16 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
// DWARF processing should succeed when the frame is native
|
||||
// but it might fail if Common Information Entry (CIE) has language
|
||||
// personality routine and/or Language Specific Data Area (LSDA).
|
||||
return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Address nextCFA = getNextCFA(nextDwarf, context, fp);
|
||||
return nextCFA == null ? null
|
||||
: new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf, false, fallback);
|
||||
try {
|
||||
Address nextCFA = getNextCFA(nextDwarf, context, fp, nextPC);
|
||||
return new LinuxAMD64CFrame(dbg, nextRSP, nextCFA, nextPC, nextDwarf, false, fallback);
|
||||
} catch (DebuggerException _) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private DwarfParser createDwarfParser(Address pc) throws DebuggerException {
|
||||
@ -210,8 +229,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
return nextDwarf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame toFrame() {
|
||||
return new AMD64Frame(rsp, cfa, rip);
|
||||
}
|
||||
|
||||
// package/class internals only
|
||||
private static final int ADDRESS_SIZE = 8;
|
||||
private Address rsp;
|
||||
private Address rip;
|
||||
private Address cfa;
|
||||
private LinuxDebugger dbg;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,6 +29,8 @@ import sun.jvm.hotspot.debugger.ppc64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.runtime.ppc64.*;
|
||||
|
||||
public final class LinuxPPC64CFrame extends BasicCFrame {
|
||||
// package/class internals only
|
||||
@ -71,6 +73,12 @@ public final class LinuxPPC64CFrame extends BasicCFrame {
|
||||
return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame toFrame() {
|
||||
// 2nd arg (raw_fp) would be derived from sp in c'tor of PPC64Frame.
|
||||
return new PPC64Frame(sp, null, pc);
|
||||
}
|
||||
|
||||
public static int PPC64_STACK_BIAS = 0;
|
||||
private static int address_size;
|
||||
private Address pc;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, Red Hat Inc.
|
||||
* Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
@ -31,13 +31,17 @@ import sun.jvm.hotspot.debugger.riscv64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.runtime.riscv64.*;
|
||||
|
||||
public final class LinuxRISCV64CFrame extends BasicCFrame {
|
||||
private static final int C_FRAME_LINK_OFFSET = -2;
|
||||
private static final int C_FRAME_RETURN_ADDR_OFFSET = -1;
|
||||
private static final int C_FRAME_SENDER_SP_OFFSET = 0;
|
||||
|
||||
public LinuxRISCV64CFrame(LinuxDebugger dbg, Address fp, Address pc) {
|
||||
public LinuxRISCV64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) {
|
||||
super(dbg.getCDebugger());
|
||||
this.sp = sp;
|
||||
this.fp = fp;
|
||||
this.pc = pc;
|
||||
this.dbg = dbg;
|
||||
@ -59,11 +63,11 @@ public final class LinuxRISCV64CFrame extends BasicCFrame {
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
return sender(thread, null, null);
|
||||
return sender(thread, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) {
|
||||
public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) {
|
||||
// Check fp
|
||||
// Skip if both nextFP and nextPC are given - do not need to load from fp.
|
||||
if (nextFP == null && nextPC == null) {
|
||||
@ -77,6 +81,13 @@ public final class LinuxRISCV64CFrame extends BasicCFrame {
|
||||
}
|
||||
}
|
||||
|
||||
if (nextSP == null) {
|
||||
nextSP = fp.getAddressAt(C_FRAME_SENDER_SP_OFFSET * ADDRESS_SIZE);
|
||||
}
|
||||
if (nextSP == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (nextFP == null) {
|
||||
nextFP = fp.getAddressAt(C_FRAME_LINK_OFFSET * ADDRESS_SIZE);
|
||||
}
|
||||
@ -91,7 +102,12 @@ public final class LinuxRISCV64CFrame extends BasicCFrame {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LinuxRISCV64CFrame(dbg, nextFP, nextPC);
|
||||
return new LinuxRISCV64CFrame(dbg, nextSP, nextFP, nextPC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame toFrame() {
|
||||
return new RISCV64Frame(sp, fp, pc);
|
||||
}
|
||||
|
||||
// package/class internals only
|
||||
|
||||
@ -272,9 +272,7 @@ public class AARCH64Frame extends Frame {
|
||||
if (cb != null) {
|
||||
if (cb.isUpcallStub()) {
|
||||
return senderForUpcallStub(map, (UpcallStub)cb);
|
||||
} else if (cb.isContinuationStub()) {
|
||||
return senderForContinuationStub(map, cb);
|
||||
} else {
|
||||
} else if (cb.getFrameSize() > 0) {
|
||||
return senderForCompiledFrame(map, cb);
|
||||
}
|
||||
}
|
||||
@ -389,7 +387,11 @@ public class AARCH64Frame extends Frame {
|
||||
if (Assert.ASSERTS_ENABLED) {
|
||||
Assert.that(cb.getFrameSize() > 0, "must have non-zero frame size");
|
||||
}
|
||||
Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize());
|
||||
|
||||
// TODO: senderSP should consider not only PreserveFramePointer but also _sp_is_trusted.
|
||||
Address senderSP = !VM.getVM().getCommandLineBooleanFlag("PreserveFramePointer")
|
||||
? getUnextendedSP().addOffsetTo(cb.getFrameSize())
|
||||
: getSenderSP();
|
||||
|
||||
// The return_address is always the word on the stack
|
||||
Address senderPC = stripPAC(senderSP.getAddressAt(-1 * VM.getVM().getAddressSize()));
|
||||
|
||||
@ -272,9 +272,7 @@ public class AMD64Frame extends Frame {
|
||||
if (cb != null) {
|
||||
if (cb.isUpcallStub()) {
|
||||
return senderForUpcallStub(map, (UpcallStub)cb);
|
||||
} else if (cb.isContinuationStub()) {
|
||||
return senderForContinuationStub(map, cb);
|
||||
} else {
|
||||
} else if (cb.getFrameSize() > 0) {
|
||||
return senderForCompiledFrame(map, cb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,6 @@ public class PStack extends Tool {
|
||||
if (cdbg != null) {
|
||||
ConcurrentLocksPrinter concLocksPrinter = null;
|
||||
// compute and cache java Vframes.
|
||||
initJFrameCache();
|
||||
if (concurrentLocks) {
|
||||
concLocksPrinter = new ConcurrentLocksPrinter(out);
|
||||
}
|
||||
@ -96,6 +95,7 @@ public class PStack extends Tool {
|
||||
return;
|
||||
}
|
||||
final boolean cdbgCanDemangle = cdbg.canDemangle();
|
||||
Map<ThreadProxy, JavaThread> proxyToThread = createProxyToThread();;
|
||||
String fillerForAddress = " ".repeat(2 + 2 * (int) VM.getVM().getAddressSize()) + "\t";
|
||||
for (Iterator<ThreadProxy> itr = l.iterator() ; itr.hasNext();) {
|
||||
ThreadProxy th = itr.next();
|
||||
@ -109,6 +109,7 @@ public class PStack extends Tool {
|
||||
jthread.printThreadInfoOn(out);
|
||||
}
|
||||
while (f != null) {
|
||||
Address senderSP = null;
|
||||
Address senderFP = null;
|
||||
Address senderPC = null;
|
||||
ClosestSymbol sym = f.closestSymbolToPC();
|
||||
@ -131,7 +132,7 @@ public class PStack extends Tool {
|
||||
// check interpreter frame
|
||||
Interpreter interp = VM.getVM().getInterpreter();
|
||||
if (interp.contains(pc)) {
|
||||
nameInfo = getJavaNames(th, f.localVariableBase());
|
||||
nameInfo = getJavaNames(jthread, f);
|
||||
// print codelet name if we can't determine method
|
||||
if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) {
|
||||
out.print("<interpreter> ");
|
||||
@ -156,7 +157,7 @@ public class PStack extends Tool {
|
||||
}
|
||||
out.println(" (Native method)");
|
||||
} else {
|
||||
nameInfo = getJavaNames(th, f.localVariableBase());
|
||||
nameInfo = getJavaNames(jthread, f);
|
||||
// just print compiled code, if can't determine method
|
||||
if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) {
|
||||
out.println("<Unknown compiled code>");
|
||||
@ -164,6 +165,12 @@ public class PStack extends Tool {
|
||||
}
|
||||
} else {
|
||||
out.println("<" + cb.getName() + ">");
|
||||
if (cb.getFrameSize() > 0) {
|
||||
Frame senderFrame = f.toFrame().sender(jthread.newRegisterMap(true));
|
||||
senderSP = senderFrame.getSP();
|
||||
senderFP = senderFrame.getFP();
|
||||
senderPC = senderFrame.getPC();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printUnknown(out);
|
||||
@ -180,11 +187,12 @@ public class PStack extends Tool {
|
||||
out.println(nameInfo.names()[i]);
|
||||
}
|
||||
}
|
||||
senderSP = nameInfo.senderSP();
|
||||
senderFP = nameInfo.senderFP();
|
||||
senderPC = nameInfo.senderPC();
|
||||
}
|
||||
}
|
||||
f = f.sender(th, senderFP, senderPC);
|
||||
f = f.sender(th, senderSP, senderFP, senderPC);
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
exp.printStackTrace();
|
||||
@ -212,95 +220,74 @@ public class PStack extends Tool {
|
||||
}
|
||||
|
||||
// -- Internals only below this point
|
||||
private Map<ThreadProxy, JavaVFrame[]> jframeCache;
|
||||
private Map<ThreadProxy, JavaThread> proxyToThread;
|
||||
private PrintStream out;
|
||||
private boolean verbose;
|
||||
private boolean concurrentLocks;
|
||||
|
||||
private void initJFrameCache() {
|
||||
// cache frames for subsequent reference
|
||||
jframeCache = new HashMap<>();
|
||||
proxyToThread = new HashMap<>();
|
||||
private Map<ThreadProxy, JavaThread> createProxyToThread() {
|
||||
Map<ThreadProxy, JavaThread> proxyToThread = new HashMap<>();
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (int i = 0; i < threads.getNumberOfThreads(); i++) {
|
||||
JavaThread cur = threads.getJavaThreadAt(i);
|
||||
List<JavaVFrame> tmp = new ArrayList<>(10);
|
||||
try {
|
||||
for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
|
||||
tmp.add(vf);
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
// may be we may get frames for other threads, continue
|
||||
// after printing stack trace.
|
||||
exp.printStackTrace();
|
||||
}
|
||||
JavaVFrame[] jvframes = tmp.toArray(new JavaVFrame[0]);
|
||||
jframeCache.put(cur.getThreadProxy(), jvframes);
|
||||
proxyToThread.put(cur.getThreadProxy(), cur);
|
||||
JavaThread jthread = threads.getJavaThreadAt(i);
|
||||
proxyToThread.put(jthread.getThreadProxy(), jthread);
|
||||
}
|
||||
return proxyToThread;
|
||||
}
|
||||
|
||||
private void printUnknown(PrintStream out) {
|
||||
out.println("\t????????");
|
||||
}
|
||||
|
||||
private static record JavaNameInfo(String[] names, Address senderFP, Address senderPC) {};
|
||||
|
||||
private JavaNameInfo getJavaNames(ThreadProxy th, Address fp) {
|
||||
if (fp == null) {
|
||||
return null;
|
||||
}
|
||||
JavaVFrame[] jvframes = jframeCache.get(th);
|
||||
if (jvframes == null) return null; // not a java thread
|
||||
private static record JavaNameInfo(String[] names, Address senderSP, Address senderFP, Address senderPC) {};
|
||||
|
||||
private JavaNameInfo getJavaNames(JavaThread jthread, CFrame f) {
|
||||
List<String> names = new ArrayList<>(10);
|
||||
JavaVFrame bottomJVFrame = null;
|
||||
for (int fCount = 0; fCount < jvframes.length; fCount++) {
|
||||
JavaVFrame vf = jvframes[fCount];
|
||||
Frame f = vf.getFrame();
|
||||
if (fp.equals(f.getFP())) {
|
||||
bottomJVFrame = vf;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Method method = vf.getMethod();
|
||||
// a special char to identify java frames in output
|
||||
sb.append("* ");
|
||||
sb.append(method.externalNameAndSignature());
|
||||
sb.append(" bci:").append(vf.getBCI());
|
||||
int lineNumber = method.getLineNumberFromBCI(vf.getBCI());
|
||||
if (lineNumber != -1) {
|
||||
sb.append(" line:").append(lineNumber);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
sb.append(" Method*:").append(method.getAddress());
|
||||
}
|
||||
|
||||
if (vf.isCompiledFrame()) {
|
||||
sb.append(" (Compiled frame");
|
||||
if (vf.isDeoptimized()) {
|
||||
sb.append(" [deoptimized]");
|
||||
}
|
||||
} else if (vf.isInterpretedFrame()) {
|
||||
sb.append(" (Interpreted frame");
|
||||
}
|
||||
if (vf.mayBeImpreciseDbg()) {
|
||||
sb.append("; information may be imprecise");
|
||||
}
|
||||
sb.append(")");
|
||||
names.add(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Address senderSP = null;
|
||||
Address senderFP = null;
|
||||
Address senderPC = null;
|
||||
if (bottomJVFrame != null) {
|
||||
Frame senderFrame = bottomJVFrame.getFrame().sender((RegisterMap)bottomJVFrame.getRegisterMap().clone());
|
||||
VFrame vf = VFrame.newVFrame(f.toFrame(), jthread.newRegisterMap(true), jthread, true, true);
|
||||
while (vf != null && vf.isJavaFrame()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Method method = ((JavaVFrame)vf).getMethod();
|
||||
// a special char to identify java frames in output
|
||||
sb.append("* ");
|
||||
sb.append(method.externalNameAndSignature());
|
||||
sb.append(" bci:").append(((JavaVFrame)vf).getBCI());
|
||||
int lineNumber = method.getLineNumberFromBCI(((JavaVFrame)vf).getBCI());
|
||||
if (lineNumber != -1) {
|
||||
sb.append(" line:").append(lineNumber);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
sb.append(" Method*:").append(method.getAddress());
|
||||
}
|
||||
|
||||
if (vf.isCompiledFrame()) {
|
||||
sb.append(" (Compiled frame");
|
||||
if (vf.isDeoptimized()) {
|
||||
sb.append(" [deoptimized]");
|
||||
}
|
||||
} else if (vf.isInterpretedFrame()) {
|
||||
sb.append(" (Interpreted frame");
|
||||
}
|
||||
if (vf.mayBeImpreciseDbg()) {
|
||||
sb.append("; information may be imprecise");
|
||||
}
|
||||
sb.append(")");
|
||||
names.add(sb.toString());
|
||||
|
||||
// Keep registers in sender Frame
|
||||
Frame senderFrame = vf.getFrame()
|
||||
.sender((RegisterMap)vf.getRegisterMap().clone());
|
||||
senderSP = senderFrame.getSP();
|
||||
senderFP = senderFrame.getFP();
|
||||
senderPC = senderFrame.getPC();
|
||||
|
||||
// Get sender VFrame for next stack walking
|
||||
vf = vf.sender(true);
|
||||
}
|
||||
|
||||
return new JavaNameInfo(names.toArray(new String[0]), senderFP, senderPC);
|
||||
return new JavaNameInfo(names.toArray(new String[0]), senderSP, senderFP, senderPC);
|
||||
}
|
||||
|
||||
public void setVerbose(boolean verbose) {
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Empty resource bundle to be used with English default bundle as parent.
|
||||
# This is necessary to make English resources available on systems using
|
||||
# one of the supported non-English locales as default locale.
|
||||
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Empty resource bundle to be used with English default bundle as parent.
|
||||
# This is necessary to make English resources available on systems using
|
||||
# one of the supported non-English locales as default locale.
|
||||
@ -27,9 +27,11 @@ package jdk.tools.jlink.internal;
|
||||
import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.Configuration;
|
||||
@ -56,6 +58,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@ -238,6 +241,27 @@ public class JlinkTask {
|
||||
}
|
||||
|
||||
public static final String OPTIONS_RESOURCE = "jdk/tools/jlink/internal/options";
|
||||
// Release information stored in the java.base module
|
||||
private static final String JDK_RELEASE_RESOURCE = "jdk/internal/misc/resources/release.txt";
|
||||
|
||||
/**
|
||||
* Read the release.txt from the module.
|
||||
*/
|
||||
private static Optional<String> getReleaseInfo(ModuleReference mref) {
|
||||
try {
|
||||
Optional<InputStream> release = mref.open().open(JDK_RELEASE_RESOURCE);
|
||||
|
||||
if (release.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try (var r = new BufferedReader(new InputStreamReader(release.get()))) {
|
||||
return Optional.of(r.readLine());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
int run(String[] args) {
|
||||
if (log == null) {
|
||||
@ -410,7 +434,8 @@ public class JlinkTask {
|
||||
|
||||
// Sanity check version if we use JMODs
|
||||
if (!isLinkFromRuntime) {
|
||||
checkJavaBaseVersion(finder);
|
||||
assert(finder.find("java.base").isPresent());
|
||||
checkJavaBaseVersion(finder.find("java.base").get());
|
||||
}
|
||||
|
||||
// Determine the roots set
|
||||
@ -561,32 +586,34 @@ public class JlinkTask {
|
||||
return finder;
|
||||
}
|
||||
|
||||
private static String getCurrentRuntimeVersion() {
|
||||
ModuleReference current = ModuleLayer.boot()
|
||||
.configuration()
|
||||
.findModule("java.base")
|
||||
.get()
|
||||
.reference();
|
||||
// This jlink runtime should always have the release.txt
|
||||
return getReleaseInfo(current).get();
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the version of the module descriptor of java.base for compatibility
|
||||
* with the current runtime version.
|
||||
* Checks the release information of the java.base used for target image
|
||||
* for compatibility with the java.base used by jlink.
|
||||
*
|
||||
* @throws IllegalArgumentException the descriptor of java.base has no
|
||||
* version or the java.base version is not the same as the current runtime's
|
||||
* version.
|
||||
* @throws IllegalArgumentException If the `java.base` module reference `target`
|
||||
* is not compatible with this jlink.
|
||||
*/
|
||||
private static void checkJavaBaseVersion(ModuleFinder finder) {
|
||||
assert finder.find("java.base").isPresent();
|
||||
private static void checkJavaBaseVersion(ModuleReference target) {
|
||||
String currentRelease = getCurrentRuntimeVersion();
|
||||
|
||||
// use the version of java.base module, if present, as
|
||||
// the release version for multi-release JAR files
|
||||
ModuleDescriptor.Version v = finder.find("java.base").get()
|
||||
.descriptor().version().orElseThrow(() ->
|
||||
new IllegalArgumentException("No version in java.base descriptor")
|
||||
);
|
||||
String targetRelease = getReleaseInfo(target).orElseThrow(() -> new IllegalArgumentException(
|
||||
taskHelper.getMessage("err.jlink.version.missing", currentRelease)));
|
||||
|
||||
Runtime.Version version = Runtime.Version.parse(v.toString());
|
||||
if (Runtime.version().feature() != version.feature() ||
|
||||
Runtime.version().interim() != version.interim()) {
|
||||
// jlink version and java.base version do not match.
|
||||
// We do not (yet) support this mode.
|
||||
if (!currentRelease.equals(targetRelease)) {
|
||||
// Current runtime image and the target runtime image are not compatible build
|
||||
throw new IllegalArgumentException(taskHelper.getMessage("err.jlink.version.mismatch",
|
||||
Runtime.version().feature(), Runtime.version().interim(),
|
||||
version.feature(), version.interim()));
|
||||
currentRelease,
|
||||
targetRelease));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -130,7 +130,9 @@ err.runtime.link.patched.module=jlink does not support linking from the run-time
|
||||
err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH
|
||||
err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH
|
||||
err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH
|
||||
err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3}
|
||||
err.jlink.version.mismatch=jlink build ''{0}'' does not match target java.base build ''{1}''
|
||||
err.jlink.version.missing=jlink build ''{0}'' cannot find the build signature\
|
||||
\ in the java.base specified on module path, likely from an earlier build.
|
||||
err.automatic.module:automatic module cannot be used with jlink: {0} from {1}
|
||||
err.unknown.byte.order:unknown byte order {0}
|
||||
err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
|
||||
|
||||
109
test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp
Normal file
109
test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
#include "procMapsParser.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
TEST(ProcSmapsParserTest, ParseMappings) {
|
||||
const char* smaps_content =
|
||||
"7f5a00000000-7f5a00001000 r--p 00000000 00:00 0 [anon]\n"
|
||||
"Size: 4 kB\n"
|
||||
"KernelPageSize: 4 kB\n"
|
||||
"MMUPageSize: 4 kB\n"
|
||||
"Rss: 0 kB\n"
|
||||
"Pss: 0 kB\n"
|
||||
"Shared_Clean: 0 kB\n"
|
||||
"Shared_Dirty: 0 kB\n"
|
||||
"Private_Clean: 0 kB\n"
|
||||
"Private_Dirty: 0 kB\n"
|
||||
"Referenced: 0 kB\n"
|
||||
"Anonymous: 0 kB\n"
|
||||
"LazyFree: 0 kB\n"
|
||||
"AnonHugePages: 0 kB\n"
|
||||
"ShmemPmdMapped: 0 kB\n"
|
||||
"FilePmdMapped: 0 kB\n"
|
||||
"Shared_Hugetlb: 0 kB\n"
|
||||
"Private_Hugetlb: 0 kB\n"
|
||||
"Swap: 0 kB\n"
|
||||
"SwapPss: 0 kB\n"
|
||||
"Locked: 0 kB\n"
|
||||
"THPeligible: 0\n"
|
||||
"VmFlags: rd mr mw me ac \n"
|
||||
"7f5a00001000-7f5a00002000 rw-p 00000000 00:00 0 [anon]\n"
|
||||
"Size: 4 kB\n"
|
||||
"KernelPageSize: 4 kB\n"
|
||||
"MMUPageSize: 4 kB\n"
|
||||
"Rss: 4 kB\n"
|
||||
"Pss: 4 kB\n"
|
||||
"Shared_Clean: 0 kB\n"
|
||||
"Shared_Dirty: 0 kB\n"
|
||||
"Private_Clean: 0 kB\n"
|
||||
"Private_Dirty: 4 kB\n"
|
||||
"Referenced: 4 kB\n"
|
||||
"Anonymous: 4 kB\n"
|
||||
"LazyFree: 0 kB\n"
|
||||
"AnonHugePages: 0 kB\n"
|
||||
"ShmemPmdMapped: 0 kB\n"
|
||||
"FilePmdMapped: 0 kB\n"
|
||||
"Shared_Hugetlb: 0 kB\n"
|
||||
"Private_Hugetlb: 0 kB\n"
|
||||
"Swap: 0 kB\n"
|
||||
"SwapPss: 0 kB\n"
|
||||
"Locked: 0 kB\n"
|
||||
"THPeligible: 0\n"
|
||||
"VmFlags: rd wr mr mw me ac \n";
|
||||
|
||||
FILE* f = fmemopen((void*)smaps_content, strlen(smaps_content), "r");
|
||||
ASSERT_TRUE(f != nullptr);
|
||||
|
||||
ProcSmapsParser parser(f);
|
||||
ProcSmapsInfo info;
|
||||
|
||||
// First mapping
|
||||
ASSERT_TRUE(parser.parse_next(info));
|
||||
EXPECT_EQ((uintptr_t)info.from, 0x7f5a00000000ULL);
|
||||
EXPECT_EQ((uintptr_t)info.to, 0x7f5a00001000ULL);
|
||||
EXPECT_STREQ(info.prot, "r--p");
|
||||
EXPECT_TRUE(info.rd);
|
||||
EXPECT_FALSE(info.wr);
|
||||
|
||||
// Second mapping
|
||||
ASSERT_TRUE(parser.parse_next(info));
|
||||
EXPECT_EQ((uintptr_t)info.from, 0x7f5a00001000ULL);
|
||||
EXPECT_EQ((uintptr_t)info.to, 0x7f5a00002000ULL);
|
||||
EXPECT_STREQ(info.prot, "rw-p");
|
||||
EXPECT_TRUE(info.rd);
|
||||
EXPECT_TRUE(info.wr);
|
||||
|
||||
// End of file
|
||||
ASSERT_FALSE(parser.parse_next(info));
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#endif // LINUX
|
||||
@ -49,7 +49,6 @@ compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all
|
||||
|
||||
compiler/runtime/Test8168712.java#with-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x
|
||||
compiler/runtime/Test8168712.java#without-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x
|
||||
compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x
|
||||
|
||||
compiler/c2/Test8004741.java 8235801 generic-all
|
||||
compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all
|
||||
@ -143,7 +142,6 @@ serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64
|
||||
serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64
|
||||
|
||||
serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64
|
||||
serviceability/sa/TestJhsdbJstackMixedWithXComp.java 8371194 linux-x64
|
||||
|
||||
serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,7 +26,7 @@ import java.util.Random;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8251871 8285301
|
||||
* @bug 8251871 8285301 8371964
|
||||
* @summary Optimize arrayCopy using AVX-512 masked instructions.
|
||||
*
|
||||
* @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions
|
||||
@ -52,6 +52,9 @@ import java.util.Random;
|
||||
* compiler.arraycopy.TestArrayCopyDisjoint
|
||||
* @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+AlwaysAtomicAccesses
|
||||
* compiler.arraycopy.TestArrayCopyDisjoint
|
||||
* @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:UseAVX=3 -XX:MaxVectorSize=32 -XX:ArrayOperationPartialInlineSize=32 -XX:+StressIGVN
|
||||
* compiler.arraycopy.TestArrayCopyDisjoint
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
83
test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java
Normal file
83
test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2025 IBM Corporation. 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 8371464
|
||||
* @summary C2: assert(no_dead_loop) failed: dead loop detected
|
||||
* @run main/othervm -Xcomp -XX:CompileOnly=TestDeadLoopAtMergeMem::test TestDeadLoopAtMergeMem
|
||||
* @run main TestDeadLoopAtMergeMem
|
||||
*/
|
||||
|
||||
public class TestDeadLoopAtMergeMem {
|
||||
static final int N = 400;
|
||||
static long instanceCount;
|
||||
boolean bFld;
|
||||
float fArrFld[];
|
||||
static int iArrFld[] = new int[N];
|
||||
long vMeth_check_sum;
|
||||
|
||||
public static void main(String[] strArr) {
|
||||
TestDeadLoopAtMergeMem r = new TestDeadLoopAtMergeMem();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
r.test((short) 0, instanceCount);
|
||||
}
|
||||
}
|
||||
|
||||
void test(short s, long l) {
|
||||
int i11 = 6, i12, i13 = 6, i14 = 2;
|
||||
byte byArr2[] = new byte[N];
|
||||
init(byArr2, (byte) 4);
|
||||
helper(66.118169, i11);
|
||||
for (i12 = 3; i12 < 23; i12++) {
|
||||
if (bFld) {
|
||||
instanceCount = 5;
|
||||
} else if (bFld) {
|
||||
fArrFld[i12] = s;
|
||||
do {
|
||||
try {
|
||||
i11 = i13 / i12 % i12;
|
||||
} catch (ArithmeticException a_e) {
|
||||
}
|
||||
} while (i14 < 8);
|
||||
}
|
||||
}
|
||||
for (int i15 : iArrFld) {
|
||||
try {
|
||||
i11 = 1 / i15;
|
||||
} catch (ArithmeticException a_e) {
|
||||
}
|
||||
}
|
||||
vMeth_check_sum += i11;
|
||||
}
|
||||
|
||||
void helper(double d, int i) {
|
||||
int i1[] = new int[N];
|
||||
}
|
||||
|
||||
public static void init(byte[] a, byte seed) {
|
||||
for (int j = 0; j < a.length; j++) {
|
||||
a[j] = (byte) ((j % 2 == 0) ? seed + j : seed - j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,16 +23,18 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8367002
|
||||
* @bug 8367002 8370766
|
||||
* @summary Compilers might not generate handlers for recursive exceptions
|
||||
*
|
||||
* @compile IllegalAccessInCatch.jasm
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test
|
||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack
|
||||
* -XX:-TieredCompilation
|
||||
* TestAccessErrorInCatch
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test
|
||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack
|
||||
* -XX:TieredStopAtLevel=3
|
||||
* TestAccessErrorInCatch
|
||||
*/
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package compiler.loopopts.superword;
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
import java.util.Random;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8372451
|
||||
* @summary Test long reduction chain. Triggered bug with long chain of dead ReductionVector
|
||||
* vtnodes after optimize_move_non_strict_order_reductions_out_of_loop.
|
||||
* @library /test/lib /
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=1000 -XX:MaxVectorSize=8 -Xbatch
|
||||
* -XX:CompileCommand=compileonly,${test.main.class}::test
|
||||
* ${test.main.class}
|
||||
* @run main ${test.main.class}
|
||||
*/
|
||||
|
||||
public class TestLongReductionChain {
|
||||
static int RANGE = 1024*8;
|
||||
private static final Random RANDOM = Utils.getRandomInstance();
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] aI = generateI();
|
||||
int[] bI = generateI();
|
||||
int gold = test(aI, bI);
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
int result = test(aI, bI);
|
||||
if (result != gold) {
|
||||
throw new RuntimeException("wrong value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int[] generateI() {
|
||||
int[] a = new int[RANGE];
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
a[i] = RANDOM.nextInt();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// Test creates a very long reduction chain, especially with -XX:LoopUnrollLimit=1000.
|
||||
// Limiting the reduction vectors to 2 elements gets us a very long chain -XX:MaxVectorSize=8.
|
||||
// During VTransform::optimize this means a long chain of nodes needs to be found as dead.
|
||||
// Before the fix, this took too many rounds, and we hit an assert.
|
||||
static int test(int[] a, int[] b) {
|
||||
int s = 0;
|
||||
for (int i = 0; i < RANGE; i+=8) {
|
||||
s += a[i+0] * b[i+0];
|
||||
s += a[i+1] * b[i+1];
|
||||
s += a[i+2] * b[i+2];
|
||||
s += a[i+3] * b[i+3];
|
||||
|
||||
s += a[i+4] & b[i+4];
|
||||
s += a[i+5] & b[i+5];
|
||||
s += a[i+6] & b[i+6];
|
||||
s += a[i+7] & b[i+7];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.test.lib.JDKToolLauncher;
|
||||
@ -32,7 +33,7 @@ import jdk.test.lib.apps.LingeredApp;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @test id=xcomp
|
||||
* @bug 8370176
|
||||
* @requires vm.hasSA
|
||||
* @requires os.family == "linux"
|
||||
@ -40,6 +41,28 @@ import jdk.test.lib.process.OutputAnalyzer;
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackMixedWithXComp
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test id=xcomp-preserve-frame-pointer
|
||||
* @bug 8370176
|
||||
* @requires vm.hasSA
|
||||
* @requires os.family == "linux"
|
||||
* @requires os.arch == "amd64"
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackMixedWithXComp -XX:+PreserveFramePointer
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test id=xcomp-disable-tiered-compilation
|
||||
* @bug 8370176
|
||||
* @requires vm.hasSA
|
||||
* @requires os.family == "linux"
|
||||
* @requires os.arch == "amd64"
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackMixedWithXComp -XX:-TieredCompilation
|
||||
*/
|
||||
|
||||
|
||||
public class TestJhsdbJstackMixedWithXComp {
|
||||
|
||||
private static void runJstack(LingeredApp app) throws Exception {
|
||||
@ -89,8 +112,12 @@ public class TestJhsdbJstackMixedWithXComp {
|
||||
LingeredApp app = null;
|
||||
|
||||
try {
|
||||
List<String> jvmOpts = new ArrayList<>();
|
||||
jvmOpts.add("-Xcomp");
|
||||
jvmOpts.addAll(Arrays.asList(args));
|
||||
|
||||
app = new LingeredAppWithVirtualThread();
|
||||
LingeredApp.startApp(app, "-Xcomp");
|
||||
LingeredApp.startApp(app, jvmOpts.toArray(new String[0]));
|
||||
System.out.println("Started LingeredApp with pid " + app.getPid());
|
||||
runJstack(app);
|
||||
System.out.println("Test Completed");
|
||||
|
||||
@ -48,6 +48,9 @@ public class GC extends nsk.share.test.Tests {
|
||||
|
||||
public GCTestRunner(Test test, String[] args) {
|
||||
super(test, args);
|
||||
// GC tests often run at the brink of OOME, make sure
|
||||
// LocalRandom is loaded, initialized, and has enough memory.
|
||||
LocalRandom.init();
|
||||
}
|
||||
|
||||
private GCParams getGCParams(String[] args) {
|
||||
|
||||
@ -44,6 +44,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import jdk.test.lib.thread.TestThreadFactory;
|
||||
import nsk.share.TestFailure;
|
||||
import nsk.share.test.StressOptions;
|
||||
import nsk.share.test.Stresser;
|
||||
@ -82,16 +83,18 @@ public class StressTest implements Runnable {
|
||||
@Option(name="ignoreTestFailures", default_value="false", description="ignore failures of the executed tests")
|
||||
private boolean ignoreTestFailures;
|
||||
|
||||
class Worker extends Thread {
|
||||
class Worker implements Runnable {
|
||||
private final Random rand;
|
||||
|
||||
private volatile DefMethTest failedTest;
|
||||
private Throwable reason;
|
||||
private volatile long executedTests = 0;
|
||||
|
||||
public Worker(String id, long seed) {
|
||||
setName(id);
|
||||
this.rand = new Random(seed);
|
||||
private final Thread thread;
|
||||
|
||||
Worker(String id, long seed) {
|
||||
this.rand = new Random(seed);
|
||||
this.thread = TestThreadFactory.newThread(this, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -247,13 +250,13 @@ public class StressTest implements Runnable {
|
||||
}
|
||||
|
||||
for (Worker worker : workers) {
|
||||
worker.start();
|
||||
worker.thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void interruptWorkers() {
|
||||
for (Worker worker : workers) {
|
||||
worker.interrupt();
|
||||
worker.thread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,14 +264,14 @@ public class StressTest implements Runnable {
|
||||
boolean isFailed = false;
|
||||
|
||||
for (Worker worker : workers) {
|
||||
while (worker.isAlive()) {
|
||||
while (worker.thread.isAlive()) {
|
||||
try {
|
||||
worker.join();
|
||||
worker.thread.join();
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
|
||||
System.out.printf("%s: %s (executed: %d)\n",
|
||||
worker.getName(),
|
||||
worker.thread.getName(),
|
||||
worker.isFailed() ? "FAILED: " + worker.getFailedTest() : "PASSED",
|
||||
worker.getExecutedTests());
|
||||
|
||||
@ -288,7 +291,7 @@ public class StressTest implements Runnable {
|
||||
|
||||
private boolean workersAlive() {
|
||||
for (Worker worker : workers) {
|
||||
if (!worker.isAlive()) {
|
||||
if (!worker.thread.isAlive()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,36 +25,49 @@
|
||||
* @test
|
||||
* @bug 8368729
|
||||
* @summary Tests that passing invalid values to Kernel constructor
|
||||
* throws only IllegalArgumentException
|
||||
* throws only IllegalArgumentException or NullPointerException
|
||||
*/
|
||||
|
||||
import java.awt.image.Kernel;
|
||||
|
||||
public class KernelInitialisationTest {
|
||||
private static void expectIllegalArgumentException(Runnable code) {
|
||||
|
||||
private static void test(int width, int height, float[] data,
|
||||
Class<?> expected)
|
||||
{
|
||||
System.out.printf("Testing for width: %d, height: %d, data: %s%n",
|
||||
width, height, data == null ? "null" : "not null");
|
||||
Class<?> actual = null;
|
||||
try {
|
||||
code.run();
|
||||
throw new RuntimeException("Expected IllegalArgumentException" +
|
||||
" but no exception was thrown");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// we expect IllegalArgumentException
|
||||
new Kernel(width, height, data);
|
||||
} catch (Exception e) {
|
||||
actual = e.getClass();
|
||||
}
|
||||
if (actual != expected) {
|
||||
System.err.println("Expected: " + expected);
|
||||
System.err.println("Actual: " + actual);
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
}
|
||||
|
||||
private static void testKernel(int width, int height, float[] data) {
|
||||
System.out.println("Testing for width: " + width + ", height: "
|
||||
+ height + ", data: " + (data == null ? "null" : "not null"));
|
||||
expectIllegalArgumentException(() -> new Kernel(width, height, data));
|
||||
private static void testIAE(int width, int height, int len) {
|
||||
test(width, height, new float[len], IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
private static void testNPE(int width, int height) {
|
||||
test(width, height, null, NullPointerException.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
testKernel(-1, 1, new float[100]);
|
||||
testKernel(1, -1, new float[100]);
|
||||
testKernel(-1, -1, new float[100]);
|
||||
testKernel(1, 1, null);
|
||||
|
||||
int width = 50;
|
||||
int height = Integer.MAX_VALUE;
|
||||
testKernel(width, height, new float[100]);
|
||||
int[][] sizes = {{-1, 1}, {1, -1}, {-1, -1}, {50, Integer.MAX_VALUE}};
|
||||
int[] lens = {1, 100};
|
||||
for (int[] kernelSize : sizes) {
|
||||
for (int len : lens) {
|
||||
testIAE(kernelSize[0], kernelSize[1], len);
|
||||
}
|
||||
testNPE(kernelSize[0], kernelSize[1]);
|
||||
}
|
||||
testNPE(10, 10); // NPE on valid width and height
|
||||
testIAE(10, 10, 10); // IAE on valid width and height but small data
|
||||
}
|
||||
}
|
||||
|
||||
337
test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java
Normal file
337
test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 6185110
|
||||
* @summary Verify get/set/Pixels/Samples APIs for bad parameters.
|
||||
*
|
||||
* @run main SampleModelGetSamplesAndPixelsTest
|
||||
*/
|
||||
|
||||
import java.awt.image.BandedSampleModel;
|
||||
import java.awt.image.ComponentSampleModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.MultiPixelPackedSampleModel;
|
||||
import java.awt.image.PixelInterleavedSampleModel;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.SinglePixelPackedSampleModel;
|
||||
import java.util.Vector;
|
||||
|
||||
public class SampleModelGetSamplesAndPixelsTest {
|
||||
|
||||
static final int WIDTH = 100;
|
||||
static final int HEIGHT = 100;
|
||||
static final int DATATYPE = DataBuffer.TYPE_BYTE;
|
||||
static final int NUMBANDS = 4;
|
||||
static final int[] INTS = new int[WIDTH * HEIGHT + NUMBANDS];
|
||||
static final float[] FLOATS = new float[WIDTH * HEIGHT + NUMBANDS];
|
||||
static final double[] DOUBLES = new double[WIDTH * HEIGHT + NUMBANDS];
|
||||
static final int[][] COORDS = {
|
||||
{ 1, 1, 1, 1, -1 }, // bad band
|
||||
{ 1, 1, 1, 1, NUMBANDS }, // bad band
|
||||
{ 1, 1, -1, 1, 0 }, // negative w
|
||||
{ 1, 1, -1, -1, 0 }, // negative w and h
|
||||
{ -4, 1, 1, 1, 0 }, // negative x
|
||||
{ -4, -4, 1, 1, 0 }, // negative x and y
|
||||
{ WIDTH+10, 0, 1, 1, 0 }, // x > width
|
||||
{ 0, HEIGHT+10, 1, 1, 0 }, // y > height
|
||||
{ WIDTH+10, HEIGHT+10, 1, 1, 0 }, // both x > width and y > height
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
Vector<Class<? extends SampleModel>> classes = new Vector<Class<? extends SampleModel>>();
|
||||
|
||||
classes.add(ComponentSampleModel.class);
|
||||
classes.add(MultiPixelPackedSampleModel.class);
|
||||
classes.add(SinglePixelPackedSampleModel.class);
|
||||
classes.add(BandedSampleModel.class);
|
||||
classes.add(PixelInterleavedSampleModel.class);
|
||||
|
||||
for (Class<? extends SampleModel> c : classes) {
|
||||
doTest(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void noException(SampleModel sm) {
|
||||
System.err.println(sm);
|
||||
throw new RuntimeException("No expected exception");
|
||||
}
|
||||
|
||||
private static void doTest(Class<? extends SampleModel> c) {
|
||||
System.out.println("Test for: " + c.getName());
|
||||
SampleModel sm = createSampleModel(c);
|
||||
doTestNull(sm);
|
||||
for (int i = 0; i < COORDS.length; i++) {
|
||||
int x = COORDS[i][0];
|
||||
int y = COORDS[i][1];
|
||||
int w = COORDS[i][2];
|
||||
int h = COORDS[i][3];
|
||||
int b = COORDS[i][4];
|
||||
doTest(sm, x, y, w, h, b);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTestNull(SampleModel sm) {
|
||||
doTestNull(sm, INTS);
|
||||
doTestNull(sm, FLOATS);
|
||||
doTestNull(sm, DOUBLES);
|
||||
}
|
||||
|
||||
private static void doTestNull(SampleModel sm, int[] INTS) {
|
||||
try {
|
||||
sm.getSamples(1, 1, 1, 1, 0, INTS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getSamples(1, 1, 1, 1, 0, INTS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getPixels(1, 1, 1, 1, INTS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setPixels(1, 1, 1, 1, INTS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTestNull(SampleModel sm, float[] FLOATS) {
|
||||
try {
|
||||
sm.getSamples(1, 1, 1, 1, 0, FLOATS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getSamples(1, 1, 1, 1, 0, FLOATS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getPixels(1, 1, 1, 1, FLOATS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setPixels(1, 1, 1, 1, FLOATS, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTestNull(SampleModel sm, double[] DOUBLES) {
|
||||
try {
|
||||
sm.getSamples(1, 1, 1, 1, 0, DOUBLES, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getSamples(1, 1, 1, 1, 0, DOUBLES, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getPixels(1, 1, 1, 1, DOUBLES, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setPixels(1, 1, 1, 1, DOUBLES, null);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTest(SampleModel sm, int x, int y, int w, int h, int b) {
|
||||
doTest(sm, x, y, w, h, b, INTS);
|
||||
doTest(sm, x, y, w, h, b, FLOATS);
|
||||
doTest(sm, x, y, w, h, b, DOUBLES);
|
||||
}
|
||||
|
||||
private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, int[] INTS) {
|
||||
|
||||
// Now test each API with a non-null buffer and the specified values.
|
||||
DataBuffer db = sm.createDataBuffer();
|
||||
|
||||
try {
|
||||
sm.getSamples(x, y, w, h, b, INTS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setSamples(x, y, w, h, b, INTS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
if (b < 0 || b >= NUMBANDS) {
|
||||
return; // Values were to test illegal bands, skip the rest.
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getPixels(x, y, w, h, INTS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setPixels(x, y, w, h, INTS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, float[] FLOATS) {
|
||||
|
||||
// Now test each API with a non-null buffer and the specified values.
|
||||
DataBuffer db = sm.createDataBuffer();
|
||||
|
||||
try {
|
||||
sm.getSamples(x, y, w, h, b, FLOATS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setSamples(x, y, w, h, b, FLOATS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
if (b < 0 || b >= NUMBANDS) {
|
||||
return; // Values were to test illegal bands, skip the rest.
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getPixels(x, y, w, h, FLOATS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setPixels(x, y, w, h, FLOATS, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, double[] DOUBLES) {
|
||||
|
||||
// Now test each API with a non-null buffer and the specified values.
|
||||
DataBuffer db = sm.createDataBuffer();
|
||||
|
||||
try {
|
||||
sm.getSamples(x, y, w, h, b, DOUBLES, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setSamples(x, y, w, h, b, DOUBLES, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
if (b < 0 || b >= NUMBANDS) {
|
||||
return; // Values were to test illegal bands, skip the rest.
|
||||
}
|
||||
|
||||
try {
|
||||
sm.getPixels(x, y, w, h, DOUBLES, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setPixels(x, y, w, h, DOUBLES, db);
|
||||
noException(sm);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
sm.setDataElements(0, 0, null, db);
|
||||
noException(sm);
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static SampleModel createSampleModel(Class<? extends SampleModel> cls) {
|
||||
SampleModel res = null;
|
||||
|
||||
if (cls == ComponentSampleModel.class) {
|
||||
res = new ComponentSampleModel(DATATYPE, WIDTH, HEIGHT, 4, WIDTH * 4, new int[] { 0, 1, 2, 3 } );
|
||||
} else if (cls == MultiPixelPackedSampleModel.class) {
|
||||
res = new MultiPixelPackedSampleModel(DATATYPE, WIDTH, HEIGHT, 4);
|
||||
} else if (cls == SinglePixelPackedSampleModel.class) {
|
||||
res = new SinglePixelPackedSampleModel(DATATYPE, WIDTH, HEIGHT,
|
||||
new int[]{ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff });
|
||||
} else if (cls == BandedSampleModel.class) {
|
||||
res = new BandedSampleModel(DATATYPE, WIDTH, HEIGHT, NUMBANDS);
|
||||
} else if (cls == PixelInterleavedSampleModel.class) {
|
||||
res = new PixelInterleavedSampleModel(DATATYPE, WIDTH, HEIGHT, 4, WIDTH * 4, new int[] { 0, 1, 2, 3 });
|
||||
} else {
|
||||
throw new RuntimeException("Unknown class " + cls);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
329
test/jdk/java/lang/String/UnicodeCaseFoldingTest.java
Normal file
329
test/jdk/java/lang/String/UnicodeCaseFoldingTest.java
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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
|
||||
* @summary tests unicode case-folding based String comparison and equality
|
||||
* @bug 4397357
|
||||
* @library /lib/testlibrary/java/lang
|
||||
* @modules java.base/jdk.internal.lang:+open
|
||||
* @run junit/othervm
|
||||
* UnicodeCaseFoldingTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import jdk.internal.lang.CaseFolding;
|
||||
|
||||
public class UnicodeCaseFoldingTest {
|
||||
|
||||
@Test
|
||||
void testAllCommnFullCodePointsListedInCaseFoldinigTxt() throws Throwable {
|
||||
var filter = "^.*; [CF]; .*$"; // C=common, F=full, for full case folding
|
||||
var results = Files.lines(UCDFiles.CASEFOLDING)
|
||||
.filter(line -> !line.startsWith("#") && line.matches(filter))
|
||||
.map(line -> {
|
||||
var fields = line.split("; ");
|
||||
var cp = Integer.parseInt(fields[0], 16);
|
||||
fields = fields[2].trim().split(" ");
|
||||
var folding = new int[fields.length];
|
||||
for (int i = 0; i < folding.length; i++) {
|
||||
folding[i] = Integer.parseInt(fields[i], 16);
|
||||
}
|
||||
var source = new String(Character.toChars(cp));
|
||||
var expected = new String(folding, 0, folding.length);
|
||||
// (1) Verify the folding result matches expected
|
||||
assertEquals(expected, foldCase(source), "CaseFolding.fold(): ");
|
||||
|
||||
// (2) Verify compareToFoldCase() result
|
||||
assertEquals(0, source.compareToFoldCase(expected), "source.compareToFoldCase(expected)");
|
||||
assertEquals(0, expected.compareToFoldCase(source), "expected.compareToFoldCase(source)");
|
||||
|
||||
// (3) Verify equalsFoldCase() result
|
||||
assertEquals(true, source.equalsFoldCase(expected), "source.equalsFoldCase(expected)");
|
||||
assertEquals(true, expected.equalsFoldCase(source), "expected.equalsFoldCase(source)");
|
||||
return null;
|
||||
})
|
||||
.filter(error -> error != null)
|
||||
.toArray();
|
||||
assertEquals(0, results.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAllSimpleCodePointsListedInCaseFoldinigTxt() throws Throwable {
|
||||
// S=simple, for simple case folding. The simple case folding should still matches
|
||||
var filter = "^.*; [S]; .*$";
|
||||
var results = Files.lines(UCDFiles.CASEFOLDING)
|
||||
.filter(line -> !line.startsWith("#") && line.matches(filter))
|
||||
.map(line -> {
|
||||
var fields = line.split("; ");
|
||||
var cp = Integer.parseInt(fields[0], 16);
|
||||
fields = fields[2].trim().split(" ");
|
||||
var folding = new int[fields.length];
|
||||
for (int i = 0; i < folding.length; i++) {
|
||||
folding[i] = Integer.parseInt(fields[i], 16);
|
||||
}
|
||||
var source = new String(Character.toChars(cp));
|
||||
var expected = new String(folding, 0, folding.length);
|
||||
|
||||
// (1) Verify compareToFoldCase() result
|
||||
assertEquals(0, source.compareToFoldCase(expected), "source.compareToFoldCase(expected)");
|
||||
assertEquals(0, expected.compareToFoldCase(source), "expected.compareToFoldCase(source)");
|
||||
|
||||
// (2) Verify equalsFoldCase() result
|
||||
assertEquals(true, source.equalsFoldCase(expected), "source.equalsFoldCase(expected)");
|
||||
assertEquals(true, expected.equalsFoldCase(source), "expected.equalsFoldCase(source)");
|
||||
return null;
|
||||
})
|
||||
.filter(error -> error != null)
|
||||
.toArray();
|
||||
assertEquals(0, results.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllCodePointsFoldToThemselvesIfNotListed() throws Exception {
|
||||
// Collect all code points that appear in CaseFolding.txt
|
||||
var listed = Files.lines(UCDFiles.CASEFOLDING)
|
||||
.filter(line -> !line.startsWith("#") && line.matches("^.*; [CF]; .*$"))
|
||||
.map(line -> Integer.parseInt(line.split("; ")[0], 16))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
var failures = new ArrayList<String>();
|
||||
|
||||
// Scan BMP + Supplementary Plane 1 (U+0000..U+1FFFF)
|
||||
for (int cp = Character.MIN_CODE_POINT; cp <= 0x1FFFF; cp++) {
|
||||
if (!Character.isDefined(cp)) {
|
||||
continue; // skip undefined
|
||||
}
|
||||
if (Character.isSurrogate((char) cp)) {
|
||||
continue; // skip surrogate code units
|
||||
}
|
||||
if (listed.contains(cp)) {
|
||||
continue; // already tested separately
|
||||
}
|
||||
String s = new String(Character.toChars(cp));
|
||||
String folded = foldCase(s);
|
||||
if (!s.equals(folded)) {
|
||||
failures.add(String.format("Unexpected folding: U+%04X '%s' → '%s'", cp, s, folded));
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(0, failures.size(),
|
||||
() -> "Some unlisted code points folded unexpectedly:\n"
|
||||
+ String.join("\n", failures));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "CaseFold \"{0}\" → \"{1}\"")
|
||||
@MethodSource("caseFoldTestCases")
|
||||
void testIndividualCaseFolding(String input, String expected) {
|
||||
assertEquals(expected, foldCase(input));
|
||||
}
|
||||
|
||||
static Stream<Arguments> caseFoldTestCases() {
|
||||
return Stream.of(
|
||||
// ASCII simple cases
|
||||
Arguments.of("ABC", "abc"),
|
||||
Arguments.of("already", "already"),
|
||||
Arguments.of("MiXeD123", "mixed123"),
|
||||
// --- Latin-1 to non-Latin-1 fold ---
|
||||
Arguments.of("aBc\u00B5Efg", "abc\u03BCefg"), // "µ" → "μ"
|
||||
Arguments.of("test\u00B5\ud801\udc00X", "test\u03bc\ud801\udc28x"),
|
||||
// German Eszett
|
||||
Arguments.of("Stra\u00DFe", "strasse"), // "Straße"
|
||||
Arguments.of("\u1E9E", "ss"), // "ẞ" capital sharp S
|
||||
// Turkish dotted I / dotless i
|
||||
Arguments.of("I", "i"),
|
||||
Arguments.of("\u0130", "i\u0307"), // capital dotted I → "i + dot above"
|
||||
Arguments.of("\u0069\u0307", "i\u0307"), // small i + dot above remains
|
||||
Arguments.of("\u0131", "\u0131"), // "ı" (dotless i stays dotless)
|
||||
|
||||
// Greek special cases ---
|
||||
Arguments.of("\u039F\u03A3", "\u03BF\u03C3"), // "ΟΣ" → "οσ" final sigma always folds to normal sigma
|
||||
Arguments.of("\u1F88", "\u1F00\u03B9"), // "ᾈ" → "ἀι" Alpha with psili + ypogegrammeni
|
||||
Arguments.of("\u039C\u03AC\u03CA\u03BF\u03C2", "\u03BC\u03AC\u03CA\u03BF\u03C3"), // "Μάϊος" → "μάϊοσ"
|
||||
Arguments.of("\u1F08", "\u1F00"), // Ἀ (Capital Alpha with psili) → ἀ
|
||||
|
||||
// Supplementary Plane characters
|
||||
Arguments.of("\uD801\uDC00", "\uD801\uDC28"), // Deseret Capital Letter Long I → Small
|
||||
Arguments.of("\uD801\uDC01", "\uD801\uDC29"), // Deseret Capital Letter Long E → Small
|
||||
|
||||
// Supplementary inside ASCII
|
||||
Arguments.of("abc\uD801\uDC00def", "abc\uD801\uDC28def"),
|
||||
// Ligatures and compatibility folds
|
||||
Arguments.of("\uFB00", "ff"), // ff → ff
|
||||
Arguments.of("\uFB03", "ffi"), // ffi → ffi
|
||||
Arguments.of("\u212A", "k"), // Kelvin sign → k
|
||||
|
||||
Arguments.of("abc\uFB00def", "abcffdef"), // ff → ff
|
||||
Arguments.of("abc\uFB03def", "abcffidef"), // ffi → ffi
|
||||
Arguments.of("abc\u212Adef", "abckdef"), // Kelvin sign → k
|
||||
|
||||
// --- Fullwidth ---
|
||||
Arguments.of("\uFF21\uFF22\uFF23", "\uFF41\uFF42\uFF43"), // "ABC" → "abc"
|
||||
|
||||
// --- Armenian ---
|
||||
Arguments.of("\u0531", "\u0561"), // "Ա" → "ա"
|
||||
|
||||
// --- Cherokee ---
|
||||
Arguments.of("\u13A0", "\u13A0"), // Capital Cherokee A folds to itself
|
||||
Arguments.of("\uAB70", "\u13A0") // Small Cherokee A folds Capital Cherokee A
|
||||
);
|
||||
}
|
||||
|
||||
static Stream<Arguments> caseFoldEqualProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of("abc", "ABC"),
|
||||
Arguments.of("aBcDe", "AbCdE"),
|
||||
Arguments.of("\u00C0\u00E7", "\u00E0\u00C7"), // Àç vs àÇ
|
||||
Arguments.of("straße", "STRASSE"), // ß → ss
|
||||
Arguments.of("\uD83C\uDDE6", "\uD83C\uDDE6"), // 🇦 vs 🇦
|
||||
Arguments.of("\u1E9E", "ss"), // ẞ (capital sharp S)
|
||||
Arguments.of("\u03A3", "\u03C3"), // Σ vs σ (Greek Sigma)
|
||||
Arguments.of("\u03C3", "\u03C2"), // σ vs ς (Greek sigma/final sigma)
|
||||
Arguments.of("\u212B", "\u00E5"), // Å (Angstrom sign) vs å
|
||||
Arguments.of("\uFB00", "ff"), // ff (ligature)
|
||||
Arguments.of("\u01C5", "\u01C5"), // Dž (Latin capital D with small z with caron)
|
||||
Arguments.of("Caf\u00E9", "CAF\u00C9"), // Café vs CAFÉ
|
||||
Arguments.of("\u03BA\u03B1\u03BB\u03B7\u03BC\u03AD\u03C1\u03B1", "\u039A\u0391\u039B\u0397\u039C\u0388\u03A1\u0391"), // καλημέρα vs ΚΑΛΗΜΕΡΑ
|
||||
Arguments.of("\u4E2D\u56FD", "\u4E2D\u56FD"), // 中国
|
||||
Arguments.of("\u03B1", "\u0391"), // α vs Α (Greek alpha)
|
||||
Arguments.of("\u212B", "\u00C5"), // Å vs Å
|
||||
// from StringCompareToIgnoreCase
|
||||
Arguments.of("\u0100\u0102\u0104\u0106\u0108", "\u0100\u0102\u0104\u0106\u0109"), // ĀĂĄĆĈ vs ĀĂĄĆĉ
|
||||
Arguments.of("\u0101\u0103\u0105\u0107\u0109", "\u0100\u0102\u0104\u0106\u0109"), // āăąćĉ vs ĀĂĄĆĉ
|
||||
Arguments.of("\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc04",
|
||||
"\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c"), // 𐐀𐐁𐐂𐐃𐐄 vs 𐐀𐐁𐐂𐐃𐐬
|
||||
Arguments.of("\ud801\udc28\ud801\udc29\ud801\udc2a\ud801\udc2b\ud801\udc2c",
|
||||
"\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c") // 𐐨𐐩𐐪𐐫𐐬 vs 𐐀𐐁𐐂𐐃𐐬
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("caseFoldEqualProvider")
|
||||
void testcompareToFoldCaseEquals(String s1, String s2) {
|
||||
assertEquals(0, s1.compareToFoldCase(s2));
|
||||
assertEquals(0, s2.compareToFoldCase(s1));
|
||||
assertEquals(true, s1.equalsFoldCase(s2));
|
||||
assertEquals(true, s2.equalsFoldCase(s1));
|
||||
assertEquals(foldCase(s1), foldCase(s2));
|
||||
}
|
||||
|
||||
static Stream<Arguments> caseFoldOrderingProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of("asa", "aß", -1), // ß → ss → "asa" < "ass"
|
||||
Arguments.of("aß", "asa", +1),
|
||||
Arguments.of("a\u00DF", "ass", 0), // aß vs ass
|
||||
Arguments.of("\uFB03", "ffi", 0), // ffi (ligature)
|
||||
Arguments.of("\u00C5", "Z", 1), // Å vs Z
|
||||
Arguments.of("A", "\u00C0", -1), // A vs À
|
||||
Arguments.of("\u03A9", "\u03C9", 0), // Ω vs ω
|
||||
Arguments.of("\u03C2", "\u03C3", 0), // ς vs σ
|
||||
Arguments.of("\uD835\uDD23", "R", 1), // 𝔯 (fraktur r) vs R
|
||||
Arguments.of("\uFF26", "E", 1), // F (full-width F) vs E
|
||||
Arguments.of("\u00C9clair", "Eclair", 1), // Éclair vs Eclair
|
||||
Arguments.of("\u03bc\u00df", "\u00b5s", 1),
|
||||
Arguments.of("\u00b5s", "\u03bc\u00df", -1)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("caseFoldOrderingProvider")
|
||||
void testcompareToFoldCaseOrdering(String s1, String s2, int expectedSign) {
|
||||
int cmp = s1.compareToFoldCase(s2);
|
||||
assertEquals(expectedSign, Integer.signum(cmp));
|
||||
}
|
||||
|
||||
static Stream<Arguments> roundTripProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of("abc"),
|
||||
Arguments.of("ABC"),
|
||||
Arguments.of("straße"),
|
||||
Arguments.of("Àç"),
|
||||
Arguments.of("aß"),
|
||||
Arguments.of("\uFB02uff"), // fluff (ligature in "fluff")
|
||||
Arguments.of("\u00C9COLE") // ÉCOLE
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("roundTripProvider")
|
||||
void testCaseFoldRoundTrip(String s) {
|
||||
String folded = foldCase(s);
|
||||
assertEquals(0, s.compareToFoldCase(folded));
|
||||
assertEquals(0, folded.compareToFoldCase(s));
|
||||
assertEquals(true, s.equalsFoldCase(folded));
|
||||
assertEquals(true, folded.equalsFoldCase(s));
|
||||
}
|
||||
|
||||
// helper to test the integrity of folding mapping
|
||||
private static int[] longToFolding(long value) {
|
||||
int len = (int) (value >>> 48);
|
||||
if (len == 0) {
|
||||
return new int[]{(int) (value & 0xFFFFF)};
|
||||
} else {
|
||||
var folding = new int[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
folding[i] = (int) (value & 0xFFFF);
|
||||
value >>= 16;
|
||||
}
|
||||
return folding;
|
||||
}
|
||||
}
|
||||
|
||||
private static String foldCase(String s) {
|
||||
int first;
|
||||
int len = s.length();
|
||||
int cpCnt = 1;
|
||||
for (first = 0; first < len; first += cpCnt) {
|
||||
int cp = s.codePointAt(first);
|
||||
if (CaseFolding.isDefined(cp)) {
|
||||
break;
|
||||
}
|
||||
cpCnt = Character.charCount(cp);
|
||||
}
|
||||
if (first == len) {
|
||||
return s;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
sb.append(s, 0, first);
|
||||
for (int i = first; i < len; i += cpCnt) {
|
||||
int cp = s.codePointAt(i);
|
||||
int[] folded = longToFolding(CaseFolding.fold(cp));
|
||||
for (int f : folded) {
|
||||
sb.appendCodePoint(f);
|
||||
}
|
||||
cpCnt = Character.charCount(cp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.IOException;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8372787
|
||||
* @summary Test the behaviour of ModuleReader when using --patch-module
|
||||
* @comment patch the java.base module with a test specific resource
|
||||
* @compile/module=java.base java/lang/PatchedFoo.java
|
||||
* @run junit/othervm ${test.main.class}
|
||||
*/
|
||||
class PatchedModuleReaderTest {
|
||||
|
||||
private static ModuleReference patchedModuleRef;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
patchedModuleRef = ModuleFinder.ofSystem()
|
||||
.find("java.base")
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the resource that was patched into a module
|
||||
* is found by the ModuleReader.
|
||||
*/
|
||||
@Test
|
||||
void testResourceFound() throws Exception {
|
||||
try (ModuleReader reader = patchedModuleRef.open()) {
|
||||
String resourceName = "java/lang/PatchedFoo.class";
|
||||
Optional<URI> res = reader.find(resourceName);
|
||||
assertTrue(res.isPresent(), resourceName + " is missing in "
|
||||
+ patchedModuleRef.descriptor().name() + " module");
|
||||
URI uri = res.get();
|
||||
assertEquals("file", uri.getScheme(),
|
||||
"unexpected scheme in resource URI " + uri);
|
||||
assertTrue(uri.getPath().endsWith(resourceName),
|
||||
"unexpected path component " + uri.getPath()
|
||||
+ " in resource URI " + uri);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies the ModuleReader against a resource which isn't
|
||||
* expected to be part of the patched module.
|
||||
*/
|
||||
@Test
|
||||
void testResourceNotFound() throws Exception {
|
||||
try (ModuleReader reader = patchedModuleRef.open()) {
|
||||
String nonExistentResource = "foo/bar/NonExistent.class";
|
||||
Optional<URI> res = reader.find(nonExistentResource);
|
||||
assertTrue(res.isEmpty(), "unexpected resource " + nonExistentResource
|
||||
+ " in " + patchedModuleRef.descriptor().name() + " module");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This test opens a ModuleReader for a patched module, accumulates
|
||||
* the Stream of resources from that ModuleReader and then closes that
|
||||
* ModuleReader. It then verifies that the closed ModuleReader
|
||||
* throws the specified IOException whenever it is used for subsequent
|
||||
* operations on the Stream of resources.
|
||||
*/
|
||||
@Test
|
||||
void testIOExceptionAfterClose() throws Exception {
|
||||
ModuleReader reader;
|
||||
Stream<String> resources;
|
||||
try (var _ = reader = patchedModuleRef.open()) {
|
||||
// hold on to the available resources, to test them after the
|
||||
// ModuleReader is closed
|
||||
resources = reader.list();
|
||||
} // close the ModuleReader
|
||||
|
||||
// verify IOException is thrown by the closed ModuleReader
|
||||
|
||||
assertThrows(IOException.class, () -> reader.list(),
|
||||
"ModuleReader.list()");
|
||||
|
||||
resources.forEach(rn -> {
|
||||
assertThrows(IOException.class, () -> reader.read(rn),
|
||||
"ModuleReader.read(String)");
|
||||
assertThrows(IOException.class, () -> reader.open(rn),
|
||||
"ModuleReader.open(String)");
|
||||
assertThrows(IOException.class, () -> reader.find(rn),
|
||||
"ModuleReader.find(String)");
|
||||
});
|
||||
|
||||
// repeat the test for a non-existent resource
|
||||
String nonExistentResource = "foo/bar/NonExistent.class";
|
||||
assertThrows(IOException.class, () -> reader.read(nonExistentResource),
|
||||
"ModuleReader.read(String)");
|
||||
assertThrows(IOException.class, () -> reader.open(nonExistentResource),
|
||||
"ModuleReader.open(String)");
|
||||
assertThrows(IOException.class, () -> reader.find(nonExistentResource),
|
||||
"ModuleReader.find(String)");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang;
|
||||
|
||||
public class PatchedFoo {
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 8372258
|
||||
* @summary Test if a copy of the internal state is provided
|
||||
* @run junit ProtectInnerStateOfTypeVariableImplTest
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
final class ProtectInnerStateOfTypeVariableImplTest {
|
||||
|
||||
static final class Foo {
|
||||
public <X> Foo() {
|
||||
}
|
||||
|
||||
<X> X x() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMethod() throws NoSuchMethodException {
|
||||
Method method = Foo.class.getDeclaredMethod("x");
|
||||
TypeVariable<Method> tv = method.getTypeParameters()[0];
|
||||
|
||||
Method gd = tv.getGenericDeclaration();
|
||||
Method gd2 = tv.getGenericDeclaration();
|
||||
assertNotSame(gd, gd2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() throws NoSuchMethodException {
|
||||
Constructor<?> ctor = Foo.class.getConstructor();
|
||||
TypeVariable<? extends Constructor<?>> tv = ctor.getTypeParameters()[0];
|
||||
|
||||
Constructor<?> gd = tv.getGenericDeclaration();
|
||||
Constructor<?> gd2 = tv.getGenericDeclaration();
|
||||
assertNotSame(gd, gd2);
|
||||
}
|
||||
|
||||
}
|
||||
@ -28,6 +28,7 @@
|
||||
*/
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Starvation {
|
||||
@ -42,7 +43,7 @@ public class Starvation {
|
||||
while (count.get() == c) Thread.onSpinWait();
|
||||
return null; }};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
static void testSubmitExternalCallable() throws Exception {
|
||||
try (var pool = new ForkJoinPool(2)) {
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
var future1 = pool.submit(new AwaitCount(i));
|
||||
@ -53,4 +54,21 @@ public class Starvation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testSubmitAdaptedCallable() throws Exception {
|
||||
try (var pool = new ForkJoinPool(2)) {
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
var future1 = pool.submit(new AwaitCount(i));
|
||||
var future2 = pool.submit(ForkJoinTask.adapt(noop));
|
||||
future2.get();
|
||||
count.set(i + 1);
|
||||
future1.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testSubmitExternalCallable();
|
||||
testSubmitAdaptedCallable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 8372708
|
||||
* @summary Javadoc ignores "-locale" and uses default locale for all messages and texts
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestSupportedLocales
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestSupportedLocales extends JavadocTester {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
var tester = new TestSupportedLocales();
|
||||
tester.runTests();
|
||||
}
|
||||
|
||||
private final ToolBox tb = new ToolBox();
|
||||
|
||||
// A locale with an associated output message
|
||||
record LocalizedOutput(Locale locale, String message) {}
|
||||
|
||||
// Console messages are determined by the system default locale
|
||||
private final LocalizedOutput[] consoleOutput = new LocalizedOutput[] {
|
||||
new LocalizedOutput(Locale.CHINA, "\u6b63\u5728\u6784\u9020 Javadoc \u4fe1\u606f..."),
|
||||
new LocalizedOutput(Locale.GERMANY, "Javadoc-Informationen werden erstellt..."),
|
||||
new LocalizedOutput(Locale.JAPAN, "Javadoc\u60c5\u5831\u3092\u69cb\u7bc9\u3057\u3066\u3044\u307e\u3059..."),
|
||||
new LocalizedOutput(Locale.US, "Constructing Javadoc information..."),
|
||||
};
|
||||
|
||||
// Documentation messages are determined by the -locale option
|
||||
private final LocalizedOutput[] documentationOutput = new LocalizedOutput[] {
|
||||
new LocalizedOutput(Locale.CHINA, "\u7c7b\u548c\u63a5\u53e3"),
|
||||
new LocalizedOutput(Locale.GERMANY, "Klassen und Schnittstellen"),
|
||||
new LocalizedOutput(Locale.JAPAN, "\u30af\u30e9\u30b9\u3068\u30a4\u30f3\u30bf\u30d5\u30a7\u30fc\u30b9"),
|
||||
new LocalizedOutput(Locale.US, "Classes and Interfaces"),
|
||||
};
|
||||
|
||||
// Test all combinations of system and documentation locales
|
||||
@Test
|
||||
public void testSupportedLocales(Path base) throws Exception {
|
||||
var src = base.resolve("src");
|
||||
initSource(src);
|
||||
for (var console : consoleOutput) {
|
||||
for (var documentation : documentationOutput) {
|
||||
test(base, console, documentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test(Path base, LocalizedOutput console, LocalizedOutput documentation) throws Exception {
|
||||
var src = base.resolve("src");
|
||||
var out = base.resolve(console.locale + "-" + documentation.locale);
|
||||
Locale.setDefault(console.locale);
|
||||
javadoc("-d", out.toString(),
|
||||
"-locale", documentation.locale.toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
checkOutput(Output.OUT, true, console.message);
|
||||
checkOutput("p/package-summary.html", true, documentation.message);
|
||||
}
|
||||
|
||||
private void initSource(Path src) throws IOException {
|
||||
tb.writeJavaFiles(src, """
|
||||
package p;
|
||||
/**
|
||||
* A class.
|
||||
*/
|
||||
public class C {
|
||||
private C() { }
|
||||
}""");
|
||||
}
|
||||
}
|
||||
@ -798,6 +798,22 @@ public class SourceLauncherTest extends TestRunner {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateConstructor(Path base) throws IOException {
|
||||
tb.writeJavaFiles(base,
|
||||
"""
|
||||
class PrivateConstructor {
|
||||
private PrivateConstructor() {}
|
||||
void main() {}
|
||||
}
|
||||
""");
|
||||
testError(base.resolve("PrivateConstructor.java"), "",
|
||||
"""
|
||||
error: no non-private zero argument constructor found in class PrivateConstructor
|
||||
remove private from existing constructor or define as:
|
||||
public PrivateConstructor()""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbstractClassInstanceMain(Path base) throws IOException {
|
||||
tb.writeJavaFiles(base,
|
||||
@ -904,14 +920,6 @@ public class SourceLauncherTest extends TestRunner {
|
||||
}
|
||||
}
|
||||
|
||||
void checkContains(String name, String found, String expect) {
|
||||
expect = expect.replace("\n", tb.lineSeparator);
|
||||
out.println(name + ": " + found);
|
||||
if (!found.contains(expect)) {
|
||||
error("Expected output not found: " + expect);
|
||||
}
|
||||
}
|
||||
|
||||
void checkEqual(String name, List<String> found, List<String> expect) {
|
||||
out.println(name + ": " + found);
|
||||
tb.checkEqual(expect, found);
|
||||
@ -939,7 +947,6 @@ public class SourceLauncherTest extends TestRunner {
|
||||
}
|
||||
|
||||
void checkFault(String name, Throwable found, String expect) {
|
||||
expect = expect.replace("\n", tb.lineSeparator);
|
||||
out.println(name + ": " + found);
|
||||
if (found == null) {
|
||||
error("No exception thrown; expected Fault");
|
||||
@ -947,8 +954,14 @@ public class SourceLauncherTest extends TestRunner {
|
||||
if (!(found instanceof Fault)) {
|
||||
error("Unexpected exception; expected Fault");
|
||||
}
|
||||
if (!(found.getMessage().equals(expect))) {
|
||||
error("Unexpected detail message; expected: " + expect);
|
||||
String actual = found.getMessage();
|
||||
List<String> actualLines = actual.lines().toList();
|
||||
List<String> expectLines = expect.lines().toList();
|
||||
if (!(actualLines.equals(expectLines))) {
|
||||
error("Unexpected detail message; expected: \n"
|
||||
+ expect.indent(2)
|
||||
+ "\nactual:\n"
|
||||
+ actual.indent(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ import toolbox.Task;
|
||||
|
||||
public class HelpOutputColumnWidthTest extends TestRunner {
|
||||
|
||||
public static final int MAX_COLUMNS = 84;
|
||||
public static final int MAX_COLUMNS = 80;
|
||||
|
||||
protected ToolBox tb;
|
||||
|
||||
|
||||
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.openjdk.bench.java.lang;
|
||||
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/*
|
||||
* This benchmark naively explores String::compareToFoldCase performance
|
||||
*/
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Thread)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 5, time = 1)
|
||||
@Fork(3)
|
||||
public class StringCompareToFoldCase {
|
||||
|
||||
private String asciiUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private String asciiUpperLower = "ABCDEFGHIJKLMNOpqrstuvwxyz";
|
||||
private String asciiLower = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
private String asciiWithDF = "abcdßßßßßßßßßßßßßßßßWXYZ";
|
||||
private String asciiWithDFSS = "abcdssssssssssssssssßßßßßßßßWXYZ";
|
||||
|
||||
private String asciiLatine1 = "ABCDEFGHIJKLMNOpqrstuvwxyz0";
|
||||
private String asciiLatin1UTF16 = "abcdefghijklmnopqrstuvwxyz\u0391";
|
||||
|
||||
private String greekUpper = "\u0391\u0392\u0393\u0394\u0395\u0391\u0392\u0393\u0394\u0395"; // ΑΒΓΔΕ
|
||||
private String greekUpperLower = "\u0391\u0392\u0393\u0394\u0395\u0391\u0392\u0393\u0394\u03B5"; // ΑΒΓΔε
|
||||
private String greekLower = "\u03B1\u03B2\u03B3\u03B4\u03B5\u03B1\u03B2\u03B3\u03B4\u03B5"; // αβγδε
|
||||
|
||||
public String supUpper = "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc04";
|
||||
public String supUpperLower = "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c";
|
||||
public String supLower = "\ud801\udc28\ud801\udc29\ud801\udc2a\ud801\udc2b\ud801\udc2c";
|
||||
|
||||
@Benchmark
|
||||
public int asciiUpperLower() {
|
||||
return asciiUpper.compareToIgnoreCase(asciiUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int asciiLower() {
|
||||
return asciiUpper.compareToIgnoreCase(asciiLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int greekUpperLower() {
|
||||
return greekUpper.compareToIgnoreCase(greekUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int greekLower() {
|
||||
return greekUpper.compareToIgnoreCase(greekLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int latin1UTF16() {
|
||||
return asciiLatine1.compareToIgnoreCase(asciiLatin1UTF16);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int supUpperLower() {
|
||||
return supUpper.compareToIgnoreCase(supUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int supLower() {
|
||||
return supUpper.compareToIgnoreCase(supLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int asciiUpperLowerFC() {
|
||||
return asciiUpper.compareToFoldCase(asciiUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int asciiLowerFC() {
|
||||
return asciiUpper.compareToFoldCase(asciiLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int asciiWithDFFC() {
|
||||
return asciiWithDF.compareToFoldCase(asciiWithDFSS);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int greekUpperLowerFC() {
|
||||
return greekUpper.compareToFoldCase(greekUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int greekLowerFC() {
|
||||
return greekUpper.compareToFoldCase(greekLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int latin1UTF16FC() {
|
||||
return asciiLatine1.compareToFoldCase(asciiLatin1UTF16); }
|
||||
|
||||
@Benchmark
|
||||
public int supUpperLowerFC() {
|
||||
return supUpper.compareToFoldCase(supUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int supLowerFC() {
|
||||
return supUpper.compareToFoldCase(supLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean asciiUpperLowerEQ() {
|
||||
return asciiUpper.equalsIgnoreCase(asciiUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean asciiLowerEQ() {
|
||||
return asciiUpper.equalsIgnoreCase(asciiLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean greekUpperLowerEQ() {
|
||||
return greekUpper.equalsIgnoreCase(greekUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean greekLowerEQ() {
|
||||
return greekUpper.equalsIgnoreCase(greekLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean latin1UTF16EQ() {
|
||||
return asciiLatine1.equalsIgnoreCase(asciiLatin1UTF16);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean supUpperLowerEQ() {
|
||||
return supUpper.equalsIgnoreCase(supUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean supLowerEQ() {
|
||||
return supUpper.equalsIgnoreCase(supLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean asciiUpperLowerEQFC() {
|
||||
return asciiUpper.equalsFoldCase(asciiUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean asciiLowerEQFC() {
|
||||
return asciiUpper.equalsFoldCase(asciiLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean greekUpperLowerEQFC() {
|
||||
return greekUpper.equalsFoldCase(greekUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean greekLowerEQFC() {
|
||||
return greekUpper.equalsFoldCase(greekLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean latin1UTF16EQFC() {
|
||||
return asciiLatine1.equalsFoldCase(asciiLatin1UTF16);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean supUpperLowerEQFC() {
|
||||
return supUpper.equalsFoldCase(supUpperLower);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean supLowerEQFC() {
|
||||
return supUpper.equalsFoldCase(supLower);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user