+// These functions needs to be exported on Windows only
+#define DEBUGEXPORT WINDOWS_ONLY(JNIEXPORT)
+
// Support for showing register content on asserts/guarantees.
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
static char g_dummy;
@@ -303,20 +306,20 @@ class Command : public StackObj {
int Command::level = 0;
-extern "C" JNIEXPORT void blob(CodeBlob* cb) {
+extern "C" DEBUGEXPORT void blob(CodeBlob* cb) {
Command c("blob");
cb->print();
}
-extern "C" JNIEXPORT void dump_vtable(address p) {
+extern "C" DEBUGEXPORT void dump_vtable(address p) {
Command c("dump_vtable");
Klass* k = (Klass*)p;
k->vtable().print();
}
-extern "C" JNIEXPORT void nm(intptr_t p) {
+extern "C" DEBUGEXPORT void nm(intptr_t p) {
// Actually we look through all CodeBlobs (the nm name has been kept for backwards compatibility)
Command c("nm");
CodeBlob* cb = CodeCache::find_blob((address)p);
@@ -328,7 +331,7 @@ extern "C" JNIEXPORT void nm(intptr_t p) {
}
-extern "C" JNIEXPORT void disnm(intptr_t p) {
+extern "C" DEBUGEXPORT void disnm(intptr_t p) {
Command c("disnm");
CodeBlob* cb = CodeCache::find_blob((address) p);
if (cb != nullptr) {
@@ -343,7 +346,7 @@ extern "C" JNIEXPORT void disnm(intptr_t p) {
}
-extern "C" JNIEXPORT void printnm(intptr_t p) {
+extern "C" DEBUGEXPORT void printnm(intptr_t p) {
char buffer[256];
os::snprintf_checked(buffer, sizeof(buffer), "printnm: " INTPTR_FORMAT, p);
Command c(buffer);
@@ -357,13 +360,13 @@ extern "C" JNIEXPORT void printnm(intptr_t p) {
}
-extern "C" JNIEXPORT void universe() {
+extern "C" DEBUGEXPORT void universe() {
Command c("universe");
Universe::print_on(tty);
}
-extern "C" JNIEXPORT void verify() {
+extern "C" DEBUGEXPORT void verify() {
// try to run a verify on the entire system
// note: this may not be safe if we're not at a safepoint; for debugging,
// this manipulates the safepoint settings to avoid assertion failures
@@ -380,7 +383,7 @@ extern "C" JNIEXPORT void verify() {
}
-extern "C" JNIEXPORT void pp(void* p) {
+extern "C" DEBUGEXPORT void pp(void* p) {
Command c("pp");
FlagSetting fl(DisplayVMOutput, true);
if (p == nullptr) {
@@ -405,9 +408,9 @@ extern "C" JNIEXPORT void pp(void* p) {
}
-extern "C" JNIEXPORT void findpc(intptr_t x);
+extern "C" DEBUGEXPORT void findpc(intptr_t x);
-extern "C" JNIEXPORT void ps() { // print stack
+extern "C" DEBUGEXPORT void ps() { // print stack
if (Thread::current_or_null() == nullptr) return;
Command c("ps");
@@ -436,7 +439,7 @@ extern "C" JNIEXPORT void ps() { // print stack
}
}
-extern "C" JNIEXPORT void pfl() {
+extern "C" DEBUGEXPORT void pfl() {
// print frame layout
Command c("pfl");
JavaThread* p = JavaThread::active();
@@ -448,7 +451,7 @@ extern "C" JNIEXPORT void pfl() {
}
}
-extern "C" JNIEXPORT void psf() { // print stack frames
+extern "C" DEBUGEXPORT void psf() { // print stack frames
{
Command c("psf");
JavaThread* p = JavaThread::active();
@@ -462,19 +465,19 @@ extern "C" JNIEXPORT void psf() { // print stack frames
}
-extern "C" JNIEXPORT void threads() {
+extern "C" DEBUGEXPORT void threads() {
Command c("threads");
Threads::print(false, true);
}
-extern "C" JNIEXPORT void psd() {
+extern "C" DEBUGEXPORT void psd() {
Command c("psd");
SystemDictionary::print();
}
-extern "C" JNIEXPORT void pss() { // print all stacks
+extern "C" DEBUGEXPORT void pss() { // print all stacks
if (Thread::current_or_null() == nullptr) return;
Command c("pss");
Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true));
@@ -482,7 +485,7 @@ extern "C" JNIEXPORT void pss() { // print all stacks
// #ifndef PRODUCT
-extern "C" JNIEXPORT void debug() { // to set things up for compiler debugging
+extern "C" DEBUGEXPORT void debug() { // to set things up for compiler debugging
Command c("debug");
NOT_PRODUCT(WizardMode = true;)
PrintCompilation = true;
@@ -491,7 +494,7 @@ extern "C" JNIEXPORT void debug() { // to set things up for compil
}
-extern "C" JNIEXPORT void ndebug() { // undo debug()
+extern "C" DEBUGEXPORT void ndebug() { // undo debug()
Command c("ndebug");
PrintCompilation = false;
PrintInlining = PrintAssembly = false;
@@ -499,35 +502,35 @@ extern "C" JNIEXPORT void ndebug() { // undo debug()
}
-extern "C" JNIEXPORT void flush() {
+extern "C" DEBUGEXPORT void flush() {
Command c("flush");
tty->flush();
}
-extern "C" JNIEXPORT void events() {
+extern "C" DEBUGEXPORT void events() {
Command c("events");
Events::print();
}
-extern "C" JNIEXPORT Method* findm(intptr_t pc) {
+extern "C" DEBUGEXPORT Method* findm(intptr_t pc) {
Command c("findm");
nmethod* nm = CodeCache::find_nmethod((address)pc);
return (nm == nullptr) ? (Method*)nullptr : nm->method();
}
-extern "C" JNIEXPORT nmethod* findnm(intptr_t addr) {
+extern "C" DEBUGEXPORT nmethod* findnm(intptr_t addr) {
Command c("findnm");
return CodeCache::find_nmethod((address)addr);
}
-extern "C" JNIEXPORT void find(intptr_t x) {
+extern "C" DEBUGEXPORT void find(intptr_t x) {
Command c("find");
os::print_location(tty, x, false);
}
-extern "C" JNIEXPORT void findpc(intptr_t x) {
+extern "C" DEBUGEXPORT void findpc(intptr_t x) {
Command c("findpc");
os::print_location(tty, x, true);
}
@@ -538,13 +541,13 @@ extern "C" JNIEXPORT void findpc(intptr_t x) {
// call findclass("java/lang/Object", 0x3) -> find j.l.Object and disasm all of its methods
// call findmethod("*ang/Object*", "wait", 0xff) -> detailed disasm of all "wait" methods in j.l.Object
// call findmethod("*ang/Object*", "wait:(*J*)V", 0x1) -> list all "wait" methods in j.l.Object that have a long parameter
-extern "C" JNIEXPORT void findclass(const char* class_name_pattern, int flags) {
+extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) {
Command c("findclass");
ClassPrinter::print_flags_help(tty);
ClassPrinter::print_classes(class_name_pattern, flags, tty);
}
-extern "C" JNIEXPORT void findmethod(const char* class_name_pattern,
+extern "C" DEBUGEXPORT void findmethod(const char* class_name_pattern,
const char* method_pattern, int flags) {
Command c("findmethod");
ClassPrinter::print_flags_help(tty);
@@ -552,7 +555,7 @@ extern "C" JNIEXPORT void findmethod(const char* class_name_pattern,
}
// Need method pointer to find bcp
-extern "C" JNIEXPORT void findbcp(intptr_t method, intptr_t bcp) {
+extern "C" DEBUGEXPORT void findbcp(intptr_t method, intptr_t bcp) {
Command c("findbcp");
Method* mh = (Method*)method;
if (!mh->is_native()) {
@@ -563,7 +566,7 @@ extern "C" JNIEXPORT void findbcp(intptr_t method, intptr_t bcp) {
}
// check and decode a single u5 value
-extern "C" JNIEXPORT u4 u5decode(intptr_t addr) {
+extern "C" DEBUGEXPORT u4 u5decode(intptr_t addr) {
Command c("u5decode");
u1* arr = (u1*)addr;
size_t off = 0, lim = 5;
@@ -580,7 +583,7 @@ extern "C" JNIEXPORT u4 u5decode(intptr_t addr) {
// there is no limit on the count of items printed; the
// printing stops when an null is printed or at limit.
// See documentation for UNSIGNED5::Reader::print(count).
-extern "C" JNIEXPORT intptr_t u5p(intptr_t addr,
+extern "C" DEBUGEXPORT intptr_t u5p(intptr_t addr,
intptr_t limit,
int count) {
Command c("u5p");
@@ -630,7 +633,7 @@ void help() {
}
#ifndef PRODUCT
-extern "C" JNIEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack
+extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack
Command c("pns");
static char buf[O_BUFLEN];
Thread* t = Thread::current_or_null();
@@ -647,7 +650,7 @@ extern "C" JNIEXPORT void pns(void* sp, void* fp, void* pc) { // print native st
// WARNING: Only intended for use when debugging. Do not leave calls to
// pns2() in committed source (product or debug).
//
-extern "C" JNIEXPORT void pns2() { // print native stack
+extern "C" DEBUGEXPORT void pns2() { // print native stack
Command c("pns2");
static char buf[O_BUFLEN];
address lastpc = nullptr;
diff --git a/src/hotspot/share/utilities/spinYield.cpp b/src/hotspot/share/utilities/spinYield.cpp
index 59fecc4677d..0b331a49784 100644
--- a/src/hotspot/share/utilities/spinYield.cpp
+++ b/src/hotspot/share/utilities/spinYield.cpp
@@ -66,7 +66,7 @@ void SpinYield::report(outputStream* s) const {
if (_sleep_time.value() != 0) { // Report sleep duration, if slept.
separator = print_separator(s, separator);
s->print("sleep = " UINT64_FORMAT " usecs",
- _sleep_time.milliseconds());
+ _sleep_time.microseconds());
}
if (separator == initial_separator) {
s->print("no waiting");
diff --git a/src/java.base/share/classes/java/io/DataInputStream.java b/src/java.base/share/classes/java/io/DataInputStream.java
index 88cd4edc411..eab7a6e2f18 100644
--- a/src/java.base/share/classes/java/io/DataInputStream.java
+++ b/src/java.base/share/classes/java/io/DataInputStream.java
@@ -571,7 +571,7 @@ public final String readUTF() throws IOException {
* valid modified UTF-8 encoding of a Unicode string.
* @see java.io.DataInputStream#readUnsignedShort()
*/
- public static String readUTF(DataInput in) throws IOException {
+ public static final String readUTF(DataInput in) throws IOException {
int utflen = in.readUnsignedShort();
byte[] bytearr;
char[] chararr;
diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
index faf28b01bf0..a58595cb541 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
@@ -305,8 +305,7 @@
* and/or garbage collection behavior).
*
* In practice, the Java runtime lays out arrays in memory so that each n-byte element
- * occurs at an n-byte aligned physical address (except for {@code long[]} and
- * {@code double[]}, where alignment is platform-dependent, as explained below). The
+ * occurs at an n-byte aligned physical address. The
* runtime preserves this invariant even if the array is relocated during garbage
* collection. Access operations rely on this invariant to determine if the specified
* offset in a heap segment refers to an aligned address in physical memory.
@@ -325,26 +324,17 @@
* would correspond to physical address 1008 but offset 4 would correspond to
* physical address 1010.
*
The starting physical address of a {@code long[]} array will be 8-byte aligned
- * (e.g. 1000) on 64-bit platforms, so that successive long elements occur at
- * 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms,
- * a heap segment backed by a {@code long[]} array can be accessed at offsets
- * 0, 8, 16, 24, etc under an 8-byte alignment constraint. In addition, the segment
- * can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
- * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And,
- * the segment can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment
- * constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are
- * 2-byte aligned.
- * The starting physical address of a {@code long[]} array will be 4-byte aligned
- * (e.g. 1004) on 32-bit platforms, so that successive long elements occur at 4-byte
- * aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit platforms, a heap
- * segment backed by a {@code long[]} array can be accessed at offsets
- * 0, 4, 8, 12, etc under a 4-byte alignment constraint, because the target addresses
- * (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment can be accessed at
- * offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target
- * addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
+ * (e.g. 1000), so that successive long elements occur at 8-byte aligned addresses
+ * (e.g., 1000, 1008, 1016, 1024, etc.) A heap segment backed by a {@code long[]}
+ * array can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment
+ * constraint. In addition, the segment can be accessed at offsets 0, 4, 8, 12,
+ * etc under a 4-byte alignment constraint, because the target addresses (1000, 1004,
+ * 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets 0, 2,
+ * 4, 6, etc under a 2-byte alignment constraint, because the target addresses (e.g.
+ * 1000, 1002, 1004, 1006) are 2-byte aligned.
*
*
- * In other words, heap segments feature a (platform-dependent) maximum
+ * In other words, heap segments feature a maximum
* alignment which is derived from the size of the elements of the Java array backing the
* segment, as shown in the following table:
*
@@ -389,10 +379,7 @@
* In such circumstances, clients have two options. They can use a heap segment backed
* by a different array type (e.g. {@code long[]}), capable of supporting greater maximum
* alignment. More specifically, the maximum alignment associated with {@code long[]} is
- * set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent
- * value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is
- * guaranteed to provide at least 8-byte alignment in 64-bit platforms, but only 4-byte
- * alignment in 32-bit platforms:
+ * set to {@code ValueLayout.JAVA_LONG.byteAlignment()}, which is 8 bytes:
*
* {@snippet lang=java :
* MemorySegment longSegment = MemorySegment.ofArray(new long[10]);
diff --git a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
index e8740be387c..77bfe0e0209 100644
--- a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
@@ -47,9 +47,6 @@
* For instance, the byte order of these constants is set to the
* {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy
* to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}.
- * Moreover, the alignment constraint of {@link ValueLayout#JAVA_LONG} and
- * {@link ValueLayout#JAVA_DOUBLE} is set to 8 bytes on 64-bit platforms,
- * but only to 4 bytes on 32-bit platforms.
*
* @implSpec implementing classes and subclasses are immutable, thread-safe and
* value-based .
diff --git a/src/java.base/share/classes/java/lang/reflect/Proxy.java b/src/java.base/share/classes/java/lang/reflect/Proxy.java
index 209e8002989..e030fcdbf5d 100644
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java
@@ -618,6 +618,7 @@ private static boolean isDebug(String flag) {
private final List> interfaces;
private final ProxyClassContext context;
ProxyBuilder(ClassLoader loader, List> interfaces) {
+ Objects.requireNonNull(interfaces);
if (!VM.isModuleSystemInited()) {
throw new InternalError("Proxy is not supported until "
+ "module system is fully initialized");
diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
index b701aab7d0b..05d7f6a8405 100644
--- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
+++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
@@ -25,16 +25,18 @@
package java.lang.reflect;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.Label;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
-import jdk.internal.org.objectweb.asm.Type;
-import sun.invoke.util.Wrapper;
+import java.lang.classfile.*;
+import java.lang.classfile.constantpool.*;
+import java.lang.classfile.attribute.ExceptionsAttribute;
import sun.security.action.GetBooleanAction;
import java.io.IOException;
-import java.lang.invoke.MethodType;
+import static java.lang.classfile.ClassFile.*;
+import java.lang.classfile.attribute.StackMapFrameInfo;
+import java.lang.classfile.attribute.StackMapTableAttribute;
+import java.lang.constant.ClassDesc;
+import static java.lang.constant.ConstantDescs.*;
+import java.lang.constant.MethodTypeDesc;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -43,8 +45,8 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
-
-import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import java.util.Objects;
+import java.util.function.IntFunction;
/**
* ProxyGenerator contains the code to generate a dynamic proxy class
@@ -53,33 +55,34 @@
* The external interface to ProxyGenerator is the static
* "generateProxyClass" method.
*/
-final class ProxyGenerator extends ClassWriter {
- private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major();
- private static final String JL_CLASS = "java/lang/Class";
- private static final String JL_OBJECT = "java/lang/Object";
- private static final String JL_THROWABLE = "java/lang/Throwable";
- private static final String JL_CLASS_NOT_FOUND_EX = "java/lang/ClassNotFoundException";
- private static final String JL_ILLEGAL_ACCESS_EX = "java/lang/IllegalAccessException";
-
- private static final String JL_NO_CLASS_DEF_FOUND_ERROR = "java/lang/NoClassDefFoundError";
- private static final String JL_NO_SUCH_METHOD_EX = "java/lang/NoSuchMethodException";
- private static final String JL_NO_SUCH_METHOD_ERROR = "java/lang/NoSuchMethodError";
- private static final String JLI_LOOKUP = "java/lang/invoke/MethodHandles$Lookup";
- private static final String JLI_METHODHANDLES = "java/lang/invoke/MethodHandles";
-
- private static final String JLR_INVOCATION_HANDLER = "java/lang/reflect/InvocationHandler";
- private static final String JLR_PROXY = "java/lang/reflect/Proxy";
- private static final String JLR_UNDECLARED_THROWABLE_EX = "java/lang/reflect/UndeclaredThrowableException";
-
- private static final String LJL_CLASS = "Ljava/lang/Class;";
- private static final String LJL_CLASSLOADER = "Ljava/lang/ClassLoader;";
- private static final String LJLR_METHOD = "Ljava/lang/reflect/Method;";
- private static final String LJLR_INVOCATION_HANDLER = "Ljava/lang/reflect/InvocationHandler;";
-
- private static final String MJLR_INVOCATIONHANDLER = "(Ljava/lang/reflect/InvocationHandler;)V";
-
- private static final String NAME_CTOR = "";
- private static final String NAME_CLINIT = "";
+final class ProxyGenerator {
+
+ private static final ClassDesc
+ CD_ClassLoader = ClassDesc.ofInternalName("java/lang/ClassLoader"),
+ CD_ClassNotFoundException = ClassDesc.ofInternalName("java/lang/ClassNotFoundException"),
+ CD_IllegalAccessException = ClassDesc.ofInternalName("java/lang/IllegalAccessException"),
+ CD_InvocationHandler = ClassDesc.ofInternalName("java/lang/reflect/InvocationHandler"),
+ CD_Method = ClassDesc.ofInternalName("java/lang/reflect/Method"),
+ CD_NoClassDefFoundError = ClassDesc.ofInternalName("java/lang/NoClassDefFoundError"),
+ CD_NoSuchMethodError = ClassDesc.ofInternalName("java/lang/NoSuchMethodError"),
+ CD_NoSuchMethodException = ClassDesc.ofInternalName("java/lang/NoSuchMethodException"),
+ CD_Proxy = ClassDesc.ofInternalName("java/lang/reflect/Proxy"),
+ CD_UndeclaredThrowableException = ClassDesc.ofInternalName("java/lang/reflect/UndeclaredThrowableException");
+
+ private static final MethodTypeDesc
+ MTD_boolean = MethodTypeDesc.of(CD_boolean),
+ MTD_void_InvocationHandler = MethodTypeDesc.of(CD_void, CD_InvocationHandler),
+ MTD_void_String = MethodTypeDesc.of(CD_void, CD_String),
+ MTD_void_Throwable = MethodTypeDesc.of(CD_void, CD_Throwable),
+ MTD_Class = MethodTypeDesc.of(CD_Class),
+ MTD_Class_String_boolean_ClassLoader = MethodTypeDesc.of(CD_Class, CD_String, CD_boolean, CD_ClassLoader),
+ MTD_ClassLoader = MethodTypeDesc.of(CD_ClassLoader),
+ MTD_MethodHandles$Lookup = MethodTypeDesc.of(CD_MethodHandles_Lookup),
+ MTD_MethodHandles$Lookup_MethodHandles$Lookup = MethodTypeDesc.of(CD_MethodHandles_Lookup, CD_MethodHandles_Lookup),
+ MTD_Method_String_ClassArray = MethodTypeDesc.of(CD_Method, CD_String, CD_Class.arrayType()),
+ MTD_Object_Object_Method_ObjectArray = MethodTypeDesc.of(CD_Object, CD_Object, CD_Method, CD_Object.arrayType()),
+ MTD_String = MethodTypeDesc.of(CD_String);
+
private static final String NAME_LOOKUP_ACCESSOR = "proxyClassLookup";
private static final Class>[] EMPTY_CLASS_ARRAY = new Class>[0];
@@ -103,25 +106,122 @@ final class ProxyGenerator extends ClassWriter {
private static final ProxyMethod equalsMethod;
private static final ProxyMethod toStringMethod;
+ private static final ClassModel TEMPLATE;
+
+ private static final ClassEntry CE_Class;
+ private static final ClassEntry CE_ClassNotFoundException;
+ private static final ClassEntry CE_NoClassDefFoundError;
+ private static final ClassEntry CE_NoSuchMethodError;
+ private static final ClassEntry CE_NoSuchMethodException;
+ private static final ClassEntry CE_Object;
+ private static final ClassEntry CE_Throwable;
+ private static final ClassEntry CE_UndeclaredThrowableException;
+
+ private static final FieldRefEntry FRE_Proxy_h;
+
+ private static final InterfaceMethodRefEntry IMRE_InvocationHandler_invoke;
+
+ private static final MethodRefEntry MRE_Class_forName;
+ private static final MethodRefEntry MRE_Class_getClassLoader;
+ private static final MethodRefEntry MRE_Class_getMethod;
+ private static final MethodRefEntry MRE_NoClassDefFoundError_init;
+ private static final MethodRefEntry MRE_NoSuchMethodError_init;
+ private static final MethodRefEntry MRE_Throwable_getMessage;
+ private static final MethodRefEntry MRE_UndeclaredThrowableException_init;
+
+ private static final Utf8Entry UE_Method;
+
+ private static final List THROWABLE_STACK;
+
+ @SuppressWarnings("unchecked")
+ private static T entryByIndex(int index) {
+ return (T) TEMPLATE.constantPool().entryByIndex(index);
+ }
+
static {
+ // static template ClassModel holds pre-defined constant pool entries
+ // proxy transformed from the template shares the template constant pool
+ // each direct use of the template pool entry is significantly faster
+ var cc = ClassFile.of();
+ var ei = new int[21];
+ TEMPLATE = cc.parse(cc.build(CD_Proxy, clb -> {
+ clb.withSuperclass(CD_Proxy);
+ generateConstructor(clb);
+ generateLookupAccessor(clb);
+ var cp = clb.constantPool();
+
+ ei[0] = cp.classEntry(CD_Class).index();
+ ei[1] = cp.classEntry(CD_ClassNotFoundException).index();
+ ei[2] = cp.classEntry(CD_NoClassDefFoundError).index();
+ ei[3] = cp.classEntry(CD_NoSuchMethodError).index();
+ ei[4] = cp.classEntry(CD_NoSuchMethodException).index();
+ ei[5] = cp.classEntry(CD_Object).index();
+ ei[6] = cp.classEntry(CD_Throwable).index();
+ ei[7] = cp.classEntry(CD_UndeclaredThrowableException).index();
+
+ ei[8] = cp.fieldRefEntry(CD_Proxy, handlerFieldName, CD_InvocationHandler).index();
+
+ ei[9] = cp.interfaceMethodRefEntry(CD_InvocationHandler, "invoke", MTD_Object_Object_Method_ObjectArray).index();
+
+ ei[10] = cp.methodRefEntry(CD_Class, "forName", MTD_Class_String_boolean_ClassLoader).index();
+ ei[11] = cp.methodRefEntry(CD_Class, "getClassLoader", MTD_ClassLoader).index();
+ ei[12] = cp.methodRefEntry(CD_Class, "getMethod", MTD_Method_String_ClassArray).index();
+ ei[13] = cp.methodRefEntry(CD_NoClassDefFoundError, INIT_NAME, MTD_void_String).index();
+ ei[14] = cp.methodRefEntry(CD_NoSuchMethodError, INIT_NAME, MTD_void_String).index();
+ ei[15] = cp.methodRefEntry(CD_Throwable, "getMessage", MTD_String).index();
+ ei[16] = cp.methodRefEntry(CD_UndeclaredThrowableException, INIT_NAME, MTD_void_Throwable).index();
+
+ ei[17] = cp.utf8Entry(CD_Method).index();
+
+ ei[18] = cp.utf8Entry("m0").index();
+ ei[19] = cp.utf8Entry("m1").index();
+ ei[20] = cp.utf8Entry("m2").index();
+ }));
+
+ CE_Class = entryByIndex(ei[0]);
+ CE_ClassNotFoundException = entryByIndex(ei[1]);
+ CE_NoClassDefFoundError = entryByIndex(ei[2]);
+ CE_NoSuchMethodError = entryByIndex(ei[3]);
+ CE_NoSuchMethodException = entryByIndex(ei[4]);
+ CE_Object = entryByIndex(ei[5]);
+ CE_Throwable = entryByIndex(ei[6]);
+ CE_UndeclaredThrowableException = entryByIndex(ei[7]);
+
+ FRE_Proxy_h = entryByIndex(ei[8]);
+
+ IMRE_InvocationHandler_invoke = entryByIndex(ei[9]);
+
+ MRE_Class_forName = entryByIndex(ei[10]);
+ MRE_Class_getClassLoader = entryByIndex(ei[11]);
+ MRE_Class_getMethod = entryByIndex(ei[12]);
+ MRE_NoClassDefFoundError_init = entryByIndex(ei[13]);
+ MRE_NoSuchMethodError_init = entryByIndex(ei[14]);
+ MRE_Throwable_getMessage = entryByIndex(ei[15]);
+ MRE_UndeclaredThrowableException_init = entryByIndex(ei[16]);
+
+ UE_Method = entryByIndex(ei[17]);
+
try {
- hashCodeMethod = new ProxyMethod(Object.class.getMethod("hashCode"), "m0");
- equalsMethod = new ProxyMethod(Object.class.getMethod("equals", Object.class), "m1");
- toStringMethod = new ProxyMethod(Object.class.getMethod("toString"), "m2");
+ hashCodeMethod = new ProxyMethod(Object.class.getMethod("hashCode"), entryByIndex(ei[18]));
+ equalsMethod = new ProxyMethod(Object.class.getMethod("equals", Object.class), entryByIndex(ei[19]));
+ toStringMethod = new ProxyMethod(Object.class.getMethod("toString"), entryByIndex(ei[20]));
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
+
+ THROWABLE_STACK = List.of(StackMapFrameInfo.ObjectVerificationTypeInfo.of(CE_Throwable));
}
/**
- * Class loader
+ * Classfile context
*/
- private final ClassLoader loader;
+ private final ClassFile classfileContext;
+ private final ConstantPoolBuilder cp;
/**
* Name of proxy class
*/
- private final String className;
+ private ClassEntry classEntry;
/**
* Proxy interfaces
@@ -155,9 +255,12 @@ final class ProxyGenerator extends ClassWriter {
*/
private ProxyGenerator(ClassLoader loader, String className, List> interfaces,
int accessFlags) {
- super(ClassWriter.COMPUTE_FRAMES);
- this.loader = loader;
- this.className = className;
+ this.classfileContext = ClassFile.of(
+ ClassFile.StackMapsOption.DROP_STACK_MAPS,
+ ClassFile.ClassHierarchyResolverOption.of(
+ ClassHierarchyResolver.ofClassLoading(loader).cached()));
+ this.cp = ConstantPoolBuilder.of(TEMPLATE);
+ this.classEntry = cp.classEntry(ClassDesc.of(className));
this.interfaces = interfaces;
this.accessFlags = accessFlags;
}
@@ -174,6 +277,7 @@ static byte[] generateProxyClass(ClassLoader loader,
final String name,
List> interfaces,
int accessFlags) {
+ Objects.requireNonNull(interfaces);
ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);
final byte[] classFile = gen.generateClassFile();
@@ -185,7 +289,7 @@ public Void run() {
int i = name.lastIndexOf('.');
Path path;
if (i > 0) {
- Path dir = Path.of(dotToSlash(name.substring(0, i)));
+ Path dir = Path.of(name.substring(0, i).replace('.', '/'));
Files.createDirectories(dir);
path = dir.resolve(name.substring(i + 1) + ".class");
} else {
@@ -205,20 +309,22 @@ public Void run() {
}
/**
- * Return an array of the class and interface names from an array of Classes.
- *
- * @param classes an array of classes or interfaces
- * @return the array of class and interface names; or null if classes is
- * null or empty
+ * {@return the entries of the given type}
+ * @param types the {@code Class} objects, not primitive types nor array types
+ */
+ private static ClassEntry[] toClassEntries(ConstantPoolBuilder cp, List> types) {
+ var ces = new ClassEntry[types.size()];
+ for (int i = 0; i < ces.length; i++)
+ ces[i] = cp.classEntry(cp.utf8Entry(types.get(i).getName().replace('.', '/')));
+ return ces;
+ }
+
+ /**
+ * {@return the {@code ClassDesc} of the given type}
+ * @param type the {@code Class} object
*/
- private static String[] typeNames(List> classes) {
- if (classes == null || classes.size() == 0)
- return null;
- int size = classes.size();
- String[] ifaces = new String[size];
- for (int i = 0; i < size; i++)
- ifaces[i] = dotToSlash(classes.get(i).getName());
- return ifaces;
+ private static ClassDesc toClassDesc(Class> type) {
+ return ClassDesc.ofDescriptor(type.descriptorString());
}
/**
@@ -387,34 +493,6 @@ private static List> computeUniqueCatchList(Class>[] exceptions) {
return uniqueList;
}
- /**
- * Convert a fully qualified class name that uses '.' as the package
- * separator, the external representation used by the Java language
- * and APIs, to a fully qualified class name that uses '/' as the
- * package separator, the representation used in the class file
- * format (see JVMS section {@jvms 4.2}).
- */
- private static String dotToSlash(String name) {
- return name.replace('.', '/');
- }
-
- /**
- * Return the number of abstract "words", or consecutive local variable
- * indexes, required to contain a value of the given type. See JVMS
- * section {@jvms 3.6.1}.
- *
- * Note that the original version of the JVMS contained a definition of
- * this abstract notion of a "word" in section 3.4, but that definition
- * was removed for the second edition.
- */
- private static int getWordsPerType(Class> type) {
- if (type == long.class || type == double.class) {
- return 2;
- } else {
- return 1;
- }
- }
-
/**
* Add to the given list all of the types in the "from" array that
* are not already contained in the list and are assignable to at
@@ -439,17 +517,6 @@ private static void collectCompatibleTypes(Class>[] from,
}
}
- /**
- * Returns the {@link ClassLoader} to be used by the default implementation of {@link
- * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
- * default.
- *
- * @return ClassLoader
- */
- protected ClassLoader getClassLoader() {
- return loader;
- }
-
/**
* Generate a class file for the proxy class. This method drives the
* class file generation process.
@@ -461,9 +528,6 @@ protected ClassLoader getClassLoader() {
* generated with no loadable descriptors attributes as it essentially has no effect.
*/
private byte[] generateClassFile() {
- visit(CLASSFILE_VERSION, accessFlags, dotToSlash(className), null,
- JLR_PROXY, typeNames(interfaces));
-
/*
* Add proxy methods for the hashCode, equals,
* and toString methods of java.lang.Object. This is done before
@@ -481,7 +545,7 @@ private byte[] generateClassFile() {
for (Class> intf : interfaces) {
for (Method m : intf.getMethods()) {
if (!Modifier.isStatic(m.getModifiers())) {
- addProxyMethod(m, intf);
+ addProxyMethod(m, intf, cp);
}
}
}
@@ -494,22 +558,23 @@ private byte[] generateClassFile() {
checkReturnTypes(sigmethods);
}
- generateConstructor();
+ return classfileContext.build(classEntry, cp, clb -> {
+ TEMPLATE.forEach(clb);
+ clb.withFlags(accessFlags);
+ clb.withInterfaces(toClassEntries(cp, interfaces));
- for (List sigmethods : proxyMethods.values()) {
- for (ProxyMethod pm : sigmethods) {
- // add static field for the Method object
- visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
- LJLR_METHOD, null, null);
+ for (List sigmethods : proxyMethods.values()) {
+ for (ProxyMethod pm : sigmethods) {
+ // add static field for the Method object
+ clb.withField(pm.methodFieldName, UE_Method, ACC_PRIVATE | ACC_STATIC | ACC_FINAL);
- // Generate code for proxy method
- pm.generateMethod(this, className);
+ // Generate code for proxy method
+ pm.generateMethod(clb, classEntry);
+ }
}
- }
- generateStaticInitializer();
- generateLookupAccessor();
- return toByteArray();
+ generateStaticInitializer(clb);
+ });
}
/**
@@ -525,7 +590,7 @@ private byte[] generateClassFile() {
* passed to the invocation handler's "invoke" method for a given
* set of duplicate methods.
*/
- private void addProxyMethod(Method m, Class> fromClass) {
+ private void addProxyMethod(Method m, Class> fromClass, ConstantPoolBuilder cp) {
Class> returnType = m.getReturnType();
Class>[] exceptionTypes = m.getSharedExceptionTypes();
@@ -551,7 +616,7 @@ private void addProxyMethod(Method m, Class> fromClass) {
}
sigmethods.add(new ProxyMethod(m, sig, m.getSharedParameterTypes(), returnType,
exceptionTypes, fromClass,
- "m" + proxyMethodCount++));
+ cp.utf8Entry("m" + proxyMethodCount++)));
}
/**
@@ -569,82 +634,51 @@ private void addProxyMethod(ProxyMethod pm) {
/**
* Generate the constructor method for the proxy class.
*/
- private void generateConstructor() {
- MethodVisitor ctor = visitMethod(Modifier.PUBLIC, NAME_CTOR,
- MJLR_INVOCATIONHANDLER, null, null);
- ctor.visitParameter(null, 0);
- ctor.visitCode();
- ctor.visitVarInsn(ALOAD, 0);
- ctor.visitVarInsn(ALOAD, 1);
- ctor.visitMethodInsn(INVOKESPECIAL, JLR_PROXY, NAME_CTOR,
- MJLR_INVOCATIONHANDLER, false);
- ctor.visitInsn(RETURN);
-
- // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
- ctor.visitMaxs(-1, -1);
- ctor.visitEnd();
+ private static void generateConstructor(ClassBuilder clb) {
+ clb.withMethodBody(INIT_NAME, MTD_void_InvocationHandler, ACC_PUBLIC, cob -> cob
+ .aload(cob.receiverSlot())
+ .aload(cob.parameterSlot(0))
+ .invokespecial(CD_Proxy, INIT_NAME, MTD_void_InvocationHandler)
+ .return_());
}
/**
* Generate the static initializer method for the proxy class.
*/
- private void generateStaticInitializer() {
-
- MethodVisitor mv = visitMethod(Modifier.STATIC, NAME_CLINIT,
- "()V", null, null);
- mv.visitCode();
- Label L_startBlock = new Label();
- Label L_endBlock = new Label();
- Label L_NoMethodHandler = new Label();
- Label L_NoClassHandler = new Label();
-
- mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_NoMethodHandler,
- JL_NO_SUCH_METHOD_EX);
- mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_NoClassHandler,
- JL_CLASS_NOT_FOUND_EX);
-
- // Put ClassLoader at local variable index 0, used by
- // Class.forName(String, boolean, ClassLoader) calls
- mv.visitLdcInsn(Type.getObjectType(dotToSlash(className)));
- mv.visitMethodInsn(INVOKEVIRTUAL, JL_CLASS,
- "getClassLoader", "()" + LJL_CLASSLOADER, false);
- mv.visitVarInsn(ASTORE, 0);
-
- mv.visitLabel(L_startBlock);
- for (List sigmethods : proxyMethods.values()) {
- for (ProxyMethod pm : sigmethods) {
- pm.codeFieldInitialization(mv, className);
+ private void generateStaticInitializer(ClassBuilder clb) {
+ clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> {
+ // Put ClassLoader at local variable index 0, used by
+ // Class.forName(String, boolean, ClassLoader) calls
+ cob.ldc(classEntry)
+ .invokevirtual(MRE_Class_getClassLoader)
+ .astore(0);
+ var ts = cob.newBoundLabel();
+ for (List sigmethods : proxyMethods.values()) {
+ for (ProxyMethod pm : sigmethods) {
+ pm.codeFieldInitialization(cob, classEntry);
+ }
}
- }
- mv.visitInsn(RETURN);
- mv.visitLabel(L_endBlock);
- // Generate exception handler
-
- mv.visitLabel(L_NoMethodHandler);
- mv.visitVarInsn(ASTORE, 1);
- mv.visitTypeInsn(Opcodes.NEW, JL_NO_SUCH_METHOD_ERROR);
- mv.visitInsn(DUP);
- mv.visitVarInsn(ALOAD, 1);
- mv.visitMethodInsn(INVOKEVIRTUAL, JL_THROWABLE,
- "getMessage", "()Ljava/lang/String;", false);
- mv.visitMethodInsn(INVOKESPECIAL, JL_NO_SUCH_METHOD_ERROR,
- "", "(Ljava/lang/String;)V", false);
- mv.visitInsn(ATHROW);
-
- mv.visitLabel(L_NoClassHandler);
- mv.visitVarInsn(ASTORE, 1);
- mv.visitTypeInsn(Opcodes.NEW, JL_NO_CLASS_DEF_FOUND_ERROR);
- mv.visitInsn(DUP);
- mv.visitVarInsn(ALOAD, 1);
- mv.visitMethodInsn(INVOKEVIRTUAL, JL_THROWABLE,
- "getMessage", "()Ljava/lang/String;", false);
- mv.visitMethodInsn(INVOKESPECIAL, JL_NO_CLASS_DEF_FOUND_ERROR,
- "", "(Ljava/lang/String;)V", false);
- mv.visitInsn(ATHROW);
-
- // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
- mv.visitMaxs(-1, -1);
- mv.visitEnd();
+ cob.return_();
+ var c1 = cob.newBoundLabel();
+ cob.exceptionCatch(ts, c1, c1, CE_NoSuchMethodException)
+ .new_(CE_NoSuchMethodError)
+ .dup_x1()
+ .swap()
+ .invokevirtual(MRE_Throwable_getMessage)
+ .invokespecial(MRE_NoSuchMethodError_init)
+ .athrow();
+ var c2 = cob.newBoundLabel();
+ cob.exceptionCatch(ts, c1, c2, CE_ClassNotFoundException)
+ .new_(CE_NoClassDefFoundError)
+ .dup_x1()
+ .swap()
+ .invokevirtual(MRE_Throwable_getMessage)
+ .invokespecial(MRE_NoClassDefFoundError_init)
+ .athrow()
+ .with(StackMapTableAttribute.of(List.of(
+ StackMapFrameInfo.of(c1, List.of(), THROWABLE_STACK),
+ StackMapFrameInfo.of(c2, List.of(), THROWABLE_STACK))));
+ });
}
/**
@@ -652,39 +686,28 @@ private void generateStaticInitializer() {
* on this proxy class if the caller's lookup class is java.lang.reflect.Proxy;
* otherwise, IllegalAccessException is thrown
*/
- private void generateLookupAccessor() {
- MethodVisitor mv = visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_LOOKUP_ACCESSOR,
- "(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/MethodHandles$Lookup;", null,
- new String[] { JL_ILLEGAL_ACCESS_EX });
- mv.visitCode();
- Label L_illegalAccess = new Label();
-
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "lookupClass",
- "()Ljava/lang/Class;", false);
- mv.visitLdcInsn(Type.getType(Proxy.class));
- mv.visitJumpInsn(IF_ACMPNE, L_illegalAccess);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "hasFullPrivilegeAccess",
- "()Z", false);
- mv.visitJumpInsn(IFEQ, L_illegalAccess);
- mv.visitMethodInsn(INVOKESTATIC, JLI_METHODHANDLES, "lookup",
- "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
- mv.visitInsn(ARETURN);
-
- mv.visitLabel(L_illegalAccess);
- mv.visitTypeInsn(Opcodes.NEW, JL_ILLEGAL_ACCESS_EX);
- mv.visitInsn(DUP);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "toString",
- "()Ljava/lang/String;", false);
- mv.visitMethodInsn(INVOKESPECIAL, JL_ILLEGAL_ACCESS_EX,
- "", "(Ljava/lang/String;)V", false);
- mv.visitInsn(ATHROW);
-
- // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
- mv.visitMaxs(-1, -1);
- mv.visitEnd();
+ private static void generateLookupAccessor(ClassBuilder clb) {
+ clb.withMethod(NAME_LOOKUP_ACCESSOR,
+ MTD_MethodHandles$Lookup_MethodHandles$Lookup,
+ ACC_PRIVATE | ACC_STATIC,
+ mb -> mb.with(ExceptionsAttribute.of(List.of(mb.constantPool().classEntry(CD_IllegalAccessException))))
+ .withCode(cob -> cob
+ .block(blockBuilder -> blockBuilder
+ .aload(cob.parameterSlot(0))
+ .invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class)
+ .constantInstruction(Opcode.LDC, CD_Proxy)
+ .if_acmpne(blockBuilder.breakLabel())
+ .aload(cob.parameterSlot(0))
+ .invokevirtual(CD_MethodHandles_Lookup, "hasFullPrivilegeAccess", MTD_boolean)
+ .ifeq(blockBuilder.breakLabel())
+ .invokestatic(CD_MethodHandles, "lookup", MTD_MethodHandles$Lookup)
+ .areturn())
+ .new_(CD_IllegalAccessException)
+ .dup()
+ .aload(cob.parameterSlot(0))
+ .invokevirtual(CD_MethodHandles_Lookup, "toString", MTD_String)
+ .invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String)
+ .athrow()));
}
/**
@@ -699,12 +722,12 @@ private static class ProxyMethod {
private final Class> fromClass;
private final Class>[] parameterTypes;
private final Class> returnType;
- private final String methodFieldName;
+ private final Utf8Entry methodFieldName;
private Class>[] exceptionTypes;
private ProxyMethod(Method method, String sig, Class>[] parameterTypes,
Class> returnType, Class>[] exceptionTypes,
- Class> fromClass, String methodFieldName) {
+ Class> fromClass, Utf8Entry methodFieldName) {
this.method = method;
this.shortSignature = sig;
this.parameterTypes = parameterTypes;
@@ -720,100 +743,70 @@ private ProxyMethod(Method method, String sig, Class>[] parameterTypes,
* @param method The method for which to create a proxy
* @param methodFieldName the fieldName to generate
*/
- private ProxyMethod(Method method, String methodFieldName) {
+ private ProxyMethod(Method method, Utf8Entry methodFieldName) {
this(method, method.toShortSignature(),
- method.getSharedParameterTypes(), method.getReturnType(),
- method.getSharedExceptionTypes(), method.getDeclaringClass(), methodFieldName);
+ method.getSharedParameterTypes(), method.getReturnType(),
+ method.getSharedExceptionTypes(), method.getDeclaringClass(), methodFieldName);
}
/**
* Generate this method, including the code and exception table entry.
*/
- private void generateMethod(ClassWriter cw, String className) {
- MethodType mt = MethodType.methodType(returnType, parameterTypes);
- String desc = mt.toMethodDescriptorString();
- int accessFlags = ACC_PUBLIC | ACC_FINAL;
- if (method.isVarArgs()) accessFlags |= ACC_VARARGS;
-
- MethodVisitor mv = cw.visitMethod(accessFlags,
- method.getName(), desc, null,
- typeNames(Arrays.asList(exceptionTypes)));
-
- int[] parameterSlot = new int[parameterTypes.length];
- int nextSlot = 1;
- for (int i = 0; i < parameterSlot.length; i++) {
- parameterSlot[i] = nextSlot;
- nextSlot += getWordsPerType(parameterTypes[i]);
- }
-
- mv.visitCode();
- Label L_startBlock = new Label();
- Label L_endBlock = new Label();
- Label L_RuntimeHandler = new Label();
- Label L_ThrowableHandler = new Label();
-
- List> catchList = computeUniqueCatchList(exceptionTypes);
- if (catchList.size() > 0) {
- for (Class> ex : catchList) {
- mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_RuntimeHandler,
- dotToSlash(ex.getName()));
- }
-
- mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_ThrowableHandler,
- JL_THROWABLE);
- }
- mv.visitLabel(L_startBlock);
-
- mv.visitVarInsn(ALOAD, 0);
- mv.visitFieldInsn(GETFIELD, JLR_PROXY, handlerFieldName,
- LJLR_INVOCATION_HANDLER);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitFieldInsn(GETSTATIC, dotToSlash(className), methodFieldName,
- LJLR_METHOD);
-
- if (parameterTypes.length > 0) {
- // Create an array and fill with the parameters converting primitives to wrappers
- emitIconstInsn(mv, parameterTypes.length);
- mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_OBJECT);
- for (int i = 0; i < parameterTypes.length; i++) {
- mv.visitInsn(DUP);
- emitIconstInsn(mv, i);
- codeWrapArgument(mv, parameterTypes[i], parameterSlot[i]);
- mv.visitInsn(Opcodes.AASTORE);
- }
- } else {
- mv.visitInsn(Opcodes.ACONST_NULL);
- }
-
- mv.visitMethodInsn(INVOKEINTERFACE, JLR_INVOCATION_HANDLER,
- "invoke",
- "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
- "[Ljava/lang/Object;)Ljava/lang/Object;", true);
+ private void generateMethod(ClassBuilder clb, ClassEntry className) {
+ var cp = clb.constantPool();
+ MethodTypeDesc desc = MethodTypeDesc.of(toClassDesc(returnType),
+ Arrays.stream(parameterTypes).map(ProxyGenerator::toClassDesc).toArray(ClassDesc[]::new));
+ int accessFlags = (method.isVarArgs()) ? ACC_VARARGS | ACC_PUBLIC | ACC_FINAL
+ : ACC_PUBLIC | ACC_FINAL;
+ var catchList = computeUniqueCatchList(exceptionTypes);
+ clb.withMethod(method.getName(), desc, accessFlags, mb ->
+ mb.with(ExceptionsAttribute.of(toClassEntries(cp, List.of(exceptionTypes))))
+ .withCode(cob -> {
+ cob.aload(cob.receiverSlot())
+ .getfield(FRE_Proxy_h)
+ .aload(cob.receiverSlot())
+ .getstatic(cp.fieldRefEntry(className, cp.nameAndTypeEntry(methodFieldName, UE_Method)));
+
+ if (parameterTypes.length > 0) {
+ // Create an array and fill with the parameters converting primitives to wrappers
+ cob.constantInstruction(parameterTypes.length)
+ .anewarray(CE_Object);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ cob.dup()
+ .constantInstruction(i);
+ codeWrapArgument(cob, parameterTypes[i], cob.parameterSlot(i));
+ cob.aastore();
+ }
+ } else {
+ cob.aconst_null();
+ }
- if (returnType == void.class) {
- mv.visitInsn(POP);
- mv.visitInsn(RETURN);
- } else {
- codeUnwrapReturnValue(mv, returnType);
- }
+ cob.invokeinterface(IMRE_InvocationHandler_invoke);
- mv.visitLabel(L_endBlock);
-
- // Generate exception handler
- mv.visitLabel(L_RuntimeHandler);
- mv.visitInsn(ATHROW); // just rethrow the exception
-
- mv.visitLabel(L_ThrowableHandler);
- mv.visitVarInsn(ASTORE, 1);
- mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
- mv.visitInsn(DUP);
- mv.visitVarInsn(ALOAD, 1);
- mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
- "", "(Ljava/lang/Throwable;)V", false);
- mv.visitInsn(ATHROW);
- // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
- mv.visitMaxs(-1, -1);
- mv.visitEnd();
+ if (returnType == void.class) {
+ cob.pop()
+ .return_();
+ } else {
+ codeUnwrapReturnValue(cob, returnType);
+ }
+ if (!catchList.isEmpty()) {
+ var c1 = cob.newBoundLabel();
+ for (var exc : catchList) {
+ cob.exceptionCatch(cob.startLabel(), c1, c1, toClassDesc(exc));
+ }
+ cob.athrow(); // just rethrow the exception
+ var c2 = cob.newBoundLabel();
+ cob.exceptionCatchAll(cob.startLabel(), c1, c2)
+ .new_(CE_UndeclaredThrowableException)
+ .dup_x1()
+ .swap()
+ .invokespecial(MRE_UndeclaredThrowableException_init)
+ .athrow()
+ .with(StackMapTableAttribute.of(List.of(
+ StackMapFrameInfo.of(c1, List.of(), THROWABLE_STACK),
+ StackMapFrameInfo.of(c2, List.of(), THROWABLE_STACK))));
+ }
+ }));
}
/**
@@ -822,15 +815,13 @@ private void generateMethod(ClassWriter cw, String className) {
* index, in order for it to be passed (as an Object) to the
* invocation handler's "invoke" method.
*/
- private void codeWrapArgument(MethodVisitor mv, Class> type, int slot) {
+ private void codeWrapArgument(CodeBuilder cob, Class> type, int slot) {
if (type.isPrimitive()) {
+ cob.loadInstruction(TypeKind.from(type).asLoadable(), slot);
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
-
- mv.visitVarInsn(prim.loadOpcode, slot);
- mv.visitMethodInsn(INVOKESTATIC, prim.wrapperClassName, "valueOf",
- prim.wrapperValueOfDesc, false);
+ cob.invokestatic(prim.wrapperMethodRef);
} else {
- mv.visitVarInsn(ALOAD, slot);
+ cob.aload(slot);
}
}
@@ -839,19 +830,16 @@ private void codeWrapArgument(MethodVisitor mv, Class> type, int slot) {
* type from the invocation handler's "invoke" method (as type
* Object) to its correct type.
*/
- private void codeUnwrapReturnValue(MethodVisitor mv, Class> type) {
+ private void codeUnwrapReturnValue(CodeBuilder cob, Class> type) {
if (type.isPrimitive()) {
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
- mv.visitTypeInsn(CHECKCAST, prim.wrapperClassName);
- mv.visitMethodInsn(INVOKEVIRTUAL,
- prim.wrapperClassName,
- prim.unwrapMethodName, prim.unwrapMethodDesc, false);
-
- mv.visitInsn(prim.returnOpcode);
+ cob.checkcast(prim.wrapperClass)
+ .invokevirtual(prim.unwrapMethodRef)
+ .returnInstruction(TypeKind.from(type).asLoadable());
} else {
- mv.visitTypeInsn(CHECKCAST, dotToSlash(type.getName()));
- mv.visitInsn(ARETURN);
+ cob.checkcast(toClassDesc(type))
+ .areturn();
}
}
@@ -860,40 +848,29 @@ private void codeUnwrapReturnValue(MethodVisitor mv, Class> type) {
* the Method object for this proxy method. A class loader is
* anticipated at local variable index 0.
*/
- private void codeFieldInitialization(MethodVisitor mv, String className) {
- codeClassForName(mv, fromClass);
-
- mv.visitLdcInsn(method.getName());
+ private void codeFieldInitialization(CodeBuilder cob, ClassEntry className) {
+ var cp = cob.constantPool();
+ codeClassForName(cob, fromClass);
- emitIconstInsn(mv, parameterTypes.length);
-
- mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_CLASS);
+ cob.ldc(method.getName())
+ .constantInstruction(parameterTypes.length)
+ .anewarray(CE_Class);
// Construct an array with the parameter types mapping primitives to Wrapper types
for (int i = 0; i < parameterTypes.length; i++) {
- mv.visitInsn(DUP);
- emitIconstInsn(mv, i);
-
+ cob.dup()
+ .constantInstruction(i);
if (parameterTypes[i].isPrimitive()) {
- PrimitiveTypeInfo prim =
- PrimitiveTypeInfo.get(parameterTypes[i]);
- mv.visitFieldInsn(GETSTATIC,
- prim.wrapperClassName, "TYPE", LJL_CLASS);
+ PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(parameterTypes[i]);
+ cob.getstatic(prim.typeFieldRef);
} else {
- codeClassForName(mv, parameterTypes[i]);
+ codeClassForName(cob, parameterTypes[i]);
}
- mv.visitInsn(Opcodes.AASTORE);
+ cob.aastore();
}
// lookup the method
- mv.visitMethodInsn(INVOKEVIRTUAL,
- JL_CLASS,
- "getMethod",
- "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
- false);
-
- mv.visitFieldInsn(PUTSTATIC,
- dotToSlash(className),
- methodFieldName, LJLR_METHOD);
+ cob.invokevirtual(MRE_Class_getMethod)
+ .putstatic(cp.fieldRefEntry(className, cp.nameAndTypeEntry(methodFieldName, UE_Method)));
}
/*
@@ -907,33 +884,11 @@ private void codeFieldInitialization(MethodVisitor mv, String className) {
* may cause the checked ClassNotFoundException to be thrown. A class
* loader is anticipated at local variable index 0.
*/
- private void codeClassForName(MethodVisitor mv, Class> cl) {
- mv.visitLdcInsn(cl.getName());
- mv.visitInsn(ICONST_0); // false
- mv.visitVarInsn(ALOAD, 0); // classLoader
- mv.visitMethodInsn(INVOKESTATIC,
- JL_CLASS,
- "forName",
- "(Ljava/lang/String;Z" + LJL_CLASSLOADER + ")Ljava/lang/Class;",
- false);
- }
-
- /**
- * Visit a bytecode for a constant.
- *
- * @param mv The MethodVisitor
- * @param cst The constant value
- */
- private void emitIconstInsn(MethodVisitor mv, final int cst) {
- if (cst >= -1 && cst <= 5) {
- mv.visitInsn(Opcodes.ICONST_0 + cst);
- } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
- mv.visitIntInsn(Opcodes.BIPUSH, cst);
- } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
- mv.visitIntInsn(Opcodes.SIPUSH, cst);
- } else {
- mv.visitLdcInsn(cst);
- }
+ private void codeClassForName(CodeBuilder cob, Class> cl) {
+ cob.ldc(cl.getName())
+ .iconst_0() // false
+ .aload(0)// classLoader
+ .invokestatic(MRE_Class_forName);
}
@Override
@@ -942,61 +897,45 @@ public String toString() {
}
}
+ private static final ConstantPoolBuilder CP = ConstantPoolBuilder.of();
/**
* A PrimitiveTypeInfo object contains bytecode-related information about
* a primitive type in its instance fields. The struct for a particular
* primitive type can be obtained using the static "get" method.
*/
private enum PrimitiveTypeInfo {
- BYTE(byte.class, ILOAD, IRETURN),
- CHAR(char.class, ILOAD, IRETURN),
- DOUBLE(double.class, DLOAD, DRETURN),
- FLOAT(float.class, FLOAD, FRETURN),
- INT(int.class, ILOAD, IRETURN),
- LONG(long.class, LLOAD, LRETURN),
- SHORT(short.class, ILOAD, IRETURN),
- BOOLEAN(boolean.class, ILOAD, IRETURN);
+ BYTE(byte.class, CD_byte, CD_Byte),
+ CHAR(char.class, CD_char, CD_Character),
+ DOUBLE(double.class, CD_double, CD_Double),
+ FLOAT(float.class, CD_float, CD_Float),
+ INT(int.class, CD_int, CD_Integer),
+ LONG(long.class, CD_long, CD_Long),
+ SHORT(short.class, CD_short, CD_Short),
+ BOOLEAN(boolean.class, CD_boolean, CD_Boolean);
/**
- * internal name of corresponding wrapper class
- */
- private final String wrapperClassName;
- /**
- * method descriptor for wrapper class "valueOf" factory method
- */
- private final String wrapperValueOfDesc;
- /**
- * name of wrapper class method for retrieving primitive value
+ * CP entry of corresponding wrapper class
*/
- private final String unwrapMethodName;
+ private final ClassEntry wrapperClass;
/**
- * descriptor of same method
+ * CP entry for wrapper class "valueOf" factory method
*/
- private final String unwrapMethodDesc;
+ private final MethodRefEntry wrapperMethodRef;
/**
- * Load opcode used by this primitive
+ * CP entry of wrapper class method for retrieving primitive value
*/
- private final int loadOpcode;
+ private final MethodRefEntry unwrapMethodRef;
/**
- * Return opcode used by this primitive
+ * CP entry of wrapper class TYPE field
*/
- private final int returnOpcode;
-
- PrimitiveTypeInfo(Class> primitiveClass, int loadOpcode, int returnOpcode) {
- assert primitiveClass.isPrimitive();
- assert returnOpcode - IRETURN == loadOpcode - ILOAD;
-
- Wrapper wrapper = Wrapper.forPrimitiveType(primitiveClass);
- // single-char BaseType descriptor (see JVMS section 4.3.2)
- String baseTypeString = wrapper.basicTypeString();
- var wrapperType = wrapper.wrapperType();
- wrapperClassName = dotToSlash(wrapperType.getName());
- wrapperValueOfDesc =
- "(" + baseTypeString + ")" + wrapperType.descriptorString();
- unwrapMethodName = primitiveClass.getName() + "Value";
- unwrapMethodDesc = "()" + baseTypeString;
- this.loadOpcode = loadOpcode;
- this.returnOpcode = returnOpcode;
+ private final FieldRefEntry typeFieldRef;
+
+ PrimitiveTypeInfo(Class> primitiveClass, ClassDesc baseType, ClassDesc wrapperClass) {
+ assert baseType.isPrimitive();
+ this.wrapperClass = CP.classEntry(wrapperClass);
+ this.wrapperMethodRef = CP.methodRefEntry(wrapperClass, "valueOf", MethodTypeDesc.of(wrapperClass, baseType));
+ this.unwrapMethodRef = CP.methodRefEntry(wrapperClass, primitiveClass.getName() + "Value", MethodTypeDesc.of(baseType));
+ this.typeFieldRef = CP.fieldRefEntry(wrapperClass, "TYPE", CD_Class);
}
public static PrimitiveTypeInfo get(Class> cl) {
diff --git a/src/java.base/share/classes/java/nio/channels/ScatteringByteChannel.java b/src/java.base/share/classes/java/nio/channels/ScatteringByteChannel.java
index fd48d4baa6e..27fce3c1e09 100644
--- a/src/java.base/share/classes/java/nio/channels/ScatteringByteChannel.java
+++ b/src/java.base/share/classes/java/nio/channels/ScatteringByteChannel.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,7 @@ public interface ScatteringByteChannel
*
* An invocation of this method attempts to read up to r bytes
* from this channel, where r is the total number of bytes remaining
- * the specified subsequence of the given buffer array, that is,
+ * in the specified subsequence of the given buffer array, that is,
*
* {@snippet lang=java :
* dsts[offset].remaining()
diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java
index cc35012fa0a..c1eba232359 100644
--- a/src/java.base/share/classes/java/nio/file/Files.java
+++ b/src/java.base/share/classes/java/nio/file/Files.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -3743,7 +3743,7 @@ public static Path writeString(Path path, CharSequence csq, Charset cs, OpenOpti
// -- Stream APIs --
/**
- * Return a lazily populated {@code Stream}, the elements of
+ * Returns a lazily populated {@code Stream}, the elements of
* which are the entries in the directory. The listing is not recursive.
*
*
The elements of the stream are {@link Path} objects that are
@@ -3834,11 +3834,12 @@ public Path next() {
}
/**
- * Return a {@code Stream} that is lazily populated with {@code
+ * Returns a {@code Stream} that is lazily populated with {@code
* Path} by walking the file tree rooted at a given starting file. The
- * file tree is traversed depth-first , the elements in the stream
- * are {@link Path} objects that are obtained as if by {@link
- * Path#resolve(Path) resolving} the relative path against {@code start}.
+ * file tree is traversed depth-first with a directory visited
+ * before the entries in that directory. The elements in the stream are
+ * {@link Path} objects that are obtained as if by {@link Path#resolve(Path)
+ * resolving} the relative path against {@code start}.
*
*
The {@code stream} walks the file tree as elements are consumed.
* The {@code Stream} returned is guaranteed to have at least one
@@ -3933,11 +3934,12 @@ public static Stream walk(Path start,
}
/**
- * Return a {@code Stream} that is lazily populated with {@code
+ * Returns a {@code Stream} that is lazily populated with {@code
* Path} by walking the file tree rooted at a given starting file. The
- * file tree is traversed depth-first , the elements in the stream
- * are {@link Path} objects that are obtained as if by {@link
- * Path#resolve(Path) resolving} the relative path against {@code start}.
+ * file tree is traversed depth-first with a directory visited
+ * before the entries in that directory. The elements in the stream are
+ * {@link Path} objects that are obtained as if by {@link Path#resolve(Path)
+ * resolving} the relative path against {@code start}.
*
* This method works as if invoking it were equivalent to evaluating the
* expression:
@@ -3978,7 +3980,7 @@ public static Stream walk(Path start, FileVisitOption... options) throws I
}
/**
- * Return a {@code Stream} that is lazily populated with {@code
+ * Returns a {@code Stream} that is lazily populated with {@code
* Path} by searching for files in a file tree rooted at a given starting
* file.
*
diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java
index b9aad971aa5..94b8c188c93 100644
--- a/src/java.base/share/classes/java/text/ChoiceFormat.java
+++ b/src/java.base/share/classes/java/text/ChoiceFormat.java
@@ -134,6 +134,16 @@
* Use two single quotes in a row to produce a literal single quote. For example,
* {@code new ChoiceFormat("1# ''one'' ").format(1)} returns {@code " 'one' "}.
*
+ * @apiNote A subclass could perform more consistent pattern validation by
+ * throwing an {@code IllegalArgumentException} for all incorrect cases.
+ * @implNote Given an incorrect pattern, this implementation may either
+ * throw an exception or succeed and discard the incorrect portion. A {@code
+ * NumberFormatException} is thrown if a {@code limit} can not be
+ * parsed as a numeric value and an {@code IllegalArgumentException} is thrown
+ * if a {@code SubPattern} is missing, or the intervals are not ascending.
+ * Discarding the incorrect portion may result in a ChoiceFormat with
+ * empty {@code limits} and {@code formats}.
+ *
* Usage Information
*
*
@@ -227,11 +237,12 @@ public class ChoiceFormat extends NumberFormat {
private static final long serialVersionUID = 1795184449645032964L;
/**
- * Apply the given pattern to this ChoiceFormat object. The syntax
- * for the ChoiceFormat pattern can be seen in the {@linkplain ##patterns
- * Patterns} section. Unlike {@link #setChoices(double[], String[])} this
- * method will throw an {@code IllegalArgumentException} if the {@code
- * limits} are not in ascending order.
+ * Apply the given pattern to this ChoiceFormat object. The syntax and error
+ * related caveats for the ChoiceFormat pattern can be found in the
+ * {@linkplain ##patterns Patterns} section. Unlike {@link #setChoices(double[],
+ * String[])}, this method will throw an {@code IllegalArgumentException} if
+ * the {@code limits} are not in ascending order.
+ *
* @param newPattern a pattern string
* @throws NullPointerException if {@code newPattern}
* is {@code null}
@@ -399,9 +410,11 @@ public String toPattern() {
/**
* Constructs a ChoiceFormat with limits and corresponding formats
- * based on the pattern.
- * The syntax for the ChoiceFormat pattern can be seen in the {@linkplain
- * ##patterns Patterns} section.
+ * based on the pattern. The syntax and error related caveats for the
+ * ChoiceFormat pattern can be found in the {@linkplain ##patterns Patterns}
+ * section. Unlike {@link #ChoiceFormat(double[], String[])}, this constructor will
+ * throw an {@code IllegalArgumentException} if the {@code limits} are not
+ * in ascending order.
*
* @param newPattern the new pattern string
* @throws NullPointerException if {@code newPattern} is
diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
index 0385c4a1674..ed380841faa 100644
--- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
+++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
@@ -4694,10 +4694,14 @@ public int parse(DateTimeParseContext context, CharSequence text, int position)
if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) {
// There are localized zone texts that start with "UTC", e.g.
// "UTC\u221210:00" (MINUS SIGN instead of HYPHEN-MINUS) in French.
- // Exclude those cases.
- if (length == position + 3 ||
- context.charEquals(text.charAt(position + 3), '+') ||
- context.charEquals(text.charAt(position + 3), '-')) {
+ // Treat them as normal '-' with the offset parser (using text parser would
+ // be problematic due to std/dst distinction)
+ if (length > position + 3 && context.charEquals(text.charAt(position + 3), '\u2212')) {
+ var tmpText = "%s-%s".formatted(
+ text.subSequence(0, position + 3),
+ text.subSequence(position + 4, text.length()));
+ return parseOffsetBased(context, tmpText, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
+ } else {
return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
}
} else {
diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java
index 88a49a94f9b..bcdf32d6f8b 100644
--- a/src/java.base/share/classes/java/util/Locale.java
+++ b/src/java.base/share/classes/java/util/Locale.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -51,16 +51,15 @@
import java.util.spi.LocaleNameProvider;
import java.util.stream.Stream;
+import jdk.internal.util.ReferencedKeyMap;
import jdk.internal.util.StaticProperty;
import jdk.internal.vm.annotation.Stable;
-import sun.security.action.GetPropertyAction;
import sun.util.locale.BaseLocale;
import sun.util.locale.InternalLocaleBuilder;
import sun.util.locale.LanguageTag;
import sun.util.locale.LocaleExtensions;
import sun.util.locale.LocaleMatcher;
-import sun.util.locale.LocaleObjectCache;
import sun.util.locale.LocaleSyntaxException;
import sun.util.locale.LocaleUtils;
import sun.util.locale.ParseStatus;
@@ -987,29 +986,20 @@ static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
if (locale != null) {
return locale;
}
- return Cache.LOCALECACHE.get(baseloc);
+ return LOCALE_CACHE.computeIfAbsent(baseloc, Locale::createLocale);
} else {
LocaleKey key = new LocaleKey(baseloc, extensions);
- return Cache.LOCALECACHE.get(key);
+ return LOCALE_CACHE.computeIfAbsent(key, Locale::createLocale);
}
}
- private static class Cache extends LocaleObjectCache {
-
- private static final Cache LOCALECACHE = new Cache();
-
- private Cache() {
- }
-
- @Override
- protected Locale createObject(Object key) {
- if (key instanceof BaseLocale) {
- return new Locale((BaseLocale)key, null);
- } else {
- LocaleKey lk = (LocaleKey)key;
- return new Locale(lk.base, lk.exts);
- }
- }
+ private static final ReferencedKeyMap LOCALE_CACHE = ReferencedKeyMap.create(true, ConcurrentHashMap::new);
+ private static Locale createLocale(Object key) {
+ return switch (key) {
+ case BaseLocale base -> new Locale(base, null);
+ case LocaleKey lk -> new Locale(lk.base, lk.exts);
+ default -> throw new InternalError("should not happen");
+ };
}
private static final class LocaleKey {
diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java
index 81ff9e7b534..d2407c403ae 100644
--- a/src/java.base/share/classes/java/util/ResourceBundle.java
+++ b/src/java.base/share/classes/java/util/ResourceBundle.java
@@ -69,9 +69,9 @@
import jdk.internal.access.SharedSecrets;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
+import jdk.internal.util.ReferencedKeyMap;
import sun.security.action.GetPropertyAction;
import sun.util.locale.BaseLocale;
-import sun.util.locale.LocaleObjectCache;
import sun.util.resources.Bundles;
import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
@@ -2867,123 +2867,122 @@ public List getCandidateLocales(String baseName, Locale locale) {
if (baseName == null) {
throw new NullPointerException();
}
- return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
+ return new ArrayList<>(CANDIDATES_CACHE.computeIfAbsent(locale.getBaseLocale(),
+ Control::createCandidateList));
}
- private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
+ private static final ReferencedKeyMap> CANDIDATES_CACHE = ReferencedKeyMap.create(true, ConcurrentHashMap::new);
- private static class CandidateListCache extends LocaleObjectCache> {
- protected List createObject(BaseLocale base) {
- String language = base.getLanguage();
- String script = base.getScript();
- String region = base.getRegion();
- String variant = base.getVariant();
+ private static List createCandidateList(BaseLocale base) {
+ String language = base.getLanguage();
+ String script = base.getScript();
+ String region = base.getRegion();
+ String variant = base.getVariant();
- // Special handling for Norwegian
- boolean isNorwegianBokmal = false;
- boolean isNorwegianNynorsk = false;
- if (language.equals("no")) {
- if (region.equals("NO") && variant.equals("NY")) {
- variant = "";
- isNorwegianNynorsk = true;
- } else {
- isNorwegianBokmal = true;
- }
+ // Special handling for Norwegian
+ boolean isNorwegianBokmal = false;
+ boolean isNorwegianNynorsk = false;
+ if (language.equals("no")) {
+ if (region.equals("NO") && variant.equals("NY")) {
+ variant = "";
+ isNorwegianNynorsk = true;
+ } else {
+ isNorwegianBokmal = true;
}
- if (language.equals("nb") || isNorwegianBokmal) {
- List tmpList = getDefaultList("nb", script, region, variant);
- // Insert a locale replacing "nb" with "no" for every list entry with precedence
- List bokmalList = new ArrayList<>();
- for (Locale l_nb : tmpList) {
- var isRoot = l_nb.getLanguage().isEmpty();
- var l_no = Locale.getInstance(isRoot ? "" : "no",
- l_nb.getScript(), l_nb.getCountry(), l_nb.getVariant(), null);
- bokmalList.add(isNorwegianBokmal ? l_no : l_nb);
- if (isRoot) {
- break;
- }
- bokmalList.add(isNorwegianBokmal ? l_nb : l_no);
+ }
+ if (language.equals("nb") || isNorwegianBokmal) {
+ List tmpList = getDefaultList("nb", script, region, variant);
+ // Insert a locale replacing "nb" with "no" for every list entry with precedence
+ List bokmalList = new ArrayList<>();
+ for (Locale l_nb : tmpList) {
+ var isRoot = l_nb.getLanguage().isEmpty();
+ var l_no = Locale.getInstance(isRoot ? "" : "no",
+ l_nb.getScript(), l_nb.getCountry(), l_nb.getVariant(), null);
+ bokmalList.add(isNorwegianBokmal ? l_no : l_nb);
+ if (isRoot) {
+ break;
}
- return bokmalList;
- } else if (language.equals("nn") || isNorwegianNynorsk) {
- // Insert no_NO_NY, no_NO, no after nn
- List nynorskList = getDefaultList("nn", script, region, variant);
- int idx = nynorskList.size() - 1;
- nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
- nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
- nynorskList.add(idx++, Locale.getInstance("no", "", ""));
- return nynorskList;
+ bokmalList.add(isNorwegianBokmal ? l_nb : l_no);
}
- // Special handling for Chinese
- else if (language.equals("zh")) {
- if (script.isEmpty() && !region.isEmpty()) {
- // Supply script for users who want to use zh_Hans/zh_Hant
- // as bundle names (recommended for Java7+)
- switch (region) {
- case "TW", "HK", "MO" -> script = "Hant";
- case "CN", "SG" -> script = "Hans";
- }
+ return bokmalList;
+ } else if (language.equals("nn") || isNorwegianNynorsk) {
+ // Insert no_NO_NY, no_NO, no after nn
+ List nynorskList = getDefaultList("nn", script, region, variant);
+ int idx = nynorskList.size() - 1;
+ nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
+ nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
+ nynorskList.add(idx++, Locale.getInstance("no", "", ""));
+ return nynorskList;
+ }
+ // Special handling for Chinese
+ else if (language.equals("zh")) {
+ if (script.isEmpty() && !region.isEmpty()) {
+ // Supply script for users who want to use zh_Hans/zh_Hant
+ // as bundle names (recommended for Java7+)
+ switch (region) {
+ case "TW", "HK", "MO" -> script = "Hant";
+ case "CN", "SG" -> script = "Hans";
}
}
-
- return getDefaultList(language, script, region, variant);
}
- private static List getDefaultList(String language, String script, String region, String variant) {
- List variants = null;
+ return getDefaultList(language, script, region, variant);
+ }
- if (!variant.isEmpty()) {
- variants = new ArrayList<>();
- int idx = variant.length();
- while (idx != -1) {
- variants.add(variant.substring(0, idx));
- idx = variant.lastIndexOf('_', --idx);
- }
+ private static List getDefaultList(String language, String script, String region, String variant) {
+ List variants = null;
+
+ if (!variant.isEmpty()) {
+ variants = new ArrayList<>();
+ int idx = variant.length();
+ while (idx != -1) {
+ variants.add(variant.substring(0, idx));
+ idx = variant.lastIndexOf('_', --idx);
}
+ }
- List list = new ArrayList<>();
+ List list = new ArrayList<>();
- if (variants != null) {
- for (String v : variants) {
- list.add(Locale.getInstance(language, script, region, v, null));
- }
- }
- if (!region.isEmpty()) {
- list.add(Locale.getInstance(language, script, region, "", null));
+ if (variants != null) {
+ for (String v : variants) {
+ list.add(Locale.getInstance(language, script, region, v, null));
}
- if (!script.isEmpty()) {
- list.add(Locale.getInstance(language, script, "", "", null));
- // Special handling for Chinese
- if (language.equals("zh")) {
- if (region.isEmpty()) {
- // Supply region(country) for users who still package Chinese
- // bundles using old convention.
- switch (script) {
- case "Hans" -> region = "CN";
- case "Hant" -> region = "TW";
- }
+ }
+ if (!region.isEmpty()) {
+ list.add(Locale.getInstance(language, script, region, "", null));
+ }
+ if (!script.isEmpty()) {
+ list.add(Locale.getInstance(language, script, "", "", null));
+ // Special handling for Chinese
+ if (language.equals("zh")) {
+ if (region.isEmpty()) {
+ // Supply region(country) for users who still package Chinese
+ // bundles using old convention.
+ switch (script) {
+ case "Hans" -> region = "CN";
+ case "Hant" -> region = "TW";
}
}
+ }
- // With script, after truncating variant, region and script,
- // start over without script.
- if (variants != null) {
- for (String v : variants) {
- list.add(Locale.getInstance(language, "", region, v, null));
- }
- }
- if (!region.isEmpty()) {
- list.add(Locale.getInstance(language, "", region, "", null));
+ // With script, after truncating variant, region and script,
+ // start over without script.
+ if (variants != null) {
+ for (String v : variants) {
+ list.add(Locale.getInstance(language, "", region, v, null));
}
}
- if (!language.isEmpty()) {
- list.add(Locale.getInstance(language, "", "", "", null));
+ if (!region.isEmpty()) {
+ list.add(Locale.getInstance(language, "", region, "", null));
}
- // Add root locale at the end
- list.add(Locale.ROOT);
-
- return list;
}
+ if (!language.isEmpty()) {
+ list.add(Locale.getInstance(language, "", "", "", null));
+ }
+ // Add root locale at the end
+ list.add(Locale.ROOT);
+
+ return list;
}
/**
diff --git a/src/java.base/share/classes/java/util/jar/Manifest.java b/src/java.base/share/classes/java/util/jar/Manifest.java
index b3b9baa38cc..c0e30707a35 100644
--- a/src/java.base/share/classes/java/util/jar/Manifest.java
+++ b/src/java.base/share/classes/java/util/jar/Manifest.java
@@ -219,22 +219,6 @@ public void write(OutputStream out) throws IOException {
dos.flush();
}
- /**
- * Adds line breaks to enforce a maximum of 72 bytes per line.
- *
- * @deprecation Replaced with {@link #println72}.
- */
- @Deprecated(since = "13")
- static void make72Safe(StringBuffer line) {
- int length = line.length();
- int index = 72;
- while (index < length) {
- line.insert(index, "\r\n ");
- index += 74; // + line width + line break ("\r\n")
- length += 3; // + line break ("\r\n") and space
- }
- }
-
/**
* Writes {@code line} to {@code out} with line breaks and continuation
* spaces within the limits of 72 bytes of contents per line followed
diff --git a/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java b/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java
index 5d443963bef..996ef705269 100644
--- a/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java
+++ b/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -75,7 +75,7 @@
*
* which is the fully qualified class name of the class implementing
* {@code DateFormatProvider}.
- * Invocation of Locale Sensitive Services
+ * Invocation of Locale Sensitive Services
*
* Locale sensitive factory methods and methods for name retrieval in the
* {@code java.text} and {@code java.util} packages invoke
@@ -120,33 +120,27 @@
* property on the java launcher command line. Setting it at runtime with
* {@link System#setProperty(String, String)} is discouraged and it may not affect
* the order.
- * JDK Reference Implementation provides the following four
+ * JDK Reference Implementation provides the following three
* locale providers:
*
* "CLDR": A provider based on Unicode Consortium's
* CLDR Project .
- * "COMPAT": represents the locale sensitive services that is compatible
- * with the prior JDK releases up to JDK 8 (same as JDK 8's "JRE"). This
- * provider is deprecated and will be removed in the future release of JDK.
* "SPI": represents the locale sensitive services implementing the subclasses of
* this {@code LocaleServiceProvider} class.
* "HOST": A provider that reflects the user's custom settings in the
* underlying operating system. This provider may not be available, depending
* on the JDK Reference Implementation.
- * "JRE": represents a synonym to "COMPAT". This name
- * is deprecated and will be removed in the future release of JDK.
*
*
* For example, if the following is specified in the property:
*
- * java.locale.providers=SPI,CLDR,COMPAT
+ * java.locale.providers=SPI,CLDR
*
* the locale sensitive services in the SPI providers are looked up first. If the
- * desired locale sensitive service is not available, then the runtime looks for CLDR,
- * COMPAT in that order.
+ * desired locale sensitive service is not available, then the runtime looks for CLDR.
*
- * The default order for looking up the preferred locale providers is "CLDR,COMPAT",
- * so specifying "CLDR,COMPAT" is identical to the default behavior. Applications which
+ * The default value for looking up the preferred locale providers is "CLDR",
+ * so specifying "CLDR" is identical to the default behavior. Applications which
* require implementations of the locale sensitive services must explicitly specify
* "SPI" in order for the Java runtime to load them from the classpath.
*
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
index eb5aab90bb0..db2b4f030a3 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
@@ -87,6 +87,7 @@ public SplitConstantPool(ClassReader parent) {
this.bsmSize = parentBsmSize;
this.myEntries = new PoolEntry[8];
this.myBsmEntries = new BootstrapMethodEntryImpl[8];
+ this.doneFullScan = true;
}
@Override
@@ -189,10 +190,15 @@ protected PoolEntry fetchElement(int index) {
// So we inflate the map with whatever we've got from the parent, and
// later, if we miss, we do a one-time full inflation before creating
// a new entry.
- for (int i=1; i map;
+ private final Queue targets;
private final BitSet visited;
private void jump(int targetBci) {
if (!visited.get(targetBci)) {
- map.put(targetBci, stack);
+ targets.add(new Target(targetBci, stack));
}
}
@@ -78,13 +78,11 @@ private void ensureLocalSlot(int index) {
}
private boolean next() {
- var it = map.entrySet().iterator();
- while (it.hasNext()) {
- var en = it.next();
- it.remove();
- if (!visited.get(en.getKey())) {
- bcs.nextBci = en.getKey();
- stack = en.getValue();
+ Target en;
+ while ((en = targets.poll()) != null) {
+ if (!visited.get(en.bci)) {
+ bcs.nextBci = en.bci;
+ stack = en.stack;
return true;
}
}
@@ -93,7 +91,6 @@ private boolean next() {
}
public StackCounter(LabelContext labelContext,
- ClassDesc thisClass,
String methodName,
MethodTypeDesc methodDesc,
boolean isStatic,
@@ -103,16 +100,14 @@ public StackCounter(LabelContext labelContext,
this.methodName = methodName;
this.methodDesc = methodDesc;
this.cp = cp;
- map = new LinkedHashMap<>();
+ targets = new ArrayDeque<>();
maxStack = stack = rets = 0;
- for (var h : handlers) map.put(labelContext.labelToBci(h.handler), 1);
+ for (var h : handlers) targets.add(new Target(labelContext.labelToBci(h.handler), 1));
maxLocals = isStatic ? 0 : 1;
- for (var cd : methodDesc.parameterList()) {
- maxLocals += Util.slotSize(cd);
- }
+ maxLocals += Util.parameterSlots(methodDesc);
bcs = new RawBytecodeHelper(bytecode);
visited = new BitSet(bcs.endBci);
- map.put(0, 0);
+ targets.add(new Target(0, 0));
while (next()) {
while (!bcs.isLastBytecode()) {
bcs.rawNext();
@@ -307,14 +302,11 @@ public StackCounter(LabelContext labelContext,
case INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC -> {
var cpe = cp.entryByIndex(bcs.getIndexU2());
var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType();
- var mDesc = MethodTypeDesc.ofDescriptor(nameAndType.type().stringValue());
- for (var arg : mDesc.parameterList()) {
- addStackSlot(-TypeKind.from(arg).slotSize());
- }
+ var mtd = Util.methodTypeSymbol(nameAndType);
+ addStackSlot(Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd));
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
addStackSlot(-1);
}
- addStackSlot(TypeKind.from(mDesc.returnType()).slotSize());
}
case MULTIANEWARRAY ->
addStackSlot (1 - bcs.getU1(bcs.bci + 3));
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
index 0fdb3622d6b..75e9f7d817b 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
@@ -80,7 +80,8 @@ public static List initFrameLocals(ClassEntry thisClass, S
} else {
vtis = new VerificationTypeInfo[methodType.parameterCount()];
}
- for(var arg : methodType.parameterList()) {
+ for (int pi = 0; pi < methodType.parameterCount(); pi++) {
+ var arg = methodType.parameterType(pi);
vtis[i++] = switch (arg.descriptorString().charAt(0)) {
case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.ITEM_INTEGER;
case 'J' -> SimpleVerificationTypeInfo.ITEM_LONG;
diff --git a/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java
index e1ea65ff308..0b95c43b440 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java
@@ -49,9 +49,6 @@
abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
// Constants defining the maximum alignment supported by various kinds of heap arrays.
- // While for most arrays, the maximum alignment is constant (the size, in bytes, of the array elements),
- // note that the alignment of a long[]/double[] depends on the platform: it's 4-byte on x86, but 8 bytes on x64
- // (as specified by the JAVA_LONG layout constant).
private static final long MAX_ALIGN_BYTE_ARRAY = ValueLayout.JAVA_BYTE.byteAlignment();
private static final long MAX_ALIGN_SHORT_ARRAY = ValueLayout.JAVA_SHORT.byteAlignment();
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java
index 77c81c6dd58..d617e535dd6 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java
@@ -307,8 +307,8 @@ class Holder {
Map.entry("bool", JAVA_BOOLEAN),
Map.entry("char", JAVA_BYTE),
Map.entry("float", JAVA_FLOAT),
- Map.entry("long long", JAVA_LONG),
- Map.entry("double", JAVA_DOUBLE),
+ Map.entry("long long", JAVA_LONG.withByteAlignment(LibFallback.longLongAlign())),
+ Map.entry("double", JAVA_DOUBLE.withByteAlignment(LibFallback.doubleAlign())),
Map.entry("void*", ADDRESS),
// platform-dependent sizes
Map.entry("size_t", FFIType.SIZE_T),
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java
index b0b6bac3d64..58d6baf8525 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java
@@ -73,6 +73,8 @@ public Boolean run() {
static int intSize() { return NativeConstants.SIZEOF_INT; }
static int longSize() {return NativeConstants.SIZEOF_LONG; }
static int wcharSize() {return NativeConstants.SIZEOF_WCHAR; }
+ static int longLongAlign() { return NativeConstants.ALIGNOF_LONG_LONG; }
+ static int doubleAlign() { return NativeConstants.ALIGNOF_DOUBLE; }
static short structTag() { return NativeConstants.STRUCT_TAG; }
@@ -242,6 +244,9 @@ private static native void doDowncall(long cif, long fn, long rvalue, long avalu
private static native int ffi_sizeof_long();
private static native int ffi_sizeof_wchar();
+ private static native int alignof_long_long();
+ private static native int alignof_double();
+
// put these in a separate class to avoid an UnsatisfiedLinkError
// when LibFallback is initialized but the library is not present
private static final class NativeConstants {
@@ -263,6 +268,8 @@ private NativeConstants() {}
static final int SIZEOF_LONG = ffi_sizeof_long();
static final int SIZEOF_WCHAR = ffi_sizeof_wchar();
+ static final int ALIGNOF_LONG_LONG = alignof_long_long();
+ static final int ALIGNOF_DOUBLE = alignof_double();
static final MemorySegment VOID_TYPE = MemorySegment.ofAddress(ffi_type_void());
static final short STRUCT_TAG = ffi_type_struct();
diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java
index cc61ed41a98..4b41c80f2eb 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java
@@ -278,7 +278,7 @@ OfLongImpl dup(ByteOrder order, long byteAlignment, Optional name) {
}
public static OfLong of(ByteOrder order) {
- return new OfLongImpl(order, ADDRESS_SIZE_BYTES, Optional.empty());
+ return new OfLongImpl(order, Long.BYTES, Optional.empty());
}
}
@@ -294,7 +294,7 @@ OfDoubleImpl dup(ByteOrder order, long byteAlignment, Optional name) {
}
public static OfDouble of(ByteOrder order) {
- return new OfDoubleImpl(order, ADDRESS_SIZE_BYTES, Optional.empty());
+ return new OfDoubleImpl(order, Double.BYTES, Optional.empty());
}
}
diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java
index 0d48a3a530c..6b98ca5e183 100644
--- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java
+++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java
@@ -440,4 +440,30 @@ private static T internKey(ReferencedKeyMap> setMap, T ke
return interned;
}
+
+ /**
+ * Attempt to add key to map if absent.
+ *
+ * @param setMap {@link ReferencedKeyMap} where interning takes place
+ * @param key key to add
+ *
+ * @param type of key
+ *
+ * @return true if the key was added
+ */
+ static boolean internAddKey(ReferencedKeyMap> setMap, T key) {
+ ReferenceKey entryKey = setMap.entryKey(key);
+ setMap.removeStaleReferences();
+ ReferenceKey existing = setMap.map.putIfAbsent(entryKey, entryKey);
+ if (existing == null) {
+ return true;
+ } else {
+ // If {@code putIfAbsent} returns non-null then was actually a
+ // {@code replace} and older key was used. In that case the new
+ // key was not used and the reference marked stale.
+ entryKey.unused();
+ return false;
+ }
+ }
+
}
diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java
index 807eea87dfe..21b940439e0 100644
--- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java
+++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java
@@ -148,7 +148,7 @@ public boolean contains(Object o) {
@Override
public boolean add(T e) {
- return intern(e) == null;
+ return ReferencedKeyMap.internAddKey(map, e);
}
@Override
diff --git a/src/java.base/share/classes/sun/net/www/MessageHeader.java b/src/java.base/share/classes/sun/net/www/MessageHeader.java
index 4192d8920f7..6af23e43ad2 100644
--- a/src/java.base/share/classes/sun/net/www/MessageHeader.java
+++ b/src/java.base/share/classes/sun/net/www/MessageHeader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,17 +40,15 @@
the header that don't have a valid key, but do have
a value (this isn't legal according to the standard,
but lines like this are everywhere). */
-public
-class MessageHeader {
- private String keys[];
- private String values[];
+public final class MessageHeader {
+ private String[] keys;
+ private String[] values;
private int nkeys;
public MessageHeader () {
grow();
}
- @SuppressWarnings("this-escape")
public MessageHeader (InputStream is) throws java.io.IOException {
parseHeader(is);
}
diff --git a/src/java.base/share/classes/sun/text/resources/FormatData_en.java b/src/java.base/share/classes/sun/text/resources/FormatData_en.java
deleted file mode 100644
index 117cfab0a30..00000000000
--- a/src/java.base/share/classes/sun/text/resources/FormatData_en.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 1997, 2014, 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.
- */
-
-/*
- * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
- * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
- *
- * The original version of this source code and documentation
- * is copyrighted and owned by Taligent, Inc., a wholly-owned
- * subsidiary of IBM. These materials are provided under terms
- * of a License Agreement between Taligent and Sun. This technology
- * is protected by multiple US and International patents.
- *
- * This notice and attribution to Taligent may not be removed.
- * Taligent is a registered trademark of Taligent, Inc.
- *
- */
-
-package sun.text.resources;
-
-import sun.util.resources.ParallelListResourceBundle;
-
-public class FormatData_en extends ParallelListResourceBundle {
- /**
- * Overrides ParallelListResourceBundle
- */
- protected final Object[][] getContents() {
- // This locale inherits almost everything from the root default locale. However,
- // even if it inherited everything, we would still need this locale to exist
- // to make the resource-bundle lookup mechanism work right. In that case, we'd
- // define this method as follows:
- // return new Object[][] { };
- return new Object[][] {
- { "MonthNarrows",
- new String[] {
- "J",
- "F",
- "M",
- "A",
- "M",
- "J",
- "J",
- "A",
- "S",
- "O",
- "N",
- "D",
- "",
- }
- },
- { "NumberPatterns",
- new String[] {
- "#,##0.###;-#,##0.###", // decimal pattern
- "\u00A4#,##0.00;-\u00A4#,##0.00", // currency pattern
- "#,##0%" // percent pattern
- }
- },
- { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" },
- };
- }
-}
diff --git a/src/java.base/share/classes/sun/text/resources/FormatData_en_US.java b/src/java.base/share/classes/sun/text/resources/FormatData_en_US.java
deleted file mode 100644
index cf25a1c26fc..00000000000
--- a/src/java.base/share/classes/sun/text/resources/FormatData_en_US.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 1998, 2013, 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.
- */
-
-/*
- * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
- * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
- *
- * The original version of this source code and documentation
- * is copyrighted and owned by Taligent, Inc., a wholly-owned
- * subsidiary of IBM. These materials are provided under terms
- * of a License Agreement between Taligent and Sun. This technology
- * is protected by multiple US and International patents.
- *
- * This notice and attribution to Taligent may not be removed.
- * Taligent is a registered trademark of Taligent, Inc.
- *
- */
-
-package sun.text.resources;
-
-import sun.util.resources.ParallelListResourceBundle;
-
-public class FormatData_en_US extends ParallelListResourceBundle {
- /**
- * Overrides ParallelListResourceBundle
- */
- protected final Object[][] getContents() {
- return new Object[][] {
- { "NumberPatterns",
- new String[] {
- "#,##0.###;-#,##0.###", // decimal pattern
- "\u00a4#,##0.00;(\u00a4#,##0.00)", // currency pattern
- "#,##0%" // percent pattern
- }
- },
- };
- }
-}
diff --git a/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary_en.java b/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary_en.java
deleted file mode 100644
index bd4c6cedbac..00000000000
--- a/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary_en.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.
- */
-
-/*
- * COPYRIGHT AND PERMISSION NOTICE
- *
- * Copyright (C) 1991-2016 Unicode, Inc. All rights reserved.
- * Distributed under the Terms of Use in
- * http://www.unicode.org/copyright.html.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of the Unicode data files and any associated documentation
- * (the "Data Files") or Unicode software and any associated documentation
- * (the "Software") to deal in the Data Files or Software
- * without restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, and/or sell copies of
- * the Data Files or Software, and to permit persons to whom the Data Files
- * or Software are furnished to do so, provided that
- * (a) this copyright and permission notice appear with all copies
- * of the Data Files or Software,
- * (b) this copyright and permission notice appear in associated
- * documentation, and
- * (c) there is clear notice in each modified Data File or in the Software
- * as well as in the documentation associated with the Data File(s) or
- * Software that the data or software has been modified.
- *
- * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
- * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
- * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
- * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THE DATA FILES OR SOFTWARE.
- *
- * Except as contained in this notice, the name of a copyright holder
- * shall not be used in advertising or otherwise to promote the sale,
- * use or other dealings in these Data Files or Software without prior
- * written authorization of the copyright holder.
- */
-
-// Note: this file has been generated by a tool.
-
-package sun.text.resources;
-
-import sun.util.resources.OpenListResourceBundle;
-
-public class JavaTimeSupplementary_en extends OpenListResourceBundle {
- @Override
- protected final Object[][] getContents() {
- final String[] sharedQuarterNames = {
- "1st quarter",
- "2nd quarter",
- "3rd quarter",
- "4th quarter",
- };
-
- final String[] sharedDatePatterns = {
- "EEEE, MMMM d, y GGGG",
- "MMMM d, y GGGG",
- "MMM d, y GGGG",
- "M/d/y G",
- };
-
- final String[] sharedDayNames = {
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday",
- };
-
- final String[] sharedQuarterAbbreviations = {
- "Q1",
- "Q2",
- "Q3",
- "Q4",
- };
-
- final String[] sharedTimePatterns = {
- "h:mm:ss a zzzz",
- "h:mm:ss a z",
- "h:mm:ss a",
- "h:mm a",
- };
-
- final String[] sharedNarrowAmPmMarkers = {
- "a",
- "p",
- };
-
- final String[] sharedJavaTimeDatePatterns = {
- "EEEE, MMMM d, y G",
- "MMMM d, y G",
- "MMM d, y G",
- "M/d/y GGGGG",
- };
-
- final String[] sharedEras = {
- "Before R.O.C.",
- "Minguo",
- };
-
- return new Object[][] {
- { "QuarterNames",
- sharedQuarterNames },
- { "calendarname.buddhist",
- "Buddhist Calendar" },
- { "calendarname.gregorian",
- "Gregorian Calendar" },
- { "calendarname.gregory",
- "Gregorian Calendar" },
- { "calendarname.islamic",
- "Islamic Calendar" },
- { "calendarname.islamic-civil",
- "Islamic Calendar (tabular, civil epoch)" },
- { "calendarname.islamic-umalqura",
- "Islamic Calendar (Umm al-Qura)" },
- { "calendarname.japanese",
- "Japanese Calendar" },
- { "calendarname.roc",
- "Minguo Calendar" },
- { "field.dayperiod",
- "AM/PM" },
- { "field.era",
- "era" },
- { "field.hour",
- "hour" },
- { "field.minute",
- "minute" },
- { "field.month",
- "month" },
- { "field.second",
- "second" },
- { "field.week",
- "week" },
- { "field.weekday",
- "day of the week" },
- { "field.year",
- "year" },
- { "field.zone",
- "time zone" },
- { "islamic.AmPmMarkers",
- new String[] {
- "AM",
- "PM",
- }
- },
- { "islamic.DatePatterns",
- sharedDatePatterns },
- { "islamic.DayNames",
- sharedDayNames },
- { "islamic.QuarterAbbreviations",
- sharedQuarterAbbreviations },
- { "islamic.QuarterNames",
- sharedQuarterNames },
- { "islamic.TimePatterns",
- sharedTimePatterns },
- { "islamic.narrow.AmPmMarkers",
- sharedNarrowAmPmMarkers },
- { "java.time.buddhist.DatePatterns",
- sharedJavaTimeDatePatterns },
- { "java.time.buddhist.short.Eras",
- new String[] {
- "BC",
- "BE",
- }
- },
- { "java.time.islamic.DatePatterns",
- sharedJavaTimeDatePatterns },
- { "java.time.japanese.DatePatterns",
- sharedJavaTimeDatePatterns },
- { "java.time.long.Eras",
- new String[] {
- "Before Christ",
- "Anno Domini",
- }
- },
- { "java.time.roc.DatePatterns",
- sharedJavaTimeDatePatterns },
- { "roc.DatePatterns",
- sharedDatePatterns },
- { "roc.DayAbbreviations",
- new String[] {
- "Sun",
- "Mon",
- "Tue",
- "Wed",
- "Thu",
- "Fri",
- "Sat",
- }
- },
- { "roc.DayNames",
- sharedDayNames },
- { "roc.Eras",
- sharedEras },
- { "roc.MonthNames",
- new String[] {
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December",
- "",
- }
- },
- { "roc.MonthNarrows",
- new String[] {
- "J",
- "F",
- "M",
- "A",
- "M",
- "J",
- "J",
- "A",
- "S",
- "O",
- "N",
- "D",
- "",
- }
- },
- { "roc.QuarterAbbreviations",
- sharedQuarterAbbreviations },
- { "roc.QuarterNames",
- sharedQuarterNames },
- { "roc.TimePatterns",
- sharedTimePatterns },
- { "roc.long.Eras",
- sharedEras },
- { "roc.narrow.AmPmMarkers",
- sharedNarrowAmPmMarkers },
- { "roc.narrow.Eras",
- sharedEras },
- { "roc.short.Eras",
- sharedEras },
- };
- }
-}
diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java
index f97888a6977..3373d3e7a96 100644
--- a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java
+++ b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
import static sun.util.locale.provider.LocaleProviderAdapter.Type;
import java.text.MessageFormat;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
@@ -154,10 +156,15 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea
var cands = ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR))
.getCandidateLocales("", locale);
for (int i = 1; i < cands.size() ; i++) {
- String[] parentNames = super.getDisplayNameArray(id, cands.get(i));
+ var loc = cands.get(i);
+ String[] parentNames = super.getDisplayNameArray(id, loc);
if (parentNames != null && !parentNames[index].isEmpty()) {
- names[index] = parentNames[index];
- return;
+ // Long names in ROOT locale should not be copied, as they can be generated
+ // with the fallback mechanisms below
+ if (!loc.equals(Locale.ROOT) || index % 2 == 0) {
+ names[index] = parentNames[index];
+ return;
+ }
}
}
}
@@ -167,19 +174,6 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea
return;
}
- // Check if COMPAT can substitute the name
- if (!exists(names, index) &&
- LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) {
- String[] compatNames = (String[])LocaleProviderAdapter.forJRE()
- .getLocaleResources(mapChineseLocale(locale))
- .getTimeZoneNames(id);
- if (compatNames != null) {
- // Assumes COMPAT has no empty slots
- names[index] = compatNames[index];
- return;
- }
- }
-
// Region Fallback
if (regionFormatFallback(names, index, locale)) {
return;
@@ -270,8 +264,18 @@ private boolean regionFormatFallback(String[] names, int index, Locale l) {
}
private String toGMTFormat(String id, boolean daylight, Locale l) {
- TimeZone tz = ZoneInfoFile.getZoneInfo(id);
- int offset = (tz.getRawOffset() + (daylight ? tz.getDSTSavings() : 0)) / 60000;
+ var zr = ZoneInfoFile.getZoneInfo(id).toZoneId().getRules();
+ var now = Instant.now();
+ var saving = zr.getTransitions().reversed().stream()
+ .dropWhile(zot -> zot.getInstant().isAfter(now))
+ .filter(zot -> zr.isDaylightSavings(zot.getInstant()))
+ .findFirst()
+ .map(zot -> zr.getDaylightSavings(zot.getInstant()))
+ .map(Duration::getSeconds)
+ .map(Long::intValue)
+ .orElse(0);
+ int offset = (zr.getStandardOffset(now).getTotalSeconds() +
+ (daylight ? saving : 0)) / 60;
LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l);
ResourceBundle fd = lr.getJavaTimeFormatData();
@@ -294,33 +298,4 @@ private String toGMTFormat(String id, boolean daylight, Locale l) {
String.format(l, hourFormat, offset / 60, offset % 60));
}
}
-
- // Mapping CLDR's Simplified/Traditional Chinese resources
- // to COMPAT's zh-CN/TW
- private Locale mapChineseLocale(Locale locale) {
- if (locale.getLanguage() == "zh") {
- switch (locale.getScript()) {
- case "Hans":
- return Locale.CHINA;
- case "Hant":
- return Locale.TAIWAN;
- case "":
- // no script, guess from country code.
- switch (locale.getCountry()) {
- case "":
- case "CN":
- case "SG":
- return Locale.CHINA;
- case "HK":
- case "MO":
- case "TW":
- return Locale.TAIWAN;
- }
- break;
- }
- }
-
- // no need to map
- return locale;
- }
}
diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java
index 89cda00a208..7e0fc9a2d34 100644
--- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java
+++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,34 +33,35 @@
package sun.util.locale;
import jdk.internal.misc.CDS;
+import jdk.internal.util.ReferencedKeySet;
import jdk.internal.util.StaticProperty;
import jdk.internal.vm.annotation.Stable;
-import java.lang.ref.SoftReference;
import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
public final class BaseLocale {
public static @Stable BaseLocale[] constantBaseLocales;
- public static final byte ENGLISH = 0,
- FRENCH = 1,
- GERMAN = 2,
- ITALIAN = 3,
- JAPANESE = 4,
- KOREAN = 5,
- CHINESE = 6,
- SIMPLIFIED_CHINESE = 7,
- TRADITIONAL_CHINESE = 8,
- FRANCE = 9,
- GERMANY = 10,
- ITALY = 11,
- JAPAN = 12,
- KOREA = 13,
- UK = 14,
- US = 15,
- CANADA = 16,
- CANADA_FRENCH = 17,
- ROOT = 18,
+ public static final byte ROOT = 0,
+ ENGLISH = 1,
+ US = 2,
+ FRENCH = 3,
+ GERMAN = 4,
+ ITALIAN = 5,
+ JAPANESE = 6,
+ KOREAN = 7,
+ CHINESE = 8,
+ SIMPLIFIED_CHINESE = 9,
+ TRADITIONAL_CHINESE = 10,
+ FRANCE = 11,
+ GERMANY = 12,
+ ITALY = 13,
+ JAPAN = 14,
+ KOREA = 15,
+ UK = 16,
+ CANADA = 17,
+ CANADA_FRENCH = 18,
NUM_CONSTANTS = 19;
static {
CDS.initializeFromArchive(BaseLocale.class);
@@ -90,6 +91,10 @@ public final class BaseLocale {
}
}
+ // Interned BaseLocale cache
+ private static final ReferencedKeySet CACHE =
+ ReferencedKeySet.create(true, ConcurrentHashMap::new);
+
public static final String SEP = "_";
private final String language;
@@ -107,27 +112,17 @@ public final class BaseLocale {
private static final boolean OLD_ISO_CODES = StaticProperty.javaLocaleUseOldISOCodes()
.equalsIgnoreCase("true");
- // This method must be called with normalize = false only when creating the
- // Locale.* constants and non-normalized BaseLocale$Keys used for lookup.
- private BaseLocale(String language, String script, String region, String variant,
- boolean normalize) {
- if (normalize) {
- this.language = LocaleUtils.toLowerString(language).intern();
- this.script = LocaleUtils.toTitleString(script).intern();
- this.region = LocaleUtils.toUpperString(region).intern();
- this.variant = variant.intern();
- } else {
- this.language = language;
- this.script = script;
- this.region = region;
- this.variant = variant;
- }
+ private BaseLocale(String language, String script, String region, String variant) {
+ this.language = language;
+ this.script = script;
+ this.region = region;
+ this.variant = variant;
}
// Called for creating the Locale.* constants. No argument
// validation is performed.
private static BaseLocale createInstance(String language, String region) {
- return new BaseLocale(language, "", region, "", false);
+ return new BaseLocale(language, "", region, "");
}
public static BaseLocale getInstance(String language, String script,
@@ -153,8 +148,8 @@ public static BaseLocale getInstance(String language, String script,
// Check for constant base locales first
if (script.isEmpty() && variant.isEmpty()) {
for (BaseLocale baseLocale : constantBaseLocales) {
- if (baseLocale.getLanguage().equals(language)
- && baseLocale.getRegion().equals(region)) {
+ if (baseLocale.language.equals(language)
+ && baseLocale.region.equals(region)) {
return baseLocale;
}
}
@@ -165,8 +160,15 @@ public static BaseLocale getInstance(String language, String script,
language = convertOldISOCodes(language);
}
- Key key = new Key(language, script, region, variant, false);
- return Cache.CACHE.get(key);
+ // Obtain the "interned" BaseLocale from the cache. The returned
+ // "interned" instance can subsequently be used by the Locale
+ // instance which guarantees the locale components are properly cased/interned.
+ return CACHE.intern(new BaseLocale(language, script, region, variant),
+ (b) -> new BaseLocale(
+ LocaleUtils.toLowerString(b.language).intern(),
+ LocaleUtils.toTitleString(b.script).intern(),
+ LocaleUtils.toUpperString(b.region).intern(),
+ b.variant.intern()));
}
public static String convertOldISOCodes(String language) {
@@ -199,14 +201,14 @@ public boolean equals(Object obj) {
if (this == obj) {
return true;
}
- if (!(obj instanceof BaseLocale)) {
- return false;
+ if (obj instanceof BaseLocale other) {
+ return LocaleUtils.caseIgnoreMatch(other.language, language)
+ && LocaleUtils.caseIgnoreMatch(other.region, region)
+ && LocaleUtils.caseIgnoreMatch(other.script, script)
+ // variant is case sensitive in JDK!
+ && other.variant.equals(variant);
}
- BaseLocale other = (BaseLocale)obj;
- return language == other.language
- && script == other.script
- && region == other.region
- && variant == other.variant;
+ return false;
}
@Override
@@ -231,128 +233,26 @@ public String toString() {
public int hashCode() {
int h = hash;
if (h == 0) {
- // Generating a hash value from language, script, region and variant
- h = language.hashCode();
- h = 31 * h + script.hashCode();
- h = 31 * h + region.hashCode();
- h = 31 * h + variant.hashCode();
- if (h != 0) {
- hash = h;
- }
- }
- return h;
- }
-
- private static final class Key {
- /**
- * Keep a SoftReference to the Key data if normalized (actually used
- * as a cache key) and not initialized via the constant creation path.
- *
- * This allows us to avoid creating SoftReferences on lookup Keys
- * (which are short-lived) and for Locales created via
- * Locale#createConstant.
- */
- private final SoftReference holderRef;
- private final BaseLocale holder;
-
- private final boolean normalized;
- private final int hash;
-
- private Key(String language, String script, String region,
- String variant, boolean normalize) {
- BaseLocale locale = new BaseLocale(language, script, region, variant, normalize);
- this.normalized = normalize;
- if (normalized) {
- this.holderRef = new SoftReference<>(locale);
- this.holder = null;
- } else {
- this.holderRef = null;
- this.holder = locale;
- }
- this.hash = hashCode(locale);
- }
-
- public int hashCode() {
- return hash;
- }
-
- private int hashCode(BaseLocale locale) {
- int h = 0;
- String lang = locale.getLanguage();
- int len = lang.length();
+ int len = language.length();
for (int i = 0; i < len; i++) {
- h = 31*h + LocaleUtils.toLower(lang.charAt(i));
+ h = 31*h + LocaleUtils.toLower(language.charAt(i));
}
- String scrt = locale.getScript();
- len = scrt.length();
+ len = script.length();
for (int i = 0; i < len; i++) {
- h = 31*h + LocaleUtils.toLower(scrt.charAt(i));
+ h = 31*h + LocaleUtils.toLower(script.charAt(i));
}
- String regn = locale.getRegion();
- len = regn.length();
+ len = region.length();
for (int i = 0; i < len; i++) {
- h = 31*h + LocaleUtils.toLower(regn.charAt(i));
+ h = 31*h + LocaleUtils.toLower(region.charAt(i));
}
- String vart = locale.getVariant();
- len = vart.length();
+ len = variant.length();
for (int i = 0; i < len; i++) {
- h = 31*h + vart.charAt(i);
- }
- return h;
- }
-
- private BaseLocale getBaseLocale() {
- return (holder == null) ? holderRef.get() : holder;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
+ h = 31*h + variant.charAt(i);
}
- if (obj instanceof Key && this.hash == ((Key)obj).hash) {
- BaseLocale other = ((Key) obj).getBaseLocale();
- BaseLocale locale = this.getBaseLocale();
- if (other != null && locale != null
- && LocaleUtils.caseIgnoreMatch(other.getLanguage(), locale.getLanguage())
- && LocaleUtils.caseIgnoreMatch(other.getScript(), locale.getScript())
- && LocaleUtils.caseIgnoreMatch(other.getRegion(), locale.getRegion())
- // variant is case sensitive in JDK!
- && other.getVariant().equals(locale.getVariant())) {
- return true;
- }
- }
- return false;
- }
-
- public static Key normalize(Key key) {
- if (key.normalized) {
- return key;
+ if (h != 0) {
+ hash = h;
}
-
- // Only normalized keys may be softly referencing the data holder
- assert (key.holder != null && key.holderRef == null);
- BaseLocale locale = key.holder;
- return new Key(locale.getLanguage(), locale.getScript(),
- locale.getRegion(), locale.getVariant(), true);
- }
- }
-
- private static class Cache extends LocaleObjectCache {
-
- private static final Cache CACHE = new Cache();
-
- public Cache() {
- }
-
- @Override
- protected Key normalizeKey(Key key) {
- return Key.normalize(key);
- }
-
- @Override
- protected BaseLocale createObject(Key key) {
- return Key.normalize(key).getBaseLocale();
}
+ return h;
}
}
diff --git a/src/java.base/share/classes/sun/util/locale/LocaleObjectCache.java b/src/java.base/share/classes/sun/util/locale/LocaleObjectCache.java
deleted file mode 100644
index 8712f8b8ad8..00000000000
--- a/src/java.base/share/classes/sun/util/locale/LocaleObjectCache.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. 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.
- */
-
-/*
- *******************************************************************************
- * Copyright (C) 2009-2010, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-package sun.util.locale;
-
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.SoftReference;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-public abstract class LocaleObjectCache {
- private final ConcurrentMap> map;
- private final ReferenceQueue queue = new ReferenceQueue<>();
-
- public LocaleObjectCache() {
- this(16, 0.75f, 16);
- }
-
- public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) {
- map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
- }
-
- public V get(K key) {
- V value = null;
-
- cleanStaleEntries();
- CacheEntry entry = map.get(key);
- if (entry != null) {
- value = entry.get();
- }
- if (value == null) {
- key = normalizeKey(key);
- V newVal = createObject(key);
- if (key == null || newVal == null) {
- // subclass must return non-null key/value object
- return null;
- }
-
- CacheEntry newEntry = new CacheEntry<>(key, newVal, queue);
- entry = map.putIfAbsent(key, newEntry);
- if (entry == null) {
- value = newVal;
- } else {
- value = entry.get();
- if (value == null) {
- map.put(key, newEntry);
- value = newVal;
- }
- }
- }
- return value;
- }
-
- protected V put(K key, V value) {
- CacheEntry entry = new CacheEntry<>(key, value, queue);
- CacheEntry oldEntry = map.put(key, entry);
- return (oldEntry == null) ? null : oldEntry.get();
- }
-
- @SuppressWarnings("unchecked")
- private void cleanStaleEntries() {
- CacheEntry entry;
- while ((entry = (CacheEntry)queue.poll()) != null) {
- map.remove(entry.getKey(), entry);
- }
- }
-
- protected abstract V createObject(K key);
-
- protected K normalizeKey(K key) {
- return key;
- }
-
- private static class CacheEntry extends SoftReference {
- private final K key;
-
- CacheEntry(K key, V value, ReferenceQueue queue) {
- super(value, queue);
- this.key = key;
- }
-
- K getKey() {
- return key;
- }
- }
-}
diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template b/src/java.base/share/classes/sun/util/locale/provider/BaseLocaleDataMetaInfo.java
similarity index 67%
rename from src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
rename to src/java.base/share/classes/sun/util/locale/provider/BaseLocaleDataMetaInfo.java
index 7509b602b6c..f6243b6b860 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
+++ b/src/java.base/share/classes/sun/util/locale/provider/BaseLocaleDataMetaInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,58 +23,49 @@
* questions.
*/
-#warn This file is preprocessed before being compiled
-
/*
* This class contains a map which records the locale list string for
* each resource in sun.util.resources & sun.text.resources.
* It is used to avoid loading non-existent localized resources so that
- * jar files won't be opened unnecessary to look up them.
+ * jar files won't be opened unnecessarily to look up them.
*/
-package #Package#;
+package sun.util.locale.provider;
import java.util.HashMap;
import java.util.Map;
-import sun.util.locale.provider.LocaleDataMetaInfo;
import static sun.util.locale.provider.LocaleProviderAdapter.Type;
-public class #Lang#LocaleDataMetaInfo implements LocaleDataMetaInfo {
+public class BaseLocaleDataMetaInfo implements LocaleDataMetaInfo {
- private static final Map resourceNameToLocales = new HashMap<>(9);
+ private static final Map resourceNameToLocales = HashMap.newHashMap(9);
static {
- /* During JDK build time, #XXX_YYY# will be replaced by a string contain all the locales
- supported by the resource.
-
- Don't remove the space character between " and #. That is put there purposely so that
- look up locale string such as "en" could be based on if it contains " en ".
- */
resourceNameToLocales.put("FormatData",
- " #FormatData_Locales# ");
+ " en en-US ");
resourceNameToLocales.put("CollationData",
- " #CollationData_Locales# ");
+ " ");
resourceNameToLocales.put("BreakIteratorInfo",
- " #BreakIteratorInfo_Locales# ");
+ " ");
resourceNameToLocales.put("BreakIteratorRules",
- " #BreakIteratorRules_Locales# ");
+ " ");
resourceNameToLocales.put("TimeZoneNames",
- " #TimeZoneNames_Locales# ");
+ " en ");
resourceNameToLocales.put("LocaleNames",
- " #LocaleNames_Locales# ");
+ " en ");
resourceNameToLocales.put("CurrencyNames",
- " #CurrencyNames_Locales# ");
+ " en-US ");
resourceNameToLocales.put("CalendarData",
- " #CalendarData_Locales# ");
+ " en ");
resourceNameToLocales.put("AvailableLocales",
- " #AvailableLocales_Locales# ");
+ " en en-US ");
}
/*
@@ -91,7 +82,7 @@ public static String getSupportedLocaleString(String resourceName) {
@Override
public Type getType() {
return Type.JRE;
-}
+ }
@Override
public String availableLanguageTags(String category) {
diff --git a/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java b/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java
index 19d32f16793..211dff643ec 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java
+++ b/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,29 +84,17 @@ public String getDisplayNameImpl(String calendarType, int field, int value, int
Era[] jeras = CalendarSystem.forName("japanese").getEras();
if (value <= jeras.length) {
// Localized era name could not be retrieved from this provider.
- // This can occur either for Reiwa or SupEra.
- //
- // If it's CLDR provider, try COMPAT first, which is guaranteed to have
- // the name for Reiwa.
- if (type == LocaleProviderAdapter.Type.CLDR) {
- lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
- key = getResourceKeyFor(LocaleProviderAdapter.Type.JRE,
- calendarType, field, style, javatime);
- strings =
- javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
- }
- if (strings == null || value >= strings.length) {
- // Get the default name for SupEra
- Era supEra = jeras[value - 1]; // 0-based index
- if (javatime) {
- return getBaseStyle(style) == NARROW_FORMAT ?
- supEra.getAbbreviation() :
- supEra.getName();
- } else {
- return (style & LONG) != 0 ?
- supEra.getName() :
- supEra.getAbbreviation();
- }
+ // This can occur for SupEra.
+ // Get the default name for SupEra
+ Era supEra = jeras[value - 1]; // 0-based index
+ if (javatime) {
+ return getBaseStyle(style) == NARROW_FORMAT ?
+ supEra.getAbbreviation() :
+ supEra.getName();
+ } else {
+ return (style & LONG) != 0 ?
+ supEra.getName() :
+ supEra.getAbbreviation();
}
} else {
return null;
@@ -314,7 +302,7 @@ private static String getResourceKeyFor(LocaleProviderAdapter.Type adapterType,
// JRE and CLDR use different resource key conventions
// due to historical reasons. (JRE DateFormatSymbols.getEras returns
// abbreviations while other getShort*() return abbreviations.)
- if (adapterType == LocaleProviderAdapter.Type.JRE) {
+ if (adapterType == LocaleProviderAdapter.Type.FALLBACK) {
if (javatime) {
if (baseStyle == LONG) {
key.append("long.");
diff --git a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java
index 30d47e3197d..8ee95c567aa 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java
+++ b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,29 +25,30 @@
package sun.util.locale.provider;
-import java.util.Collections;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.text.spi.BreakIteratorProvider;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
+import java.util.stream.Stream;
-/**
- * FallbackProviderAdapter implementation.
+/*
+ * FallbackProviderAdapter implementation. Fallback provider serves the
+ * following purposes:
*
- * @author Naoto Sato
+ * - Locale data for ROOT, in case CLDR provider is absent.
+ * - Locale data for BreakIterator/Collator resources for all locales.
+ * - "Gan-nen" support for SimpleDateFormat (provides "FirstYear" for
+ * Japanese locales).
*/
public class FallbackLocaleProviderAdapter extends JRELocaleProviderAdapter {
+ // Required locales/langtags
+ private static final Locale[] AVAILABLE_LOCS = {Locale.US, Locale.ENGLISH, Locale.ROOT};
+ private static final Set AVAILABLE_LANGTAGS = Set.of("en-US", "en", "und");
- /**
- * Supported language tag set.
- */
- private static final Set rootTagSet =
- Collections.singleton(Locale.ROOT.toLanguageTag());
-
- /**
- * Fallback provider only provides the ROOT locale data.
- */
- @SuppressWarnings("this-escape")
- private final LocaleResources rootLocaleResources =
- new LocaleResources(this, Locale.ROOT);
+ private volatile BreakIteratorProvider breakIteratorProvider;
/**
* Returns the type of this LocaleProviderAdapter
@@ -58,17 +59,45 @@ public LocaleProviderAdapter.Type getAdapterType() {
}
@Override
- public LocaleResources getLocaleResources(Locale locale) {
- return rootLocaleResources;
+ public Locale[] getAvailableLocales() {
+ return Stream.concat(Arrays.stream(super.getAvailableLocales()), Stream.of(AVAILABLE_LOCS))
+ .distinct().toArray(Locale[]::new);
}
@Override
protected Set createLanguageTagSet(String category) {
- return rootTagSet;
+ var s = new HashSet<>(super.createLanguageTagSet(category));
+ s.addAll(AVAILABLE_LANGTAGS);
+ return s;
}
@Override
- public boolean isSupportedProviderLocale(Locale locale, Setlangtags) {
- return Locale.ROOT.equals(locale);
+ public boolean isSupportedProviderLocale(Locale locale, Set langtags) {
+ if (Locale.ROOT.equals(locale)) {
+ return true;
+ }
+
+ locale = locale.stripExtensions();
+ return langtags.contains(locale.toLanguageTag());
+ }
+
+ @Override
+ // In order to correctly report supported locales
+ public BreakIteratorProvider getBreakIteratorProvider() {
+ if (breakIteratorProvider == null) {
+ @SuppressWarnings("removal")
+ BreakIteratorProvider provider = AccessController.doPrivileged(
+ (PrivilegedAction) () ->
+ new BreakIteratorProviderImpl(
+ getAdapterType(),
+ getLanguageTagSet("BreakIteratorRules")));
+
+ synchronized (this) {
+ if (breakIteratorProvider == null) {
+ breakIteratorProvider = provider;
+ }
+ }
+ }
+ return breakIteratorProvider;
}
}
diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java
index fc5a92ebf99..1dd927b8729 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java
+++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -470,7 +470,7 @@ private static String createSupportedLocaleString(String category) {
if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
String t = ldmi.availableLanguageTags(category);
if (t != null) {
- if (tags.length() > 0) {
+ if (!tags.isEmpty()) {
tags.append(' ');
}
tags.append(t);
diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java
index 01654672abf..a027191e45f 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java
+++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -126,8 +126,7 @@ public String getTextResourcesPackage() {
for (String type : types) {
type = type.trim().toUpperCase(Locale.ROOT);
if (type.equals("COMPAT") || type.equals("JRE")) {
- compatWarningMessage = "COMPAT locale provider will be removed in a future release";
- type = "JRE";
+ compatWarningMessage = "COMPAT locale provider has been removed";
}
try {
Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT));
@@ -141,17 +140,14 @@ public String getTextResourcesPackage() {
}
}
- if (!typeList.isEmpty()) {
- // bona fide preference exists
- if (!(typeList.contains(Type.CLDR) || typeList.contains(Type.JRE))) {
- // Append FALLBACK as the last resort when no ResourceBundleBasedAdapter is available.
- typeList.add(Type.FALLBACK);
- }
- } else {
+ if (typeList.isEmpty()) {
// Default preference list.
typeList.add(Type.CLDR);
- typeList.add(Type.JRE);
}
+
+ // always append FALLBACK
+ typeList.add(Type.FALLBACK);
+
adapterPreference = Collections.unmodifiableList(typeList);
// Emit logs, if any, after 'adapterPreference' is initialized which is needed
@@ -307,14 +303,13 @@ public boolean isSupportedProviderLocale(Locale locale, Set langtags) {
public static Locale[] toLocaleArray(Set tags) {
return tags.stream()
- .map(t -> {
- return switch (t) {
- case "ja-JP-JP" -> JRELocaleConstants.JA_JP_JP;
- case "no-NO-NY" -> JRELocaleConstants.NO_NO_NY;
- case "th-TH-TH" -> JRELocaleConstants.TH_TH_TH;
- default -> Locale.forLanguageTag(t);
- };
+ .map(t -> switch (t) {
+ case "ja-JP-JP" -> JRELocaleConstants.JA_JP_JP;
+ case "no-NO-NY" -> JRELocaleConstants.NO_NO_NY;
+ case "th-TH-TH" -> JRELocaleConstants.TH_TH_TH;
+ default -> Locale.forLanguageTag(t);
})
+ .distinct()
.toArray(Locale[]::new);
}
diff --git a/src/java.base/share/classes/sun/util/resources/CalendarData_en.properties b/src/java.base/share/classes/sun/util/resources/CalendarData_en.properties
deleted file mode 100644
index ca2ae0f185f..00000000000
--- a/src/java.base/share/classes/sun/util/resources/CalendarData_en.properties
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# Copyright (c) 2005, 2012, 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.
-#
-
-# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
-# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
-#
-# The original version of this source code and documentation
-# is copyrighted and owned by Taligent, Inc., a wholly-owned
-# subsidiary of IBM. These materials are provided under terms
-# of a License Agreement between Taligent and Sun. This technology
-# is protected by multiple US and International patents.
-#
-# This notice and attribution to Taligent may not be removed.
-# Taligent is a registered trademark of Taligent, Inc.
-
-
-# This bundle is empty because the data of the base bundle
-# is adequate for this locale.
-# The bundle is necessary to prevent the resource
-# bundle lookup from falling back to the default
-# locale.
diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames_en_US.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames_en_US.properties
deleted file mode 100644
index 009773ad3df..00000000000
--- a/src/java.base/share/classes/sun/util/resources/CurrencyNames_en_US.properties
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (c) 2005, 2012, 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.
-#
-
-# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
-# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
-#
-# The original version of this source code and documentation
-# is copyrighted and owned by Taligent, Inc., a wholly-owned
-# subsidiary of IBM. These materials are provided under terms
-# of a License Agreement between Taligent and Sun. This technology
-# is protected by multiple US and International patents.
-#
-# This notice and attribution to Taligent may not be removed.
-# Taligent is a registered trademark of Taligent, Inc.
-
-USD=$
diff --git a/src/java.base/share/classes/sun/util/resources/LocaleNames_en.properties b/src/java.base/share/classes/sun/util/resources/LocaleNames_en.properties
deleted file mode 100644
index ef2759e5859..00000000000
--- a/src/java.base/share/classes/sun/util/resources/LocaleNames_en.properties
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (c) 2005, 2012, 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.
-#
-# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
-# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
-#
-# The original version of this source code and documentation
-# is copyrighted and owned by Taligent, Inc., a wholly-owned
-# subsidiary of IBM. These materials are provided under terms
-# of a License Agreement between Taligent and Sun. This technology
-# is protected by multiple US and International patents.
-#
-# This notice and attribution to Taligent may not be removed.
-# Taligent is a registered trademark of Taligent, Inc.
-
-
-# This bundle is empty because the data of the base bundle
-# is adequate for this locale.
-# The bundle is necessary to prevent the resource
-# bundle lookup from falling back to the default
-# locale.
diff --git a/src/java.base/share/classes/sun/util/resources/TimeZoneNames_en.java b/src/java.base/share/classes/sun/util/resources/TimeZoneNames_en.java
deleted file mode 100644
index cc2199b8e21..00000000000
--- a/src/java.base/share/classes/sun/util/resources/TimeZoneNames_en.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 1997, 2012, 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.
- */
-
-
-/*
- * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
- * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
- *
- * The original version of this source code and documentation
- * is copyrighted and owned by Taligent, Inc., a wholly-owned
- * subsidiary of IBM. These materials are provided under terms
- * of a License Agreement between Taligent and Sun. This technology
- * is protected by multiple US and International patents.
- *
- * This notice and attribution to Taligent may not be removed.
- * Taligent is a registered trademark of Taligent, Inc.
- *
- */
-
-package sun.util.resources;
-
-import sun.util.resources.TimeZoneNamesBundle;
-
-public final class TimeZoneNames_en extends TimeZoneNamesBundle {
-
- // This bundle is empty because the root bundle's content
- // is adequate for this locale.
- // The bundle is necessary to prevent the resource
- // bundle lookup from falling back to the default
- // locale.
-
- protected final Object[][] getContents() {
- return new Object[][] {
- };
- }
-}
diff --git a/src/java.base/share/native/libfallbackLinker/fallbackLinker.c b/src/java.base/share/native/libfallbackLinker/fallbackLinker.c
index 39d869adb63..2ee64fb05bc 100644
--- a/src/java.base/share/native/libfallbackLinker/fallbackLinker.c
+++ b/src/java.base/share/native/libfallbackLinker/fallbackLinker.c
@@ -28,6 +28,7 @@
#include
#include
+#include
#include
#include
#include
@@ -275,3 +276,13 @@ JNIEXPORT jint JNICALL
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1sizeof_1wchar(JNIEnv* env, jclass cls) {
return sizeof(wchar_t);
}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_foreign_abi_fallback_LibFallback_alignof_1long_1long(JNIEnv* env, jclass cls) {
+ return alignof(long long);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_foreign_abi_fallback_LibFallback_alignof_1double(JNIEnv* env, jclass cls) {
+ return alignof(double);
+}
diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java
index 23df6b67849..10aadfa7cd8 100644
--- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java
+++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -139,19 +139,22 @@ protected void installKeyboardActions() {
*/
@SuppressWarnings("serial") // Superclass is not serializable across versions
private static class TakeFocus extends AbstractAction {
+ @Override
public void actionPerformed(ActionEvent e) {
JMenuBar menuBar = (JMenuBar)e.getSource();
JMenu menu = menuBar.getMenu(0);
if (menu != null) {
MenuSelectionManager msm =
MenuSelectionManager.defaultManager();
- MenuElement[] path = new MenuElement[2];
- path[0] = (MenuElement)menuBar;
- path[1] = (MenuElement)menu;
- msm.setSelectedPath(path);
-
- // show mnemonics
- WindowsLookAndFeel.setMnemonicHidden(false);
+ MenuElement[] selectedPath = msm.getSelectedPath();
+ if (selectedPath.length > 0 && (selectedPath[0] instanceof JMenuBar)) {
+ msm.clearSelectedPath();
+ WindowsLookAndFeel.setMnemonicHidden(true);
+ } else {
+ MenuElement[] path = {menuBar, menu};
+ msm.setSelectedPath(path);
+ WindowsLookAndFeel.setMnemonicHidden(false);
+ }
WindowsLookAndFeel.repaintRootPane(menuBar);
}
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index f922849d5fa..455e2b5446f 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -94,7 +94,7 @@
* @author K.Venugopal SUN Microsystems
* @author Neeraj Bajaj SUN Microsystems
* @author Sunitha Reddy SUN Microsystems
- * @LastModified: Jan 2024
+ * @LastModified: Feb 2024
*/
public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
@@ -1118,8 +1118,9 @@ private InputSource resolveWithCatalog(CatalogResolver cr, String cFile,
* this method attempts to resolve the resource as an EntityResolver first
* and then URIResolver if no match is found.
*/
- private XMLInputSource resolveEntityOrURI(CatalogResolver cr, String publicId, String systemId, String base) {
- XMLInputSource xis = resolveEntity(cr, publicId, systemId, base);
+ private XMLInputSource resolveEntityOrURI(String catalogName, CatalogResolver cr,
+ String publicId, String systemId, String base) {
+ XMLInputSource xis = resolveEntity(catalogName, cr, publicId, systemId, base);
if (xis != null) {
return xis;
@@ -1137,13 +1138,21 @@ private XMLInputSource resolveEntityOrURI(CatalogResolver cr, String publicId, S
return null;
}
- private XMLInputSource resolveEntity(CatalogResolver cr, String publicId, String systemId, String base) {
+ private XMLInputSource resolveEntity(String catalogName, CatalogResolver cr,
+ String publicId, String systemId, String base) {
InputSource is = null;
try {
if (publicId != null || systemId != null) {
is = cr.resolveEntity(publicId, systemId);
}
- } catch (CatalogException e) {}
+ } catch (CatalogException e) {
+ //Note: XSDHandler does not set ErrorReporter on EntityManager
+ if (fErrorReporter != null) {
+ fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,"CatalogException",
+ new Object[]{SecuritySupport.sanitizePath(catalogName)},
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e );
+ }
+ }
if (is != null && !is.isEmpty()) {
return new XMLInputSource(is, true);
@@ -1216,7 +1225,7 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
}
String pid = (publicId != null? publicId : resourceIdentifier.getNamespace());
- xmlInputSource = resolveEntityOrURI(fCatalogResolver, pid, literalSystemId, baseSystemId);
+ xmlInputSource = resolveEntityOrURI(fCatalogFile, fCatalogResolver, pid, literalSystemId, baseSystemId);
}
// Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
@@ -1225,7 +1234,7 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
&& JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
initJdkCatalogResolver();
// unlike a custom catalog, the JDK Catalog only contains entity references
- xmlInputSource = resolveEntity(fDefCR, publicId, literalSystemId, baseSystemId);
+ xmlInputSource = resolveEntity("JDKCatalog", fDefCR, publicId, literalSystemId, baseSystemId);
}
// Step 4: default resolution if not resolved by a resolver and the RESOLVE
diff --git a/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java b/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
index cfb2a264f7b..071676703e1 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -387,20 +387,21 @@ static long getLastModified(final File f) {
}
/**
- * Strip off path from an URI
+ * Strips off path from a URI or file path.
*
- * @param uri an URI with full path
+ * @param input a URI or file path
* @return the file name only
*/
- public static String sanitizePath(String uri) {
- if (uri == null) {
+ public static String sanitizePath(String input) {
+ if (input == null) {
return "";
}
- int i = uri.lastIndexOf("/");
+ input = input.replace('\\', '/');
+ int i = input.lastIndexOf('/');
if (i > 0) {
- return uri.substring(i+1, uri.length());
+ return input.substring(i+1);
}
- return "";
+ return input;
}
/**
diff --git a/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp b/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp
index 5386e4afdd3..c16fd791e5b 100644
--- a/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp
+++ b/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,22 @@ AccessBridgeJavaEntryPoints::~AccessBridgeJavaEntryPoints() {
return (returnVal); \
}
+#define EXCEPTION_CHECK_WITH_RELEASE(situationDescription, returnVal, js, stringBytes) \
+ if (exception = jniEnv->ExceptionOccurred()) { \
+ PrintDebugString("[ERROR]: *** Exception occured while doing: %s - call to GetStringLength; returning %d", situationDescription, returnVal); \
+ jniEnv->ExceptionDescribe(); \
+ jniEnv->ExceptionClear(); \
+ jniEnv->ReleaseStringChars(js, stringBytes); \
+ return (returnVal); \
+ } \
+ jniEnv->ReleaseStringChars(js, stringBytes); \
+ if (exception = jniEnv->ExceptionOccurred()) { \
+ PrintDebugString("[ERROR]: *** Exception occured while doing: %s - call to ReleaseStringChars; returning %d", situationDescription, returnVal); \
+ jniEnv->ExceptionDescribe(); \
+ jniEnv->ExceptionClear(); \
+ return (returnVal); \
+ }
+
#define EXCEPTION_CHECK_VOID(situationDescription) \
if (exception = jniEnv->ExceptionOccurred()) { \
PrintDebugString("[ERROR]: *** Exception occured while doing: %s", situationDescription); \
@@ -1215,9 +1231,7 @@ AccessBridgeJavaEntryPoints::getVirtualAccessibleName (
EXCEPTION_CHECK("Getting AccessibleName - call to GetStringChars()", FALSE);
wcsncpy(name, stringBytes, nameSize - 1);
length = jniEnv->GetStringLength(js);
- EXCEPTION_CHECK("Getting AccessibleName - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleName - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleName", FALSE, js, stringBytes);
jniEnv->CallVoidMethod (
accessBridgeObject,
decrementReferenceMethod, js);
@@ -1380,9 +1394,7 @@ AccessBridgeJavaEntryPoints::getTextAttributesInRange(const jobject accessibleCo
length = jniEnv->GetStringLength(js);
test_attributes.fullAttributesString[length < (sizeof(test_attributes.fullAttributesString) / sizeof(wchar_t)) ?
length : (sizeof(test_attributes.fullAttributesString) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleAttributesAtIndex", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to CallVoidMethod()", FALSE);
@@ -1735,11 +1747,9 @@ AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleName - call to GetStringChars()", FALSE);
wcsncpy(info->name, stringBytes, (sizeof(info->name) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleName", FALSE, js, stringBytes);
info->name[length < (sizeof(info->name) / sizeof(wchar_t)) ?
length : (sizeof(info->name) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleName - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleName - call to ReleaseStringChars()", FALSE);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleName - call to CallVoidMethod()", FALSE);
@@ -1767,11 +1777,9 @@ AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleName - call to GetStringChars()", FALSE);
wcsncpy(info->description, stringBytes, (sizeof(info->description) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleName", FALSE, js, stringBytes);
info->description[length < (sizeof(info->description) / sizeof(wchar_t)) ?
length : (sizeof(info->description) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleName - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleName - call to ReleaseStringChars()", FALSE);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleName - call to CallVoidMethod()", FALSE);
@@ -1799,11 +1807,9 @@ AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleRole - call to GetStringChars()", FALSE);
wcsncpy(info->role, stringBytes, (sizeof(info->role) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleRole", FALSE, js, stringBytes);
info->role[length < (sizeof(info->role) / sizeof(wchar_t)) ?
length : (sizeof(info->role) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleRole - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleRole - call to ReleaseStringChars()", FALSE);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleRole - call to CallVoidMethod()", FALSE);
@@ -1831,11 +1837,9 @@ AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to GetStringChars()", FALSE);
wcsncpy(info->role_en_US, stringBytes, (sizeof(info->role_en_US) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleRole_en_US", FALSE, js, stringBytes);
info->role_en_US[length < (sizeof(info->role_en_US) / sizeof(wchar_t)) ?
length : (sizeof(info->role_en_US) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to ReleaseStringChars()", FALSE);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to CallVoidMethod()", FALSE);
@@ -1862,11 +1866,9 @@ AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleState - call to GetStringChars()", FALSE);
wcsncpy(info->states, stringBytes, (sizeof(info->states) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleState", FALSE, js, stringBytes);
info->states[length < (sizeof(info->states) / sizeof(wchar_t)) ?
length : (sizeof(info->states) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleState - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleState - call to ReleaseStringChars()", FALSE);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleState - call to CallVoidMethod()", FALSE);
@@ -1893,11 +1895,9 @@ AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleState_en_US - call to GetStringChars()", FALSE);
wcsncpy(info->states_en_US, stringBytes, (sizeof(info->states_en_US) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleState_en_US", FALSE, js, stringBytes);
info->states_en_US[length < (sizeof(info->states_en_US) / sizeof(wchar_t)) ?
length : (sizeof(info->states_en_US) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleState_en_US - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleState_en_US - call to ReleaseStringChars()", FALSE);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleState_en_US - call to CallVoidMethod()", FALSE);
@@ -2809,11 +2809,9 @@ AccessBridgeJavaEntryPoints::getAccessibleRelationSet(jobject accessibleContext,
EXCEPTION_CHECK("Getting AccessibleRelation key - call to GetStringChars()", FALSE);
wcsncpy(relationSet->relations[i].key, stringBytes, (sizeof(relationSet->relations[i].key ) / sizeof(wchar_t)));
length = jniEnv->GetStringLength(js);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleRelation key", FALSE, js, stringBytes);
relationSet->relations[i].key [length < (sizeof(relationSet->relations[i].key ) / sizeof(wchar_t)) ?
length : (sizeof(relationSet->relations[i].key ) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleRelation key - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleRelation key - call to ReleaseStringChars()", FALSE);
// jniEnv->CallVoidMethod(accessBridgeObject,
// decrementReferenceMethod, js);
//EXCEPTION_CHECK("Getting AccessibleRelation key - call to CallVoidMethod()", FALSE);
@@ -2915,9 +2913,7 @@ AccessBridgeJavaEntryPoints::getAccessibleHypertext(jobject accessibleContext,
length = (sizeof(hypertext->links[i].text) / sizeof(wchar_t)) - 2;
}
hypertext->links[i].text[length] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleHyperlink text", FALSE, js, stringBytes);
// jniEnv->CallVoidMethod(accessBridgeObject,
// decrementReferenceMethod, js);
//EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to CallVoidMethod()", FALSE);
@@ -3052,9 +3048,7 @@ AccessBridgeJavaEntryPoints::getAccessibleHypertextExt(const jobject accessibleC
length = (sizeof(hypertext->links[bufIndex].text) / sizeof(wchar_t)) - 2;
}
hypertext->links[bufIndex].text[length] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleHyperlink text", FALSE, js, stringBytes);
// jniEnv->CallVoidMethod(accessBridgeObject,
// decrementReferenceMethod, js);
//EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to CallVoidMethod()", FALSE);
@@ -3171,9 +3165,7 @@ BOOL AccessBridgeJavaEntryPoints::getAccessibleHyperlink(jobject hypertext,
length = (sizeof(info->text) / sizeof(wchar_t)) - 2;
}
info->text[length] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleHyperlink text", FALSE, js, stringBytes);
// jniEnv->CallVoidMethod(accessBridgeObject,
// decrementReferenceMethod, js);
//EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to CallVoidMethod()", FALSE);
@@ -3300,9 +3292,7 @@ BOOL AccessBridgeJavaEntryPoints::getAccessibleIcons(jobject accessibleContext,
length = (sizeof(icons->iconInfo[i].description) / sizeof(wchar_t)) - 2;
}
icons->iconInfo[i].description[length] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleIcon description - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleIcon description - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleIcon description", FALSE, js, stringBytes);
// jniEnv->CallVoidMethod(accessBridgeObject,
// decrementReferenceMethod, js);
//EXCEPTION_CHECK("Getting AccessibleIcon description - call to CallVoidMethod()", FALSE);
@@ -3379,9 +3369,7 @@ BOOL AccessBridgeJavaEntryPoints::getAccessibleActions(jobject accessibleContext
length = (sizeof(actions->actionInfo[i].name ) / sizeof(wchar_t)) - 2;
}
actions->actionInfo[i].name [length] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleAction name - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleAction name - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleAction name", FALSE, js, stringBytes);
// jniEnv->CallVoidMethod(accessBridgeObject,
// decrementReferenceMethod, js);
//EXCEPTION_CHECK("Getting AccessibleAction name - call to CallVoidMethod()", FALSE);
@@ -3561,9 +3549,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextItems(jobject accessibleContext,
length = jniEnv->GetStringLength(js);
textItems->word[length < (sizeof(textItems->word) / sizeof(wchar_t)) ?
length : (sizeof(textItems->word) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleWordAtIndex", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to CallVoidMethod()", FALSE);
@@ -3597,9 +3583,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextItems(jobject accessibleContext,
} else {
textItems->sentence[(sizeof(textItems->sentence) / sizeof(wchar_t))-2] = (wchar_t) 0;
}
- EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleSentenceAtIndex", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to CallVoidMethod()", FALSE);
@@ -3673,9 +3657,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextSelectionInfo(jobject accessibleCo
length = jniEnv->GetStringLength(js);
selectionInfo->selectedText[length < (sizeof(selectionInfo->selectedText) / sizeof(wchar_t)) ?
length : (sizeof(selectionInfo->selectedText) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleTextSelectedText", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to CallVoidMethod()", FALSE);
@@ -3890,9 +3872,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextAttributes(jobject accessibleConte
length = jniEnv->GetStringLength(js);
attributes->backgroundColor[length < (sizeof(attributes->backgroundColor) / sizeof(wchar_t)) ?
length : (sizeof(attributes->backgroundColor) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting BackgroundColorFromAttributeSet", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to CallVoidMethod()", FALSE);
@@ -3927,9 +3907,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextAttributes(jobject accessibleConte
length = jniEnv->GetStringLength(js);
attributes->foregroundColor[length < (sizeof(attributes->foregroundColor) / sizeof(wchar_t)) ?
length : (sizeof(attributes->foregroundColor) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting ForegroundColorFromAttributeSet", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to CallVoidMethod()", FALSE);
@@ -3964,9 +3942,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextAttributes(jobject accessibleConte
length = jniEnv->GetStringLength(js);
attributes->fontFamily[length < (sizeof(attributes->fontFamily) / sizeof(wchar_t)) ?
length : (sizeof(attributes->fontFamily) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting FontFamilyFromAttributeSet", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to CallVoidMethod()", FALSE);
@@ -4170,9 +4146,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextAttributes(jobject accessibleConte
length = jniEnv->GetStringLength(js);
attributes->fullAttributesString[length < (sizeof(attributes->fullAttributesString) / sizeof(wchar_t)) ?
length : (sizeof(attributes->fullAttributesString) / sizeof(wchar_t))-2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleAttributesAtIndex", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to CallVoidMethod()", FALSE);
@@ -4413,9 +4387,7 @@ AccessBridgeJavaEntryPoints::getAccessibleTextRange(jobject accessibleContext,
PrintDebugString("[INFO]: Accessible Text stringBytes length = %d", length);
text[length < len ? length : len - 2] = (wchar_t) 0;
wPrintDebugString(L"[INFO]: Accessible Text 'text' after null termination = %ls", text);
- EXCEPTION_CHECK("Getting AccessibleTextRange - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting AccessibleTextRange - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting AccessibleTextRange", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting AccessibleTextRange - call to CallVoidMethod()", FALSE);
@@ -4458,9 +4430,7 @@ AccessBridgeJavaEntryPoints::getCurrentAccessibleValueFromContext(jobject access
wcsncpy(value, stringBytes, len);
length = jniEnv->GetStringLength(js);
value[length < len ? length : len - 2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting CurrentAccessibleValue", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to CallVoidMethod()", FALSE);
@@ -4501,9 +4471,7 @@ AccessBridgeJavaEntryPoints::getMaximumAccessibleValueFromContext(jobject access
wcsncpy(value, stringBytes, len);
length = jniEnv->GetStringLength(js);
value[length < len ? length : len - 2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting MaximumAccessibleValue", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to CallVoidMethod()", FALSE);
@@ -4544,9 +4512,7 @@ AccessBridgeJavaEntryPoints::getMinimumAccessibleValueFromContext(jobject access
wcsncpy(value, stringBytes, len);
length = jniEnv->GetStringLength(js);
value[length < len ? length : len - 2] = (wchar_t) 0;
- EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to GetStringLength()", FALSE);
- jniEnv->ReleaseStringChars(js, stringBytes);
- EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to ReleaseStringChars()", FALSE);
+ EXCEPTION_CHECK_WITH_RELEASE("Getting MinimumAccessibleValue", FALSE, js, stringBytes);
jniEnv->CallVoidMethod(accessBridgeObject,
decrementReferenceMethod, js);
EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to CallVoidMethod()", FALSE);
diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
index d6a91a7a9c0..87cd10b400f 100644
--- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
@@ -221,35 +221,60 @@ static String[] exceptionToString(Throwable o, boolean toString, boolean stackTr
*/
static final Map options = new HashMap<>();
+ /**
+ * Sentinel help value to denote options that are not printed by -XX:+JVMCIPrintProperties.
+ * Javadoc is used instead to document these options.
+ */
+ private static final String[] NO_HELP = null;
+
/**
* A list of all supported JVMCI options.
*/
public enum Option {
// @formatter:off
- Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " +
- "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " +
- "An empty string or the value \"null\" selects a compiler " +
- "that will raise an exception upon receiving a compilation request."),
- // Note: The following one is not used (see InitTimer.ENABLED). It is added here
- // so that -XX:+JVMCIPrintProperties shows the option.
- InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
- CodeSerializationTypeInfo(Boolean.class, false, "Prepend the size and label of each element to the stream when " +
- "serializing HotSpotCompiledCode to verify both ends of the protocol agree on the format. " +
- "Defaults to true in non-product builds."),
- DumpSerializedCode(String.class, null, "Dump serialized code during code installation for code whose simple " +
- "name (a stub) or fully qualified name (an nmethod) contains this option's value as a substring."),
- ForceTranslateFailure(String.class, null, "Forces HotSpotJVMCIRuntime.translate to throw an exception in the context " +
- "of the peer runtime. The value is a filter that can restrict the forced failure to matching translated " +
- "objects. See HotSpotJVMCIRuntime.postTranslation for more details. This option exists solely to test " +
- "correct handling of translation failures."),
- PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
- AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " +
- "to debug issue with a wrapper being used after its scope has closed."),
- TraceMethodDataFilter(String.class, null,
- "Enables tracing of profiling info when read by JVMCI.",
- "Empty value: trace all methods",
- "Non-empty value: trace methods whose fully qualified name contains the value."),
- UseProfilingInformation(Boolean.class, true, "");
+ Compiler(String.class, null,
+ "Selects the system compiler. This must match the getCompilerName() value",
+ "returned by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. ",
+ "An empty string or the value \"null\" selects a compiler ",
+ "that raises an exception upon receiving a compilation request."),
+
+ PrintConfig(Boolean.class, false, "Prints VM values (e.g. flags, constants, field offsets etc) exposed to JVMCI."),
+
+ InitTimer(Boolean.class, false, NO_HELP),
+
+ /**
+ * Prepends the size and label of each element to the stream when serializing {@link HotSpotCompiledCode}
+ * to verify both ends of the protocol agree on the format. Defaults to true in non-product builds.
+ */
+ CodeSerializationTypeInfo(Boolean.class, false, NO_HELP),
+
+ /**
+ * Dumps serialized code during code installation for code whose qualified form (e.g.
+ * {@code java.lang.String.hashCode()}) contains this option's value as a substring.
+ */
+ DumpSerializedCode(String.class, null, NO_HELP),
+
+ /**
+ * Forces {@link #translate} to throw an exception in the context of the peer runtime for
+ * translated objects that match this value. See {@link #postTranslation} for more details.
+ * This option exists solely to test correct handling of translation failures.
+ */
+ ForceTranslateFailure(String.class, null, NO_HELP),
+
+ /**
+ * Captures a stack trace along with scoped foreign object reference wrappers
+ * to debug an issue with a wrapper being used after its scope has closed.
+ */
+ AuditHandles(Boolean.class, false, NO_HELP),
+
+ /**
+ * Enables tracing of profiling info when read by JVMCI.
+ * Empty value: trace all methods
+ * Non-empty value: trace methods whose fully qualified name contains the value
+ */
+ TraceMethodDataFilter(String.class, null, NO_HELP),
+
+ UseProfilingInformation(Boolean.class, true, NO_HELP);
// @formatter:on
/**
@@ -343,6 +368,9 @@ public static void printProperties(PrintStream out) {
out.println("[JVMCI properties]");
Option[] values = values();
for (Option option : values) {
+ if (option.helpLines == null) {
+ continue;
+ }
Object value = option.getValue();
if (value instanceof String) {
value = '"' + String.valueOf(value) + '"';
@@ -362,6 +390,7 @@ public static void printProperties(PrintStream out) {
for (String line : option.helpLines) {
out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line);
}
+ out.println();
}
}
diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
index 6b9381df1ec..4c9dc509ce1 100644
--- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -632,7 +632,7 @@ public LocalVariableTable getLocalVariableTable() {
for (int i = 0; i < localVariableTableLength; i++) {
final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset);
- final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset);
+ final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset) - 1;
final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset);
final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset);
final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset);
diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Local.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Local.java
index ff444ffe094..c68ce13d811 100644
--- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Local.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Local.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,10 +41,19 @@ public Local(String name, JavaType type, int startBci, int endBci, int slot) {
this.type = type;
}
+ /**
+ * Returns the first BCI at which this local has a value (inclusive).
+ */
public int getStartBCI() {
return startBci;
}
+
+ /**
+ * Returns the last BCI at which this local has a value (inclusive).
+ * If the value returned is less than {@link #getStartBCI}, this object denotes a local
+ * variable that is never live.
+ */
public int getEndBCI() {
return endBci;
}
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java
index 4b54150e5bb..29267803009 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,12 +35,14 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jdk.jfr.AnnotationElement;
import jdk.jfr.Event;
import jdk.jfr.EventType;
+import jdk.jfr.Name;
import jdk.jfr.Period;
import jdk.jfr.StackTrace;
import jdk.jfr.Threshold;
@@ -54,8 +56,8 @@ public final class MetadataRepository {
private static final MetadataRepository instance = new MetadataRepository();
- private final List nativeEventTypes = new ArrayList<>(150);
- private final List nativeControls = new ArrayList(nativeEventTypes.size());
+ private final Map nativeEventTypes = LinkedHashMap.newHashMap(150);
+ private final Map nativeControls = LinkedHashMap.newHashMap(150);
private final SettingsManager settingsManager = new SettingsManager();
private Constructor cachedEventConfigurationConstructor;
private boolean staleMetadata = true;
@@ -83,8 +85,9 @@ private void initializeJVMEventTypes() {
PeriodicEvents.addJVMEvent(pEventType);
}
}
- nativeControls.add(new EventControl(pEventType));
- nativeEventTypes.add(eventType);
+ String name = eventType.getName();
+ nativeControls.put(name, new EventControl(pEventType));
+ nativeEventTypes.put(name,eventType);
}
}
}
@@ -101,7 +104,7 @@ public synchronized List getRegisteredEventTypes() {
eventTypes.add(ec.getEventType());
}
}
- for (EventType t : nativeEventTypes) {
+ for (EventType t : nativeEventTypes.values()) {
if (PrivateAccess.getInstance().isVisible(t)) {
eventTypes.add(t);
}
@@ -200,6 +203,32 @@ private EventConfiguration makeConfiguration(Class extends jdk.internal.event.
if (pEventType == null) {
pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields);
}
+ // Check for native mirror.
+ // Note, defining an event in metadata.xml is not a generic mechanism to emit
+ // native data in Java. For example, calling JVM.getStackTraceId(int, long)
+ // and assign the result to a long field is not enough to always get a proper
+ // stack trace. Purpose of the mechanism is to transfer metadata, such as
+ // native type IDs, without specialized Java logic for each type.
+ if (eventClass.getClassLoader() == null) {
+ Name name = eventClass.getAnnotation(Name.class);
+ if (name != null) {
+ String n = name.value();
+ EventType nativeType = nativeEventTypes.get(n);
+ if (nativeType != null) {
+ var nativeFields = nativeType.getFields();
+ var eventFields = pEventType.getFields();
+ var comparator = Comparator.comparing(ValueDescriptor::getName);
+ if (!Utils.compareLists(nativeFields, eventFields, comparator)) {
+ throw new InternalError("Field for native mirror event " + n + " doesn't match Java event");
+ }
+ nativeEventTypes.remove(n);
+ nativeControls.remove(n);
+ TypeLibrary.removeType(nativeType.getId());
+ pEventType.setAnnotations(nativeType.getAnnotationElements());
+ pEventType.setFields(nativeType.getFields());
+ }
+ }
+ }
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
EventControl ec = new EventControl(pEventType, eventClass);
EventConfiguration configuration = newEventConfiguration(eventType, ec);
@@ -226,7 +255,7 @@ synchronized void disableEvents() {
public synchronized List getEventControls() {
List> eventClasses = JVM.getAllEventClasses();
ArrayList controls = new ArrayList<>(eventClasses.size() + nativeControls.size());
- controls.addAll(nativeControls);
+ controls.addAll(nativeControls.values());
for (Class extends jdk.internal.event.Event> clazz : eventClasses) {
EventConfiguration eh = JVMSupport.getConfiguration(clazz);
if (eh != null) {
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java
index 277b28505e6..bc949b8c7ff 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -222,6 +222,10 @@ public boolean isDefinedByJVM() {
return id < JVM.RESERVED_CLASS_ID_LIMIT;
}
+ public void setFields(List fields) {
+ this.fields = List.copyOf(fields);
+ }
+
public void add(ValueDescriptor valueDescriptor) {
Objects.requireNonNull(valueDescriptor);
fields.add(valueDescriptor);
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java
index 4663ead6838..19c83b3dc1c 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -322,7 +322,7 @@ private static void addUserFields(Class> clazz, Type type, List sanitizeNullFreeStringMap(Map
return map;
}
+ public static boolean compareLists(List a, List b, Comparator