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 7ecbe2504f3..cd38bd19227 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
@@ -1307,7 +1307,8 @@ MemorySegment reinterpret(long newSize,
* @param offset offset in bytes (relative to this segment address) at which this
* access operation will occur
* @param charset the charset used to {@linkplain Charset#newDecoder() decode} the
- * string bytes
+ * string bytes. The {@code charset} must be a
+ * {@linkplain StandardCharsets standard charset}
* @return a Java string constructed from the bytes read from the given starting
* address up to (but not including) the first {@code '\0'} terminator
* character (assuming one is found)
@@ -1375,7 +1376,9 @@ MemorySegment reinterpret(long newSize,
* access operation will occur, the final address of this write
* operation can be expressed as {@code address() + offset}
* @param str the Java string to be written into this segment
- * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes
+ * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the
+ * string bytes. The {@code charset} must be a
+ * {@linkplain StandardCharsets standard charset}
* @throws IndexOutOfBoundsException if {@code offset < 0}
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + N)}, where:
*
diff --git a/src/java.base/share/classes/javax/crypto/KDF.java b/src/java.base/share/classes/javax/crypto/KDF.java
index ea2a0375813..0ee0904c1c2 100644
--- a/src/java.base/share/classes/javax/crypto/KDF.java
+++ b/src/java.base/share/classes/javax/crypto/KDF.java
@@ -396,19 +396,21 @@ public static KDF getInstance(String algorithm,
InvalidAlgorithmParameterException {
Objects.requireNonNull(algorithm, "algorithm must not be null");
Objects.requireNonNull(provider, "provider must not be null");
-
- Instance instance = GetInstance.getInstance("KDF", KDFSpi.class,
- algorithm,
- kdfParameters,
- provider);
- if (!JceSecurity.canUseProvider(instance.provider)) {
- String msg = "JCE cannot authenticate the provider "
- + instance.provider.getName();
- throw new NoSuchProviderException(msg);
+ try {
+ Instance instance = GetInstance.getInstance("KDF", KDFSpi.class,
+ algorithm,
+ kdfParameters,
+ provider);
+ if (!JceSecurity.canUseProvider(instance.provider)) {
+ String msg = "JCE cannot authenticate the provider "
+ + instance.provider.getName();
+ throw new NoSuchProviderException(msg);
+ }
+ return new KDF(new Delegate((KDFSpi) instance.impl,
+ instance.provider), algorithm);
+ } catch (NoSuchAlgorithmException nsae) {
+ return handleException(nsae);
}
- return new KDF(new Delegate((KDFSpi) instance.impl,
- instance.provider), algorithm
- );
}
/**
@@ -444,18 +446,31 @@ public static KDF getInstance(String algorithm,
InvalidAlgorithmParameterException {
Objects.requireNonNull(algorithm, "algorithm must not be null");
Objects.requireNonNull(provider, "provider must not be null");
- Instance instance = GetInstance.getInstance("KDF", KDFSpi.class,
- algorithm,
- kdfParameters,
- provider);
- if (!JceSecurity.canUseProvider(instance.provider)) {
- String msg = "JCE cannot authenticate the provider "
- + instance.provider.getName();
- throw new SecurityException(msg);
+ try {
+ Instance instance = GetInstance.getInstance("KDF", KDFSpi.class,
+ algorithm,
+ kdfParameters,
+ provider);
+ if (!JceSecurity.canUseProvider(instance.provider)) {
+ String msg = "JCE cannot authenticate the provider "
+ + instance.provider.getName();
+ throw new SecurityException(msg);
+ }
+ return new KDF(new Delegate((KDFSpi) instance.impl,
+ instance.provider), algorithm);
+ } catch (NoSuchAlgorithmException nsae) {
+ return handleException(nsae);
+ }
+ }
+
+ private static KDF handleException(NoSuchAlgorithmException e)
+ throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException {
+ Throwable cause = e.getCause();
+ if (cause instanceof InvalidAlgorithmParameterException iape) {
+ throw iape;
}
- return new KDF(new Delegate((KDFSpi) instance.impl,
- instance.provider), algorithm
- );
+ throw e;
}
/**
@@ -671,7 +686,8 @@ private static Delegate getNext(Iterator serviceIter,
if (hasOne) throw new InvalidAlgorithmParameterException(
"The KDFParameters supplied could not be used in combination "
+ "with the supplied algorithm for the selected Provider");
- else throw new NoSuchAlgorithmException();
+ else throw new NoSuchAlgorithmException(
+ "No available provider supports the specified algorithm");
}
private static boolean checkSpiNonNull(Delegate d) {
diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java
index 432b324c1bd..9b98bf82b5e 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java
@@ -41,8 +41,7 @@ final class ConfinedSession extends MemorySessionImpl {
private int asyncReleaseCount = 0;
- static final VarHandle ASYNC_RELEASE_COUNT= MhUtil.findVarHandle(
- MethodHandles.lookup(), "asyncReleaseCount", int.class);
+ static final VarHandle ASYNC_RELEASE_COUNT= MhUtil.findVarHandle(MethodHandles.lookup(), "asyncReleaseCount", int.class);
public ConfinedSession(Thread owner) {
super(owner, new ConfinedResourceList());
@@ -52,17 +51,17 @@ public ConfinedSession(Thread owner) {
@ForceInline
public void acquire0() {
checkValidState();
- if (state == MAX_FORKS) {
+ if (acquireCount == MAX_FORKS) {
throw tooManyAcquires();
}
- state++;
+ acquireCount++;
}
@Override
@ForceInline
public void release0() {
if (Thread.currentThread() == owner) {
- state--;
+ acquireCount--;
} else {
// It is possible to end up here in two cases: this session was kept alive by some other confined session
// which is implicitly released (in which case the release call comes from the cleaner thread). Or,
@@ -75,11 +74,11 @@ public void release0() {
void justClose() {
checkValidState();
int asyncCount = (int)ASYNC_RELEASE_COUNT.getVolatile(this);
- if ((state == 0 && asyncCount == 0)
- || ((state - asyncCount) == 0)) {
+ int acquire = acquireCount - asyncCount;
+ if (acquire == 0) {
state = CLOSED;
} else {
- throw alreadyAcquired(state - asyncCount);
+ throw alreadyAcquired(acquire);
}
}
diff --git a/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java b/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java
index c075778b5ee..3fc46d6c0bc 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java
@@ -42,6 +42,7 @@ non-sealed class GlobalSession extends MemorySessionImpl {
public GlobalSession() {
super(null, null);
+ this.state = NONCLOSEABLE;
}
@Override
@@ -50,11 +51,6 @@ public void release0() {
// do nothing
}
- @Override
- public boolean isCloseable() {
- return false;
- }
-
@Override
@ForceInline
public void acquire0() {
diff --git a/src/java.base/share/classes/jdk/internal/foreign/ImplicitSession.java b/src/java.base/share/classes/jdk/internal/foreign/ImplicitSession.java
index 0eb3642508c..0b79e45960a 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/ImplicitSession.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/ImplicitSession.java
@@ -42,6 +42,7 @@ final class ImplicitSession extends SharedSession {
public ImplicitSession(Cleaner cleaner) {
super();
+ this.state = NONCLOSEABLE;
cleaner.register(this, resourceList);
}
@@ -55,11 +56,6 @@ public void acquire0() {
// do nothing
}
- @Override
- public boolean isCloseable() {
- return false;
- }
-
@Override
public void justClose() {
throw nonCloseable();
diff --git a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java
index a12b16ca8b4..541a0907e4c 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java
@@ -38,6 +38,7 @@
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.invoke.MhUtil;
import jdk.internal.vm.annotation.ForceInline;
+import jdk.internal.vm.annotation.Stable;
/**
* This class manages the temporal bounds associated with a memory segment as well
@@ -55,11 +56,19 @@
public abstract sealed class MemorySessionImpl
implements Scope
permits ConfinedSession, GlobalSession, SharedSession {
+
+ /**
+ * The value of the {@code state} of a {@code MemorySessionImpl}. The only possible transition
+ * is OPEN -> CLOSED. As a result, the states CLOSED and NONCLOSEABLE are stable. This allows
+ * us to annotate {@code state} with {@link Stable} and elide liveness check on non-closeable
+ * constant scopes, such as {@code GLOBAL_SESSION}.
+ */
static final int OPEN = 0;
static final int CLOSED = -1;
+ static final int NONCLOSEABLE = 1;
- static final VarHandle STATE = MhUtil.findVarHandle(
- MethodHandles.lookup(), "state", int.class);
+ static final VarHandle STATE = MhUtil.findVarHandle(MethodHandles.lookup(), "state", int.class);
+ static final VarHandle ACQUIRE_COUNT = MhUtil.findVarHandle(MethodHandles.lookup(), "acquireCount", int.class);
static final int MAX_FORKS = Integer.MAX_VALUE;
@@ -70,7 +79,11 @@ public abstract sealed class MemorySessionImpl
final ResourceList resourceList;
final Thread owner;
- int state = OPEN;
+
+ @Stable
+ int state;
+
+ int acquireCount;
public Arena asArena() {
return new ArenaImpl(this);
@@ -214,8 +227,8 @@ protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
- public boolean isCloseable() {
- return true;
+ public final boolean isCloseable() {
+ return state <= OPEN;
}
/**
diff --git a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java
index 6c9666c2b58..b4415ad4959 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java
@@ -44,6 +44,8 @@ sealed class SharedSession extends MemorySessionImpl permits ImplicitSession {
private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
+ private static final int CLOSED_ACQUIRE_COUNT = -1;
+
SharedSession() {
super(null, new SharedResourceList());
}
@@ -53,15 +55,15 @@ sealed class SharedSession extends MemorySessionImpl permits ImplicitSession {
public void acquire0() {
int value;
do {
- value = (int) STATE.getVolatile(this);
- if (value < OPEN) {
+ value = (int) ACQUIRE_COUNT.getVolatile(this);
+ if (value < 0) {
//segment is not open!
- throw alreadyClosed();
+ throw sharedSessionAlreadyClosed();
} else if (value == MAX_FORKS) {
//overflow
throw tooManyAcquires();
}
- } while (!STATE.compareAndSet(this, value, value + 1));
+ } while (!ACQUIRE_COUNT.compareAndSet(this, value, value + 1));
}
@Override
@@ -69,24 +71,35 @@ public void acquire0() {
public void release0() {
int value;
do {
- value = (int) STATE.getVolatile(this);
- if (value <= OPEN) {
+ value = (int) ACQUIRE_COUNT.getVolatile(this);
+ if (value <= 0) {
//cannot get here - we can't close segment twice
- throw alreadyClosed();
+ throw sharedSessionAlreadyClosed();
}
- } while (!STATE.compareAndSet(this, value, value - 1));
+ } while (!ACQUIRE_COUNT.compareAndSet(this, value, value - 1));
}
void justClose() {
- int prevState = (int) STATE.compareAndExchange(this, OPEN, CLOSED);
- if (prevState < 0) {
- throw alreadyClosed();
- } else if (prevState != OPEN) {
- throw alreadyAcquired(prevState);
+ int acquireCount = (int) ACQUIRE_COUNT.compareAndExchange(this, 0, CLOSED_ACQUIRE_COUNT);
+ if (acquireCount < 0) {
+ throw sharedSessionAlreadyClosed();
+ } else if (acquireCount > 0) {
+ throw alreadyAcquired(acquireCount);
}
+
+ STATE.setVolatile(this, CLOSED);
SCOPED_MEMORY_ACCESS.closeScope(this, ALREADY_CLOSED);
}
+ private IllegalStateException sharedSessionAlreadyClosed() {
+ // To avoid the situation where a scope fails to be acquired or closed but still reports as
+ // alive afterward, we wait for the state to change before throwing the exception
+ while ((int) STATE.getVolatile(this) == OPEN) {
+ Thread.onSpinWait();
+ }
+ return alreadyClosed();
+ }
+
/**
* A shared resource list; this implementation has to handle add vs. add races, as well as add vs. cleanup races.
*/
diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template
index 82807148224..7d2e73ea915 100644
--- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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,11 +139,13 @@ class UnixConstants {
#endif
// flags used with openat/unlinkat/etc.
-#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_REMOVEDIR)
+#if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) && defined(AT_REMOVEDIR)
+ static final int PREFIX_AT_FDCWD = AT_FDCWD;
static final int PREFIX_AT_SYMLINK_NOFOLLOW = AT_SYMLINK_NOFOLLOW;
static final int PREFIX_AT_REMOVEDIR = AT_REMOVEDIR;
#else
// not supported (dummy values will not be used at runtime).
+ static final int PREFIX_AT_FDCWD = 00;
static final int PREFIX_AT_SYMLINK_NOFOLLOW = 00;
static final int PREFIX_AT_REMOVEDIR = 00;
#endif
diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java
index 94e0f91e812..033deee2f4f 100644
--- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -76,13 +76,16 @@ public void setTimes(FileTime lastModifiedTime,
boolean useFutimes = false;
boolean useFutimens = false;
boolean useLutimes = false;
+ boolean useUtimensat = false;
int fd = -1;
try {
if (!followLinks) {
- useLutimes = lutimesSupported() &&
- UnixFileAttributes.get(file, false).isSymbolicLink();
+ // these path-based syscalls also work if following links
+ if (!(useUtimensat = utimensatSupported())) {
+ useLutimes = lutimesSupported();
+ }
}
- if (!useLutimes) {
+ if (!useUtimensat && !useLutimes) {
fd = file.openForAttributeAccess(followLinks);
if (fd != -1) {
haveFd = true;
@@ -92,8 +95,8 @@ public void setTimes(FileTime lastModifiedTime,
}
}
} catch (UnixException x) {
- if (!(x.errno() == UnixConstants.ENXIO ||
- (x.errno() == UnixConstants.ELOOP && useLutimes))) {
+ if (!(x.errno() == ENXIO ||
+ (x.errno() == ELOOP && (useUtimensat || useLutimes)))) {
x.rethrowAsIOException(file);
}
}
@@ -117,7 +120,7 @@ public void setTimes(FileTime lastModifiedTime,
}
// update times
- TimeUnit timeUnit = useFutimens ?
+ TimeUnit timeUnit = (useFutimens || useUtimensat) ?
TimeUnit.NANOSECONDS : TimeUnit.MICROSECONDS;
long modValue = lastModifiedTime.to(timeUnit);
long accessValue= lastAccessTime.to(timeUnit);
@@ -130,13 +133,16 @@ public void setTimes(FileTime lastModifiedTime,
futimes(fd, accessValue, modValue);
} else if (useLutimes) {
lutimes(file, accessValue, modValue);
+ } else if (useUtimensat) {
+ utimensat(AT_FDCWD, file, accessValue, modValue,
+ followLinks ? 0 : AT_SYMLINK_NOFOLLOW);
} else {
utimes(file, accessValue, modValue);
}
} catch (UnixException x) {
// if futimes/utimes fails with EINVAL and one/both of the times is
// negative then we adjust the value to the epoch and retry.
- if (x.errno() == UnixConstants.EINVAL &&
+ if (x.errno() == EINVAL &&
(modValue < 0L || accessValue < 0L)) {
retry = true;
} else {
@@ -153,6 +159,9 @@ public void setTimes(FileTime lastModifiedTime,
futimes(fd, accessValue, modValue);
} else if (useLutimes) {
lutimes(file, accessValue, modValue);
+ } else if (useUtimensat) {
+ utimensat(AT_FDCWD, file, accessValue, modValue,
+ followLinks ? 0 : AT_SYMLINK_NOFOLLOW);
} else {
utimes(file, accessValue, modValue);
}
diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java
index ab8975c6d12..d6d2b9fdcd7 100644
--- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java
@@ -391,6 +391,20 @@ static void lutimes(UnixPath path, long times0, long times1)
private static native void lutimes0(long pathAddress, long times0, long times1)
throws UnixException;
+ /**
+ * utimensat(int fd, const char* path,
+ * const struct timeval times[2], int flags)
+ */
+ static void utimensat(int fd, UnixPath path, long times0, long times1, int flags)
+ throws UnixException
+ {
+ try (NativeBuffer buffer = copyToNativeBuffer(path)) {
+ utimensat0(fd, buffer.address(), times0, times1, flags);
+ }
+ }
+ private static native void utimensat0(int fd, long pathAddress, long times0, long times1, int flags)
+ throws UnixException;
+
/**
* DIR *opendir(const char* dirname)
*/
@@ -557,7 +571,8 @@ static native int flistxattr(int filedes, long listAddress, int size)
private static final int SUPPORTS_FUTIMES = 1 << 2;
private static final int SUPPORTS_FUTIMENS = 1 << 3;
private static final int SUPPORTS_LUTIMES = 1 << 4;
- private static final int SUPPORTS_XATTR = 1 << 5;
+ private static final int SUPPORTS_UTIMENSAT = 1 << 5;
+ private static final int SUPPORTS_XATTR = 1 << 6;
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
private static final int capabilities;
@@ -589,6 +604,13 @@ static boolean lutimesSupported() {
return (capabilities & SUPPORTS_LUTIMES) != 0;
}
+ /**
+ * Supports utimensat
+ */
+ static boolean utimensatSupported() {
+ return (capabilities & SUPPORTS_UTIMENSAT) != 0;
+ }
+
/**
* Supports file birth (creation) time attribute
*/
diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
index 9a68a12c219..aa46a2470a1 100644
--- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
+++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
@@ -211,6 +211,8 @@ typedef DIR* fdopendir_func(int);
#if defined(__linux__)
typedef int statx_func(int dirfd, const char *restrict pathname, int flags,
unsigned int mask, struct my_statx *restrict statxbuf);
+typedef int utimensat_func(int dirfd, const char *pathname,
+ const struct timespec[2], int flags);
#endif
static openat_func* my_openat_func = NULL;
@@ -223,6 +225,7 @@ static lutimes_func* my_lutimes_func = NULL;
static fdopendir_func* my_fdopendir_func = NULL;
#if defined(__linux__)
static statx_func* my_statx_func = NULL;
+static utimensat_func* my_utimensat_func = NULL;
#endif
/**
@@ -432,6 +435,10 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
if (my_statx_func != NULL) {
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;
}
+ my_utimensat_func = (utimensat_func*) dlsym(RTLD_DEFAULT, "utimensat");
+ if (my_utimensat_func != NULL) {
+ capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_UTIMENSAT;
+ }
#endif
/* supports extended attributes */
@@ -976,6 +983,34 @@ Java_sun_nio_fs_UnixNativeDispatcher_lutimes0(JNIEnv* env, jclass this,
}
}
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_utimensat0(JNIEnv* env, jclass this,
+ jint fd, jlong pathAddress, jlong accessTime, jlong modificationTime, jint flags) {
+#if defined(__linux__)
+ int err;
+ struct timespec times[2];
+ const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+ times[0].tv_sec = accessTime / 1000000000;
+ times[0].tv_nsec = accessTime % 1000000000;
+
+ times[1].tv_sec = modificationTime / 1000000000;
+ times[1].tv_nsec = modificationTime % 1000000000;
+
+ if (my_utimensat_func == NULL) {
+ JNU_ThrowInternalError(env, "my_utimensat_func is NULL");
+ return;
+ }
+ RESTARTABLE((*my_utimensat_func)(fd, path, ×[0], flags), err);
+
+ if (err == -1) {
+ throwUnixException(env, errno);
+ }
+#else
+ JNU_ThrowInternalError(env, "should not reach here");
+#endif
+}
+
JNIEXPORT jlong JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,
jlong pathAddress)
diff --git a/src/java.management/share/classes/com/sun/jmx/mbeanserver/MBeanServerDelegateImpl.java b/src/java.management/share/classes/com/sun/jmx/mbeanserver/MBeanServerDelegateImpl.java
index c4837c8ea89..f5925a25d35 100644
--- a/src/java.management/share/classes/com/sun/jmx/mbeanserver/MBeanServerDelegateImpl.java
+++ b/src/java.management/share/classes/com/sun/jmx/mbeanserver/MBeanServerDelegateImpl.java
@@ -100,7 +100,7 @@ public MBeanServerDelegateImpl () {
super();
delegateInfo =
new MBeanInfo("javax.management.MBeanServerDelegate",
- "Represents the MBean server from the management "+
+ "Represents the MBean server from the management "+
"point of view.",
MBeanServerDelegateImpl.attributeInfos, null,
null,getNotificationInfo());
diff --git a/src/java.management/share/classes/javax/management/MBeanServerDelegate.java b/src/java.management/share/classes/javax/management/MBeanServerDelegate.java
index 443e9a7a06c..6e089f4164d 100644
--- a/src/java.management/share/classes/javax/management/MBeanServerDelegate.java
+++ b/src/java.management/share/classes/javax/management/MBeanServerDelegate.java
@@ -31,7 +31,7 @@
import com.sun.jmx.mbeanserver.Util;
/**
- * Represents the MBean server from the management point of view.
+ * Represents the MBean server from the management point of view.
* The MBeanServerDelegate MBean emits the MBeanServerNotifications when
* an MBean is registered/unregistered in the MBean server.
*
diff --git a/src/java.management/share/classes/javax/management/Notification.java b/src/java.management/share/classes/javax/management/Notification.java
index 80cf4b464d2..337628aeec8 100644
--- a/src/java.management/share/classes/javax/management/Notification.java
+++ b/src/java.management/share/classes/javax/management/Notification.java
@@ -59,7 +59,7 @@ public class Notification extends EventObject {
/**
* @serialField type String The notification type.
* A string expressed in a dot notation similar to Java properties.
- * An example of a notification type is network.alarm.router
+ * An example of a notification type is com.sun.management.gc.notification
* @serialField sequenceNumber long The notification sequence number.
* A serial number which identify particular instance
* of notification in the context of the notification source.
@@ -83,7 +83,7 @@ public class Notification extends EventObject {
/**
* @serial The notification type.
* A string expressed in a dot notation similar to Java properties.
- * An example of a notification type is network.alarm.router
+ * An example of a notification type is com.sun.management.gc.notification
*/
private String type;
@@ -239,7 +239,7 @@ public void setSequenceNumber(long sequenceNumber) {
* @return The notification type. It's a string expressed in a dot notation
* similar to Java properties. It is recommended that the notification type
* should follow the reverse-domain-name convention used by Java package
- * names. An example of a notification type is com.example.alarm.router.
+ * names. An example of a notification type is com.sun.management.gc.notification
*/
public String getType() {
return type ;
diff --git a/src/java.management/share/classes/javax/management/remote/JMXConnectionNotification.java b/src/java.management/share/classes/javax/management/remote/JMXConnectionNotification.java
index 0ba100ec8b2..b7bb5a3dc8c 100644
--- a/src/java.management/share/classes/javax/management/remote/JMXConnectionNotification.java
+++ b/src/java.management/share/classes/javax/management/remote/JMXConnectionNotification.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -159,12 +159,7 @@ public JMXConnectionNotification(String type,
long sequenceNumber,
String message,
Object userData) {
- /* We don't know whether the parent class (Notification) will
- throw an exception if the type or source is null, because
- JMX 1.2 doesn't specify that. So we make sure it is not
- null, in case it would throw the wrong exception
- (e.g. IllegalArgumentException instead of
- NullPointerException). Likewise for the sequence number. */
+ // Do not pass null source to super, as EventObject will throw IllegalArgumentException.
super((String) nonNull(type),
nonNull(source),
Math.max(0, sequenceNumber),
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java
index 7e8b96d5856..c7e71f74d8a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java
@@ -103,6 +103,7 @@ public class ClassFile {
public static final int MAX_STACK = 0xffff;
public static final int PREVIEW_MINOR_VERSION = 0xffff;
+ public static final int MAX_ANNOTATIONS = 0xffff;
public enum Version {
V45_3(45, 3), // base level for all attributes
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
index 6679bb43fb8..d70032353b6 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
@@ -649,11 +649,19 @@ void writeCompoundAttribute(Attribute.Compound c) {
databuf.appendChar(poolWriter.putDescriptor(c.type));
databuf.appendChar(c.values.length());
for (Pair p : c.values) {
+ checkAnnotationArraySizeInternal(p);
databuf.appendChar(poolWriter.putName(p.fst.name));
p.snd.accept(awriter);
}
}
+ private void checkAnnotationArraySizeInternal(Pair p) {
+ if (p.snd instanceof Attribute.Array arrAttr &&
+ arrAttr.values.length > ClassFile.MAX_ANNOTATIONS) {
+ log.error(Errors.AnnotationArrayTooLarge(p.fst.owner));
+ }
+ }
+
void writeTypeAnnotation(Attribute.TypeCompound c) {
writePosition(c.position);
writeCompoundAttribute(c);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
index a991ae60601..a24dd2f95bd 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -887,6 +887,10 @@ compiler.err.limit.stack=\
compiler.err.limit.string=\
constant string too long
+# 0: symbol
+compiler.err.annotation.array.too.large=\
+ Annotation array element too large in \"{0}\"
+
# 0: string
compiler.err.limit.string.overflow=\
UTF8 representation for string \"{0}...\" is too long for the constant pool
@@ -2235,6 +2239,7 @@ compiler.warn.proc.duplicate.option.name=\
compiler.warn.proc.duplicate.supported.annotation=\
Duplicate supported annotation interface ''{0}'' returned by annotation processor ''{1}''
+
# 0: string
compiler.warn.proc.redundant.types.with.wildcard=\
Annotation processor ''{0}'' redundantly supports both ''*'' and other annotation interfaces
diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups
index 2a08266d79f..575c0caa674 100644
--- a/test/hotspot/jtreg/TEST.groups
+++ b/test/hotspot/jtreg/TEST.groups
@@ -444,6 +444,7 @@ hotspot_appcds_dynamic = \
-runtime/cds/appcds/jcmd/JCmdTestStaticDump.java \
-runtime/cds/appcds/jcmd/JCmdTestDynamicDump.java \
-runtime/cds/appcds/jcmd/JCmdTestFileSafety.java \
+ -runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClass.java \
-runtime/cds/appcds/lambdaForm/DefaultClassListLFInvokers.java \
-runtime/cds/appcds/methodHandles \
-runtime/cds/appcds/sharedStrings \
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/BootChild.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/BootChild.java
new file mode 100644
index 00000000000..08e15fea1a5
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/BootChild.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class BootChild extends BootSuper {
+ // Does not override BootSuper::doit()
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/BootSuper.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/BootSuper.java
new file mode 100644
index 00000000000..d1682ebf390
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/BootSuper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class BootSuper {
+ public String doit() {
+ return "Hello";
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/NewChild.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/NewChild.java
new file mode 100644
index 00000000000..b11eb9717f1
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/NewChild.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class NewChild extends OldSuper {
+ // Does not override BootSuper::doit()
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClass.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClass.java
new file mode 100644
index 00000000000..242a78ca024
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClass.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8342303
+ * @summary Test loading of shared old class when another class has been redefined.
+ * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes /test/hotspot/jtreg/runtime/cds/appcds/jvmti
+ * @requires vm.cds.write.archived.java.heap
+ * @requires vm.jvmti
+ * @build jdk.test.whitebox.WhiteBox
+ * OldClassAndRedefineClassApp
+ * @compile ../../test-classes/OldSuper.jasm
+ * ../../test-classes/ChildOldSuper.java
+ * ../../test-classes/Hello.java
+ * @run driver RedefineClassHelper
+ * @run driver OldClassAndRedefineClass
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.helpers.ClassFileInstaller;
+
+public class OldClassAndRedefineClass {
+ public static String appClasses[] = {
+ "OldClassAndRedefineClassApp",
+ "OldSuper",
+ "ChildOldSuper",
+ "Hello",
+ };
+ public static String sharedClasses[] = TestCommon.concat(appClasses);
+
+ public static void main(String[] args) throws Throwable {
+ runTest();
+ }
+
+ public static void runTest() throws Throwable {
+ String appJar =
+ ClassFileInstaller.writeJar("OldClassAndRedefineClassApp.jar", appClasses);
+
+ String agentCmdArg = "-javaagent:redefineagent.jar";
+
+ OutputAnalyzer out = TestCommon.testDump(appJar, sharedClasses, "-Xlog:cds,cds+class=debug");
+ out.shouldMatch("klasses.*OldSuper.[*][*].unlinked")
+ .shouldMatch("klasses.*ChildOldSuper.[*][*].unlinked");
+
+ out = TestCommon.exec(
+ appJar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+AllowArchivingWithJavaAgent",
+ "-XX:+WhiteBoxAPI",
+ "-Xlog:cds,class+load",
+ agentCmdArg,
+ "OldClassAndRedefineClassApp");
+ out.shouldContain("[class,load] OldSuper source: shared objects file")
+ .shouldContain("[class,load] ChildOldSuper source: shared objects file")
+ .shouldContain("[class,load] Hello source: __VM_RedefineClasses__");
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClassApp.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClassApp.java
new file mode 100644
index 00000000000..2c460ccb027
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClassApp.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class OldClassAndRedefineClassApp {
+
+ public static void main(String args[]) throws Throwable {
+ ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
+
+ System.out.println("Main: loading OldSuper");
+ // Load an old class (version 49), but not linking it.
+ Class.forName("OldSuper", false, appClassLoader);
+
+ // Redefine a class unrelated to the above old class.
+ System.out.println("INFO: instrumentation = " + RedefineClassHelper.instrumentation);
+ Class> c = Class.forName("Hello", false, appClassLoader);
+ byte[] bytes = c.getClassLoader().getResourceAsStream(c.getName().replace('.', '/') + ".class").readAllBytes();
+ RedefineClassHelper.redefineClass(c, bytes);
+
+ System.out.println("Main: loading ChildOldSuper");
+ // Load and link a subclass of the above old class.
+ // This will in turn link the old class and initializes its vtable, etc.
+ Class.forName("ChildOldSuper");
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineBootClassApp.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineBootClassApp.java
new file mode 100644
index 00000000000..92642c467d2
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineBootClassApp.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+
+public class RedefineBootClassApp {
+ public static void main(String args[]) throws Throwable {
+ File bootJar = new File(args[0]);
+
+ Class> superCls = Class.forName("BootSuper", false, null);
+ System.out.println("BootSuper>> loader = " + superCls.getClassLoader());
+
+ {
+ BootSuper obj = (BootSuper)superCls.newInstance();
+ System.out.println("(before transform) BootSuper>> doit() = " + obj.doit());
+ }
+
+ // Redefine the class
+ byte[] bytes = Util.getClassFileFromJar(bootJar, "BootSuper");
+ Util.replace(bytes, "Hello", "HELLO");
+ RedefineClassHelper.redefineClass(superCls, bytes);
+
+ {
+ BootSuper obj = (BootSuper)superCls.newInstance();
+ String s = obj.doit();
+ System.out.println("(after transform) BootSuper>> doit() = " + s);
+ if (!s.equals("HELLO")) {
+ throw new RuntimeException("BootSuper doit() should be HELLO but got " + s);
+ }
+ }
+
+ Class> childCls = Class.forName("BootChild", false, null);
+ System.out.println("BootChild>> loader = " + childCls.getClassLoader());
+
+
+ {
+ BootSuper obj = (BootSuper)childCls.newInstance();
+ String s = obj.doit();
+ System.out.println("(after transform) BootChild>> doit() = " + s);
+ if (!s.equals("HELLO")) {
+ throw new RuntimeException("BootChild doit() should be HELLO but got " + s);
+ }
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineBootClassTest.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineBootClassTest.java
new file mode 100644
index 00000000000..bc14ec996f5
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineBootClassTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8342303
+ * @summary Redefine a shared super class loaded by the boot loader. The vtable of its archived child class must be updated
+ * @library /test/lib
+ * /test/hotspot/jtreg/runtime/cds/appcds
+ * /test/hotspot/jtreg/runtime/cds/appcds/test-classes
+ * /test/hotspot/jtreg/runtime/cds/appcds/jvmti
+ * @requires vm.jvmti
+ * @build RedefineBootClassTest
+ * RedefineBootClassApp
+ * BootSuper BootChild
+ * @run driver RedefineClassHelper
+ * @run driver RedefineBootClassTest
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.helpers.ClassFileInstaller;
+
+public class RedefineBootClassTest {
+ public static String bootClasses[] = {
+ "BootSuper",
+ "BootChild",
+ };
+ public static String appClasses[] = {
+ "RedefineBootClassApp",
+ "Util",
+ };
+ public static String sharedClasses[] = TestCommon.concat(bootClasses, appClasses);
+
+ public static void main(String[] args) throws Throwable {
+ runTest();
+ }
+
+ public static void runTest() throws Throwable {
+ String bootJar =
+ ClassFileInstaller.writeJar("RedefineClassBoot.jar", bootClasses);
+ String appJar =
+ ClassFileInstaller.writeJar("RedefineClassApp.jar", appClasses);
+
+ String bootCP = "-Xbootclasspath/a:" + bootJar;
+ String agentCmdArg = "-javaagent:redefineagent.jar";
+
+ TestCommon.testDump(appJar, sharedClasses, bootCP, "-Xlog:cds,cds+class=debug");
+
+ OutputAnalyzer out = TestCommon.execAuto("-cp", appJar,
+ bootCP,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-Xlog:cds=info,class+load",
+ agentCmdArg,
+ "RedefineBootClassApp", bootJar);
+ out.reportDiagnosticSummary();
+ TestCommon.checkExec(out);
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineOldSuperApp.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineOldSuperApp.java
new file mode 100644
index 00000000000..c60edfd2891
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineOldSuperApp.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+
+public class RedefineOldSuperApp {
+ public static void main(String args[]) throws Throwable {
+ File bootJar = new File(args[0]);
+ ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
+
+ Class> superCls = Class.forName("OldSuper", false, appClassLoader);
+ System.out.println("OldSuper>> loader = " + superCls.getClassLoader());
+
+ {
+ OldSuper obj = (OldSuper)superCls.newInstance();
+ System.out.println("(before transform) OldSuper>> doit() = " + obj.doit());
+ }
+
+ // Redefine the class
+ byte[] bytes = Util.getClassFileFromJar(bootJar, "OldSuper");
+ Util.replace(bytes, "Hello", "HELLO");
+ RedefineClassHelper.redefineClass(superCls, bytes);
+
+ {
+ OldSuper obj = (OldSuper)superCls.newInstance();
+ String s = obj.doit();
+ System.out.println("(after transform) OldSuper>> doit() = " + s);
+ if (!s.equals("HELLO")) {
+ throw new RuntimeException("OldSuper doit() should be HELLO but got " + s);
+ }
+ }
+
+ Class> childCls = Class.forName("NewChild", false, appClassLoader);
+ System.out.println("NewChild>> loader = " + childCls.getClassLoader());
+
+
+ {
+ OldSuper obj = (OldSuper)childCls.newInstance();
+ String s = obj.doit();
+ System.out.println("(after transform) NewChild>> doit() = " + s);
+ if (!s.equals("HELLO")) {
+ throw new RuntimeException("NewChild doit() should be HELLO but got " + s);
+ }
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineOldSuperTest.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineOldSuperTest.java
new file mode 100644
index 00000000000..a0c8fa7a448
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/redefineClasses/RedefineOldSuperTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8342303
+ * @summary Redefine a shared old super class loaded by the app loader. The vtable of its archived child class must be updated
+ * @library /test/lib
+ * /test/hotspot/jtreg/runtime/cds/appcds
+ * /test/hotspot/jtreg/runtime/cds/appcds/test-classes
+ * /test/hotspot/jtreg/runtime/cds/appcds/jvmti
+ * @requires vm.jvmti
+ * @compile ../../test-classes/OldSuper.jasm
+ * @build RedefineOldSuperTest
+ * RedefineOldSuperApp
+ * NewChild
+ * @run driver RedefineClassHelper
+ * @run driver RedefineOldSuperTest
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.helpers.ClassFileInstaller;
+
+public class RedefineOldSuperTest {
+ public static String appClasses[] = {
+ "OldSuper",
+ "NewChild",
+ "RedefineOldSuperApp",
+ "Util",
+ };
+ public static String sharedClasses[] = TestCommon.concat(appClasses);
+
+ public static void main(String[] args) throws Throwable {
+ runTest();
+ }
+
+ public static void runTest() throws Throwable {
+ String appJar =
+ ClassFileInstaller.writeJar("RedefineClassApp.jar", appClasses);
+
+ String agentCmdArg = "-javaagent:redefineagent.jar";
+
+ TestCommon.testDump(appJar, sharedClasses, "-Xlog:cds,cds+class=debug");
+
+ OutputAnalyzer out = TestCommon.execAuto("-cp", appJar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-Xlog:cds=info,class+load",
+ agentCmdArg,
+ "RedefineOldSuperApp", appJar);
+ out.reportDiagnosticSummary();
+ TestCommon.checkExec(out);
+ }
+}
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java
index acbd0c948be..fbdec462e09 100644
--- a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java
+++ b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineBasicTest.java
@@ -30,7 +30,7 @@
* @requires vm.jvmti
* @library /test/lib /test/hotspot/jtreg/serviceability/jvmti/RedefineClasses /test/hotspot/jtreg/runtime/cds/appcds
* @run driver RedefineClassHelper
- * @build jdk.test.whitebox.WhiteBox RedefineBasic
+ * @build jdk.test.whitebox.WhiteBox jdk.test.lib.compiler.InMemoryJavaCompiler RedefineBasic
* @run driver RedefineBasicTest
*/
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java
index 039aaef11cd..62bd62662a0 100644
--- a/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java
+++ b/test/hotspot/jtreg/runtime/cds/appcds/redefineClass/RedefineRunningMethods_Shared.java
@@ -30,7 +30,7 @@
* @requires vm.jvmti
* @library /test/lib /test/hotspot/jtreg/serviceability/jvmti/RedefineClasses /test/hotspot/jtreg/runtime/cds/appcds
* @run driver RedefineClassHelper
- * @build jdk.test.whitebox.WhiteBox
+ * @build jdk.test.whitebox.WhiteBox jdk.test.lib.compiler.InMemoryJavaCompiler
* @compile RedefineRunningMethods_SharedHelper.java
* @run driver RedefineRunningMethods_Shared
*/
diff --git a/test/hotspot/jtreg/runtime/logging/RedefineClasses.java b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java
index 34c8900e616..714c05174eb 100644
--- a/test/hotspot/jtreg/runtime/logging/RedefineClasses.java
+++ b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java
@@ -30,6 +30,7 @@
* @modules java.compiler
* java.instrument
* @requires vm.jvmti
+ * @build jdk.test.lib.compiler.InMemoryJavaCompiler
* @run main RedefineClassHelper
* @run main/othervm -Xmx256m -XX:MaxMetaspaceSize=64m -javaagent:redefineagent.jar -Xlog:all=trace:file=all.log RedefineClasses
*/
diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
index ea74cd40fb8..5f78fc06abd 100644
--- a/test/jdk/ProblemList.txt
+++ b/test/jdk/ProblemList.txt
@@ -518,6 +518,8 @@ java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic-
java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all
java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-all
java/lang/invoke/RicochetTest.java 8251969 generic-all
+java/lang/Thread/jni/AttachCurrentThread/AttachTest.java#id0 8343244 generic-all
+java/lang/Thread/jni/AttachCurrentThread/AttachTest.java#id1 8343244 generic-all
############################################################################
@@ -804,6 +806,7 @@ java/awt/image/VolatileImage/VolatileImageConfigurationTest.java 8171069 macosx-
java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all
java/awt/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all
java/awt/print/PrinterJob/ScaledText/ScaledText.java 8231226 macosx-all
+java/awt/print/PrinterJob/PrintTextTest.java 8148334 generic-all
java/awt/font/TextLayout/TestJustification.java 8250791 macosx-all
java/awt/TrayIcon/DragEventSource/DragEventSource.java 8252242 macosx-all
java/awt/FileDialog/DefaultFocusOwner/DefaultFocusOwner.java 7187728 macosx-all,linux-all
diff --git a/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java b/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java
index 0088fe54a80..fd33337a3c0 100644
--- a/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java
+++ b/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java
@@ -69,6 +69,8 @@ public class HKDFExhaustiveTest {
private static final int LARGE_LENGTH = 1000;
private static final int NEGATIVE_LENGTH = -1;
+ static class TestKDFParams implements KDFParameters {}
+
private static final KdfVerifier KdfGetInstanceVerifier =
(a, p, s) -> {
@@ -304,6 +306,12 @@ private static void testGetInstanceNegative() {
Utils.runAndCheckException(
() -> KDF.getInstance(KDF_ALGORITHMS[0], null, INVALID_STRING),
NoSuchProviderException.class);
+ Utils.runAndCheckException(
+ () -> KDF.getInstance(KDF_ALGORITHMS[0], new TestKDFParams(), SUNJCE),
+ InvalidAlgorithmParameterException.class);
+ Utils.runAndCheckException(
+ () -> KDF.getInstance(KDF_ALGORITHMS[0], new TestKDFParams(), SUNJCE_PROVIDER),
+ InvalidAlgorithmParameterException.class);
// getInstance(String algorithm, KDFParameters kdfParameters, Provider provider)
Utils.runAndCheckException(
diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java
index 95bf177aa2f..f2ec4e15a8a 100644
--- a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java
+++ b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2012, 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
@@ -21,193 +21,207 @@
* questions.
*/
-/**
+/*
* @test
* @bug 6425068 7157659 8132890
* @key printer
* @summary Confirm that text prints where we expect to the length we expect.
- * @run main/manual=yesno PrintTextTest
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual PrintTextTest
*/
-import java.awt.*;
-import java.awt.event.*;
-import java.text.*;
-import java.util.*;
-import java.awt.font.*;
-import java.awt.geom.*;
-import java.awt.print.*;
-import javax.swing.*;
-
-public class PrintTextTest extends Component implements Printable {
-
- static int preferredSize;
- Font textFont;
- AffineTransform gxTx;
- String page;
- boolean useFM;
-
- public static void main(String args[]) {
- String[] instructions =
- {
- "This tests that printed text renders similarly to on-screen",
- "under a variety of APIs and graphics and font transforms",
- "Print to your preferred printer. Collect the output.",
- "Refer to the onscreen buttons to cycle through the on-screen",
- "content",
- "For each page, confirm that the printed content corresponds to",
- "the on-screen rendering for that *same* page.",
- "Some cases may look odd but its intentional. Verify",
- "it looks the same on screen and on the printer.",
- "Note that text does not scale linearly from screen to printer",
- "so some differences are normal and not a bug.",
- "The easiest way to spot real problems is to check that",
- "any underlines are the same length as the underlined text",
- "and that any rotations are the same in each case.",
- "Note that each on-screen page is printed in both portrait",
- "and landscape mode",
- "So for example, Page 1/Portrait, and Page 1/Landscape when",
- "rotated to view properly, should both match Page 1 on screen.",
- };
- Sysout.createDialogWithInstructions(instructions);
-
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.RenderingHints;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.print.Book;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.util.HashMap;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JTabbedPane;
+
+public class PrintTextTest {
+
+ static final String INSTRUCTIONS = """
+ This tests that printed text renders similarly to on-screen under a variety
+ of APIs and graphics and font transforms.
+ 1. Print to your preferred printer.
+ 2. Collect the output.
+ 3. Refer to the onscreen buttons to cycle through the on-screen content.
+ 4. For each page, confirm that the printed content corresponds to the
+ on-screen rendering for that *same* page. Some cases may look odd but
+ its intentional. Verify it looks the same on screen and on the printer.
+ Note that text does not scale linearly from screen to printer so some
+ differences are normal and not a bug.
+ The easiest way to spot real problems is to check that any underlines are
+ the same length as the underlined text and that any rotations are the same
+ in each case.
+ Note that each on-screen page is printed in both portrait and landscape mode.
+ So for example, Page 1/Portrait, and Page 1/Landscape when rotated to view
+ properly, should both match Page 1 on screen.
+ """;
+
+ public static void main(String[] args) throws Exception {
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat portrait = pjob.defaultPage();
portrait.setOrientation(PageFormat.PORTRAIT);
- preferredSize = (int)portrait.getImageableWidth();
+ int preferredSize = (int) portrait.getImageableWidth();
PageFormat landscape = pjob.defaultPage();
landscape.setOrientation(PageFormat.LANDSCAPE);
Book book = new Book();
- JTabbedPane p = new JTabbedPane();
+ JTabbedPane pane = new JTabbedPane();
int page = 1;
- Font font = new Font("Dialog", Font.PLAIN, 18);
- String name = "Page " + new Integer(page++);
- PrintTextTest ptt = new PrintTextTest(name, font, null, false);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
-
- font = new Font("Dialog", Font.PLAIN, 18);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, null, true);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ Font font = new Font(Font.DIALOG, Font.PLAIN, 18);
+ String name = "Page " + page++;
+ PrintText pt = new PrintText(name, font, null, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
+
+ font = new Font(Font.DIALOG, Font.PLAIN, 18);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, null, true, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
font = getPhysicalFont();
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, null, false);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, null, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
font = getPhysicalFont();
AffineTransform rotTx = AffineTransform.getRotateInstance(0.15);
- rotTx.translate(60,0);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, rotTx, false);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
-
- font = new Font("Dialog", Font.PLAIN, 18);
+ rotTx.translate(60, 0);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, rotTx, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
+
+ font = new Font(Font.DIALOG, Font.PLAIN, 18);
AffineTransform scaleTx = AffineTransform.getScaleInstance(1.25, 1.25);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, scaleTx, false);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, scaleTx, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
- font = new Font("Dialog", Font.PLAIN, 18);
+ font = new Font(Font.DIALOG, Font.PLAIN, 18);
scaleTx = AffineTransform.getScaleInstance(-1.25, 1.25);
- scaleTx.translate(-preferredSize/1.25, 0);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, scaleTx, false);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
-
- font = new Font("Dialog", Font.PLAIN, 18);
+ scaleTx.translate(-preferredSize / 1.25, 0);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, scaleTx, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
+
+ font = new Font(Font.DIALOG, Font.PLAIN, 18);
scaleTx = AffineTransform.getScaleInstance(1.25, -1.25);
- scaleTx.translate(0, -preferredSize/1.25);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, scaleTx, false);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ scaleTx.translate(0, -preferredSize / 1.25);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, scaleTx, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
font = font.deriveFont(rotTx);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, null, false);
- p.add(ptt, BorderLayout.CENTER);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
-
- font = new Font("Monospaced", Font.PLAIN, 12);
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, font, null, false);
- p.add(ptt, BorderLayout.CENTER);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, null, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
+
+ font = new Font(Font.MONOSPACED, Font.PLAIN, 12);
+ name = "Page " + page++;
+ pt = new PrintText(name, font, null, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
Font xfont = font.deriveFont(AffineTransform.getScaleInstance(1.5, 1));
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, xfont, null, false);
- p.add(ptt, BorderLayout.CENTER);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ name = "Page " + page++;
+ pt = new PrintText(name, xfont, null, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
Font yfont = font.deriveFont(AffineTransform.getScaleInstance(1, 1.5));
- name = "Page " + new Integer(page++);
- ptt = new PrintTextTest(name, yfont, null, false);
- p.add(ptt, BorderLayout.CENTER);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ name = "Page " + page++;
+ pt = new PrintText(name, yfont, null, false, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
if (System.getProperty("os.name").startsWith("Windows")) {
font = new Font("MS Gothic", Font.PLAIN, 12);
- name = "Page " + new Integer(page++);
- ptt = new PrintJAText(name, font, null, true);
- p.add(ptt, BorderLayout.CENTER);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ name = "Page " + page++;
+ pt = new PrintJapaneseText(name, font, null, true, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
font = new Font("MS Gothic", Font.PLAIN, 12);
- name = "Page " + new Integer(page++);
+ name = "Page " + page++;
rotTx = AffineTransform.getRotateInstance(0.15);
- ptt = new PrintJAText(name, font, rotTx, true);
- p.add(ptt, BorderLayout.CENTER);
- p.add(name, ptt);
- book.append(ptt, portrait);
- book.append(ptt, landscape);
+ pt = new PrintJapaneseText(name, font, rotTx, true, preferredSize);
+ pane.addTab(name, pt);
+ book.append(pt, portrait);
+ book.append(pt, landscape);
}
pjob.setPageable(book);
- JFrame f = new JFrame();
- f.add(BorderLayout.CENTER, p);
- f.addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {System.exit(0);}
+ JButton printButton = new JButton("Print");
+ printButton.addActionListener(event -> {
+ try {
+ if (pjob.printDialog()) {
+ pjob.print();
+ }
+ } catch (PrinterException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
});
+
+ JFrame f = new JFrame("PrintTextTest");
+ f.add(BorderLayout.CENTER, pane);
+ f.add(BorderLayout.SOUTH, printButton);
f.pack();
- f.show();
- try {
- if (pjob.printDialog()) {
- pjob.print();
- }
- } catch (PrinterException e) {
- throw new RuntimeException(e.getMessage());
- }
+ PassFailJFrame.builder()
+ .title("PrintTextTest")
+ .instructions(INSTRUCTIONS)
+ .testTimeOut(10)
+ .columns(60)
+ .testUI(f)
+ .build()
+ .awaitAndCheck();
}
// The test needs a physical font that supports Latin.
@@ -221,338 +235,228 @@ private static Font getPhysicalFont() {
String[] names = ge.getAvailableFontFamilyNames();
for (String n : names) {
- switch (n.toLowerCase()) {
- case "dialog":
- case "dialoginput":
- case "serif":
- case "sansserif":
- case "monospaced":
- break;
+ switch (n) {
+ case Font.DIALOG:
+ case Font.DIALOG_INPUT:
+ case Font.SERIF:
+ case Font.SANS_SERIF:
+ case Font.MONOSPACED:
+ continue;
default:
Font f = new Font(n, Font.PLAIN, 18);
if (f.canDisplayUpTo("AZaz09") == -1) {
physicalFont = f;
return f;
}
- }
+ }
}
physicalFont = new Font(Font.DIALOG, Font.PLAIN, 18);
return physicalFont;
}
- public PrintTextTest(String page, Font font, AffineTransform gxTx,
- boolean fm) {
- this.page = page;
- textFont = font;
- this.gxTx = gxTx;
- this.useFM = fm;
- setBackground(Color.white);
- }
-
- public static AttributedCharacterIterator getIterator(String s) {
- return new AttributedString(s).getIterator();
- }
-
- static String orient(PageFormat pf) {
- if (pf.getOrientation() == PageFormat.PORTRAIT) {
- return "Portrait";
- } else {
- return "Landscape";
+ private static class PrintText extends Component implements Printable {
+
+ protected final Font textFont;
+ protected final AffineTransform gxTx;
+ protected final String page;
+ protected final boolean useFM;
+ protected final int preferredSize;
+
+ public PrintText(String page, Font font, AffineTransform gxTx, boolean fm, int size) {
+ this.page = page;
+ this.textFont = font;
+ this.gxTx = gxTx;
+ this.useFM = fm;
+ this.preferredSize = size;
+ setBackground(Color.WHITE);
}
- }
- public int print(Graphics g, PageFormat pf, int pageIndex) {
-
- Graphics2D g2d = (Graphics2D)g;
- g2d.translate(pf.getImageableX(), pf.getImageableY());
- g.drawString(page+" "+orient(pf),50,20);
- g.translate(0, 25);
- paint(g);
- return PAGE_EXISTS;
- }
-
- public Dimension getMinimumSize() {
- return getPreferredSize();
- }
-
- public Dimension getPreferredSize() {
- return new Dimension(preferredSize, preferredSize);
- }
-
- public void paint(Graphics g) {
-
- /* fill with white before any transformation is applied */
- g.setColor(Color.white);
- g.fillRect(0, 0, getSize().width, getSize().height);
-
-
- Graphics2D g2d = (Graphics2D) g;
- if (gxTx != null) {
- g2d.transform(gxTx);
+ private static AttributedCharacterIterator getIterator(String s) {
+ return new AttributedString(s).getIterator();
}
- if (useFM) {
- g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
- RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- }
-
- g.setFont(textFont);
- FontMetrics fm = g.getFontMetrics();
- String s;
- int LS = 30;
- int ix=10, iy=LS+10;
- g.setColor(Color.black);
-
- s = "drawString(String str, int x, int y)";
- g.drawString(s, ix, iy);
- if (!textFont.isTransformed()) {
- g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
+ private static String orient(PageFormat pf) {
+ if (pf.getOrientation() == PageFormat.PORTRAIT) {
+ return "Portrait";
+ } else {
+ return "Landscape";
+ }
}
- iy += LS;
- s = "drawString(AttributedCharacterIterator iterator, int x, int y)";
- g.drawString(getIterator(s), ix, iy);
-
- iy += LS;
- s = "\tdrawChars(\t\r\nchar[], int off, int len, int x, int y\t)";
- g.drawChars(s.toCharArray(), 0, s.length(), ix, iy);
- if (!textFont.isTransformed()) {
- g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
+ @Override
+ public int print(Graphics g, PageFormat pf, int pageIndex) {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.translate(pf.getImageableX(), pf.getImageableY());
+ g.drawString(page + " " + orient(pf), 50, 20);
+ g.translate(0, 25);
+ paint(g);
+ return PAGE_EXISTS;
}
- iy += LS;
- s = "drawBytes(byte[], int off, int len, int x, int y)";
- byte data[] = new byte[s.length()];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) s.charAt(i);
+ @Override
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
}
- g.drawBytes(data, 0, data.length, ix, iy);
- Font f = g2d.getFont();
- FontRenderContext frc = g2d.getFontRenderContext();
-
- iy += LS;
- s = "drawString(String s, float x, float y)";
- g2d.drawString(s, (float) ix, (float) iy);
- if (!textFont.isTransformed()) {
- g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
+ @Override
+ public Dimension getPreferredSize() {
+ return new Dimension(preferredSize, preferredSize);
}
- iy += LS;
- s = "drawString(AttributedCharacterIterator iterator, "+
- "float x, float y)";
- g2d.drawString(getIterator(s), (float) ix, (float) iy);
-
- iy += LS;
- s = "drawGlyphVector(GlyphVector g, float x, float y)";
- GlyphVector gv = f.createGlyphVector(frc, s);
- g2d.drawGlyphVector(gv, ix, iy);
- Point2D adv = gv.getGlyphPosition(gv.getNumGlyphs());
- if (!textFont.isTransformed()) {
- g.drawLine(ix, iy+1, ix+(int)adv.getX(), iy+1);
- }
+ @Override
+ public void paint(Graphics g) {
- iy += LS;
- s = "GlyphVector with position adjustments";
-
- gv = f.createGlyphVector(frc, s);
- int ng = gv.getNumGlyphs();
- adv = gv.getGlyphPosition(ng);
- for (int i=0; i(), frc);
+ tl.draw(g2d, ix, iy);
- String text = TEXT + TEXT + TEXT;
- g.setColor(Color.black);
- int y = 20;
- float origSize = 7f;
- for (int i=0;i<11;i++) {
- float size = origSize+(i*0.1f);
- g2d.translate(0, size+6);
- Font f = textFont.deriveFont(size);
- g2d.setFont(f);
- FontMetrics fontMetrics = g2d.getFontMetrics();
- int stringWidth = fontMetrics.stringWidth(text);
- g.drawLine(0, y+1, stringWidth, y+1);
- g.drawString(text, 0, y);
- y +=10;
+ iy += LS;
+ s = "TextLayout 2: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End.";
+ tl = new TextLayout(s, f, frc);
+ tl.draw(g2d, ix, iy);
}
}
-}
-
-class Sysout
- {
- private static TestDialog dialog;
- public static void createDialogWithInstructions( String[] instructions )
- {
- dialog = new TestDialog( new Frame(), "Instructions" );
- dialog.printInstructions( instructions );
- dialog.show();
- println( "Any messages for the tester will display here." );
- }
+ private static class PrintJapaneseText extends PrintText {
- public static void createDialog( )
- {
- dialog = new TestDialog( new Frame(), "Instructions" );
- String[] defInstr = { "Instructions will appear here. ", "" } ;
- dialog.printInstructions( defInstr );
- dialog.show();
- println( "Any messages for the tester will display here." );
- }
+ public PrintJapaneseText(String page, Font font, AffineTransform gxTx, boolean fm, int size) {
+ super(page, font, gxTx, fm, size);
+ }
+ private static final String TEXT =
+ "\u3042\u3044\u3046\u3048\u304a\u30a4\u30ed\u30cf" +
+ "\u30cb\u30db\u30d8\u30c8\u4e00\u4e01\u4e02\u4e05\uff08";
- public static void printInstructions( String[] instructions )
- {
- dialog.printInstructions( instructions );
- }
+ @Override
+ public void paint(Graphics g) {
+ g.setColor(Color.WHITE);
+ g.fillRect(0, 0, getSize().width, getSize().height);
- public static void println( String messageIn )
- {
- dialog.displayMessage( messageIn );
- }
+ Graphics2D g2d = (Graphics2D) g;
+ if (gxTx != null) {
+ g2d.transform(gxTx);
+ }
+ if (useFM) {
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ }
- }// Sysout class
-
-/**
- This is part of the standard test machinery. It provides a place for the
- test instructions to be displayed, and a place for interactive messages
- to the user to be displayed.
- To have the test instructions displayed, see Sysout.
- To have a message to the user be displayed, see Sysout.
- Do not call anything in this dialog directly.
- */
-class TestDialog extends Dialog
- {
-
- TextArea instructionsText;
- TextArea messageText;
- int maxStringLength = 80;
-
- //DO NOT call this directly, go through Sysout
- public TestDialog( Frame frame, String name )
- {
- super( frame, name );
- int scrollBoth = TextArea.SCROLLBARS_BOTH;
- instructionsText = new TextArea( "", 20, maxStringLength, scrollBoth );
- add( "North", instructionsText );
-
- messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
- add("South", messageText);
-
- pack();
-
- show();
- }// TestDialog()
-
- //DO NOT call this directly, go through Sysout
- public void printInstructions( String[] instructions )
- {
- //Clear out any current instructions
- instructionsText.setText( "" );
-
- //Go down array of instruction strings
-
- String printStr, remainingStr;
- for( int i=0; i < instructions.length; i++ )
- {
- //chop up each into pieces maxSringLength long
- remainingStr = instructions[ i ];
- while( remainingStr.length() > 0 )
- {
- //if longer than max then chop off first max chars to print
- if( remainingStr.length() >= maxStringLength )
- {
- //Try to chop on a word boundary
- int posOfSpace = remainingStr.
- lastIndexOf( ' ', maxStringLength - 1 );
-
- if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
-
- printStr = remainingStr.substring( 0, posOfSpace + 1 );
- remainingStr = remainingStr.substring( posOfSpace + 1 );
- }
- //else just print
- else
- {
- printStr = remainingStr;
- remainingStr = "";
- }
-
- instructionsText.append( printStr + "\n" );
-
- }// while
-
- }// for
-
- }//printInstructions()
-
- //DO NOT call this directly, go through Sysout
- public void displayMessage( String messageIn )
- {
- messageText.append( messageIn + "\n" );
+ String text = TEXT + TEXT + TEXT;
+ g.setColor(Color.BLACK);
+ int y = 20;
+ float origSize = 7f;
+ for (int i = 0; i < 11; i++) {
+ float size = origSize + (i * 0.1f);
+ g2d.translate(0, size + 6);
+ Font f = textFont.deriveFont(size);
+ g2d.setFont(f);
+ FontMetrics fontMetrics = g2d.getFontMetrics();
+ int stringWidth = fontMetrics.stringWidth(text);
+ g.drawLine(0, y + 1, stringWidth, y + 1);
+ g.drawString(text, 0, y);
+ y += 10;
+ }
+ }
}
-
-}// TestDialog class
+}
diff --git a/test/jdk/java/foreign/TestMemorySession.java b/test/jdk/java/foreign/TestMemorySession.java
index 617951f6b6b..e5b4ca74027 100644
--- a/test/jdk/java/foreign/TestMemorySession.java
+++ b/test/jdk/java/foreign/TestMemorySession.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 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,12 +28,6 @@
*/
import java.lang.foreign.Arena;
-
-import jdk.internal.foreign.MemorySessionImpl;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@@ -41,6 +35,11 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.stream.IntStream;
+import jdk.internal.foreign.MemorySessionImpl;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
public class TestMemorySession {
@@ -319,6 +318,70 @@ public void testIsCloseableBy(ArenaSupplier arenaSupplier) {
assertEquals(sessionImpl.isCloseableBy(otherThread), isCloseableByOther);
}
+ /**
+ * Test that a thread failing to acquire a scope will not observe it as alive afterwards.
+ */
+ @Test
+ public void testAcquireCloseRace() throws InterruptedException {
+ int iteration = 1000;
+ AtomicInteger lock = new AtomicInteger();
+ boolean[] result = new boolean[1];
+ lock.set(-2);
+ MemorySessionImpl[] scopes = new MemorySessionImpl[iteration];
+ for (int i = 0; i < iteration; i++) {
+ scopes[i] = MemorySessionImpl.toMemorySession(Arena.ofShared());
+ }
+
+ // This thread tries to close the scopes
+ Thread t1 = new Thread(() -> {
+ for (int i = 0; i < iteration; i++) {
+ MemorySessionImpl scope = scopes[i];
+ while (true) {
+ try {
+ scope.close();
+ break;
+ } catch (IllegalStateException e) {}
+ }
+ // Keep the 2 threads operating on the same scope
+ int k = lock.getAndAdd(1) + 1;
+ while (k != i * 2) {
+ Thread.onSpinWait();
+ k = lock.get();
+ }
+ }
+ });
+
+ // This thread tries to acquire the scopes, then check if it is alive after an acquire failure
+ Thread t2 = new Thread(() -> {
+ for (int i = 0; i < iteration; i++) {
+ MemorySessionImpl scope = scopes[i];
+ while (true) {
+ try {
+ scope.acquire0();
+ } catch (IllegalStateException e) {
+ if (scope.isAlive()) {
+ result[0] = true;
+ }
+ break;
+ }
+ scope.release0();
+ }
+ // Keep the 2 threads operating on the same scope
+ int k = lock.getAndAdd(1) + 1;
+ while (k != i * 2) {
+ Thread.onSpinWait();
+ k = lock.get();
+ }
+ }
+ });
+
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+ assertFalse(result[0]);
+ }
+
private void waitSomeTime() {
try {
Thread.sleep(10);
diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/SetTimesNanos.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/SetTimesNanos.java
index 0c07c9ab9db..d71b9407bbc 100644
--- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/SetTimesNanos.java
+++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/SetTimesNanos.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,10 +22,13 @@
*/
/* @test
- * @bug 8181493 8231174
+ * @bug 8181493 8231174 8343417
* @summary Verify that nanosecond precision is maintained for file timestamps
* @requires (os.family == "linux") | (os.family == "mac") | (os.family == "windows")
+ * @library ../.. /test/lib
+ * @build jdk.test.lib.Platform
* @modules java.base/sun.nio.fs:+open
+ * @run main SetTimesNanos
*/
import java.io.IOException;
@@ -36,15 +39,19 @@
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileTime;
+import java.util.List;
import java.util.Set;
-import java.util.concurrent.TimeUnit;
+
+import static java.nio.file.LinkOption.*;
+import static java.util.concurrent.TimeUnit.*;
+
+import jdk.test.lib.Platform;
+import jtreg.SkippedException;
public class SetTimesNanos {
- private static final boolean IS_WINDOWS =
- System.getProperty("os.name").startsWith("Windows");
public static void main(String[] args) throws Exception {
- if (!IS_WINDOWS) {
+ if (!Platform.isWindows()) {
// Check whether futimens() system call is supported
Class unixNativeDispatcherClass =
Class.forName("sun.nio.fs.UnixNativeDispatcher");
@@ -52,8 +59,7 @@ public static void main(String[] args) throws Exception {
unixNativeDispatcherClass.getDeclaredMethod("futimensSupported");
futimensSupported.setAccessible(true);
if (!(boolean)futimensSupported.invoke(null)) {
- System.err.println("futimens() not supported; skipping test");
- return;
+ throw new SkippedException("futimens() not supported");
}
}
@@ -63,30 +69,34 @@ public static void main(String[] args) throws Exception {
System.out.format("FileStore: \"%s\" on %s (%s)%n",
dir, store.name(), store.type());
- Set testedTypes = IS_WINDOWS ?
+ Set testedTypes = Platform.isWindows() ?
Set.of("NTFS") : Set.of("apfs", "ext4", "xfs", "zfs");
if (!testedTypes.contains(store.type())) {
- System.err.format("%s not in %s; skipping test", store.type(), testedTypes);
- return;
+ throw new SkippedException(store.type() + " not in " + testedTypes);
}
testNanos(dir);
Path file = Files.createFile(dir.resolve("test.dat"));
testNanos(file);
+
+ if (Platform.isLinux()) {
+ testNanosLink(false);
+ testNanosLink(true);
+ }
}
private static void testNanos(Path path) throws IOException {
// Set modification and access times
// Time stamp = "2017-01-01 01:01:01.123456789";
long timeNanos = 1_483_261_261L*1_000_000_000L + 123_456_789L;
- FileTime pathTime = FileTime.from(timeNanos, TimeUnit.NANOSECONDS);
+ FileTime pathTime = FileTime.from(timeNanos, NANOSECONDS);
BasicFileAttributeView view =
Files.getFileAttributeView(path, BasicFileAttributeView.class);
view.setTimes(pathTime, pathTime, null);
// Windows file time resolution is 100ns so truncate
- if (IS_WINDOWS) {
+ if (Platform.isWindows()) {
timeNanos = 100L*(timeNanos/100L);
}
@@ -99,7 +109,7 @@ private static void testNanos(Path path) throws IOException {
FileTime[] times = new FileTime[] {attrs.lastModifiedTime(),
attrs.lastAccessTime()};
for (int i = 0; i < timeNames.length; i++) {
- long nanos = times[i].to(TimeUnit.NANOSECONDS);
+ long nanos = times[i].to(NANOSECONDS);
if (nanos != timeNanos) {
throw new RuntimeException("Expected " + timeNames[i] +
" timestamp to be '" + timeNanos + "', but was '" +
@@ -107,4 +117,42 @@ private static void testNanos(Path path) throws IOException {
}
}
}
+
+ private static void testNanosLink(boolean absolute) throws IOException {
+ System.out.println("absolute: " + absolute);
+
+ var target = Path.of("target");
+ var symlink = Path.of("symlink");
+ if (absolute)
+ symlink = symlink.toAbsolutePath();
+
+ try {
+ Files.createFile(target);
+ Files.createSymbolicLink(symlink, target);
+
+ var newTime = FileTime.from(1730417633157646106L, NANOSECONDS);
+ System.out.println("newTime: " + newTime.to(NANOSECONDS));
+
+ for (Path p : List.of(target, symlink)) {
+ System.out.println("p: " + p);
+
+ var view = Files.getFileAttributeView(p,
+ BasicFileAttributeView.class, NOFOLLOW_LINKS);
+ view.setTimes(newTime, newTime, null);
+ var attrs = view.readAttributes();
+
+ if (!attrs.lastAccessTime().equals(newTime))
+ throw new RuntimeException("Last access time "
+ + attrs.lastAccessTime()
+ + " != " + newTime);
+ if (!attrs.lastAccessTime().equals(newTime))
+ throw new RuntimeException("Last modified time "
+ + attrs.lastModifiedTime()
+ + " != " + newTime);
+ }
+ } finally {
+ Files.deleteIfExists(target);
+ Files.deleteIfExists(symlink);
+ }
+ }
}
diff --git a/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java b/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java
index 0526f86b4a1..677341aacb1 100644
--- a/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java
+++ b/test/jdk/javax/management/remote/mandatory/connection/DeadLockTest.java
@@ -27,6 +27,10 @@
* @summary test on a client notification deadlock.
* @author Shanliang JIANG
*
+ * @requires vm.compMode != "Xcomp"
+ * @comment Running with -Xcomp is likely to cause a timeout while establishing the connection
+ * (RMI: java.rmi.NoSuchObjectException: no such object in table).
+ *
* @run clean DeadLockTest
* @run build DeadLockTest
* @run main DeadLockTest
@@ -139,7 +143,7 @@ public void handleNotification(Notification n, Object h) {
try {
conn.getDefaultDomain();
} catch (IOException ioe) {
- // Greate !
+ // OK
}
synchronized(this) {
diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
index d4219704934..9b25c9058d1 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
@@ -897,8 +897,9 @@ public JPackageCommand setAppLayoutAsserts(AppLayoutAssert ... asserts) {
}
public JPackageCommand excludeAppLayoutAsserts(AppLayoutAssert... asserts) {
- return setAppLayoutAsserts(Stream.of(asserts).filter(Predicate.not(
- appLayoutAsserts::contains)).toArray(AppLayoutAssert[]::new));
+ var asSet = Set.of(asserts);
+ return setAppLayoutAsserts(appLayoutAsserts.stream().filter(Predicate.not(
+ asSet::contains)).toArray(AppLayoutAssert[]::new));
}
JPackageCommand assertAppLayout() {
diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
index 8068e1d858f..63afb6cf9f7 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
@@ -259,7 +259,7 @@ static PackageHandlers createPkgPackageHandlers() {
}
static void verifyBundleStructure(JPackageCommand cmd) {
- Path bundleRoot;
+ final Path bundleRoot;
if (cmd.isImagePackageType()) {
bundleRoot = cmd.outputBundle();
} else {
@@ -268,8 +268,26 @@ static void verifyBundleStructure(JPackageCommand cmd) {
}
TKit.assertDirectoryContent(bundleRoot).match(Path.of("Contents"));
- TKit.assertDirectoryContent(bundleRoot.resolve("Contents")).match(
- cmd.isRuntime() ? RUNTIME_BUNDLE_CONTENTS : APP_BUNDLE_CONTENTS);
+
+ final var contentsDir = bundleRoot.resolve("Contents");
+ final var expectedContentsItems = cmd.isRuntime() ? RUNTIME_BUNDLE_CONTENTS : APP_BUNDLE_CONTENTS;
+
+ var contentsVerifier = TKit.assertDirectoryContent(contentsDir);
+ if (!cmd.hasArgument("--app-content")) {
+ contentsVerifier.match(expectedContentsItems);
+ } else {
+ // Additional content added to the bundle.
+ // Verify there is no period (.) char in the names of additional directories if any.
+ contentsVerifier.contains(expectedContentsItems);
+ contentsVerifier = contentsVerifier.removeAll(expectedContentsItems);
+ contentsVerifier.match(contentsVerifier.items().stream().filter(path -> {
+ if (Files.isDirectory(contentsDir.resolve(path))) {
+ return !path.getFileName().toString().contains(".");
+ } else {
+ return true;
+ }
+ }).collect(toSet()));
+ }
}
static String getBundleName(JPackageCommand cmd) {
diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java
index ca1224aafd7..02841a1a713 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java
@@ -61,6 +61,7 @@
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toSet;
import java.util.stream.Stream;
+import jdk.internal.util.OperatingSystem;
import jdk.jpackage.test.Functional.ExceptionBox;
import jdk.jpackage.test.Functional.ThrowingConsumer;
import jdk.jpackage.test.Functional.ThrowingRunnable;
@@ -68,8 +69,6 @@
public final class TKit {
- private static final String OS = System.getProperty("os.name").toLowerCase();
-
public static final Path TEST_SRC_ROOT = Functional.identity(() -> {
Path root = Path.of(System.getProperty("test.src"));
@@ -176,15 +175,15 @@ static String getCurrentDefaultAppName() {
}
public static boolean isWindows() {
- return (OS.contains("win"));
+ return OperatingSystem.isWindows();
}
public static boolean isOSX() {
- return (OS.contains("mac"));
+ return OperatingSystem.isMacOS();
}
public static boolean isLinux() {
- return ((OS.contains("nix") || OS.contains("nux")));
+ return OperatingSystem.isLinux();
}
public static boolean isLinuxAPT() {
@@ -786,7 +785,7 @@ public void match(Set expected) {
baseDir, format(comm.common), format(comm.unique1), format(comm.unique2)));
} else if (!comm.unique1.isEmpty()) {
error(String.format(
- "assertDirectoryContentEquals%s: Expected %s. Unexpected %s",
+ "assertDirectoryContentEquals(%s): Expected %s. Unexpected %s",
baseDir, format(comm.common), format(comm.unique1)));
} else if (!comm.unique2.isEmpty()) {
error(String.format(
@@ -818,12 +817,20 @@ public void contains(Set expected) {
}
}
- public DirectoryContentVerifier removeAll(Path ... paths) {
+ public DirectoryContentVerifier removeAll(Collection paths) {
Set newContent = new HashSet<>(content);
- newContent.removeAll(List.of(paths));
+ newContent.removeAll(paths);
return new DirectoryContentVerifier(baseDir, newContent);
}
+ public DirectoryContentVerifier removeAll(Path ... paths) {
+ return removeAll(List.of(paths));
+ }
+
+ public Set items() {
+ return content;
+ }
+
private DirectoryContentVerifier(Path baseDir, Set contents) {
this.baseDir = baseDir;
this.content = contents;
diff --git a/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java b/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java
index 5829aba23cc..69e1cd6c42a 100644
--- a/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java
+++ b/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java
@@ -28,6 +28,7 @@
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
+import jdk.internal.util.Architecture;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -73,7 +74,7 @@ private static void verifyHostArch(JPackageCommand cmd) throws Exception {
"/installer-gui-script/options/@hostArchitectures",
doc, XPathConstants.STRING);
- if ("aarch64".equals(System.getProperty("os.arch"))) {
+ if (Architecture.isAARCH64()) {
TKit.assertEquals(v, "arm64",
"Check value of \"hostArchitectures\" attribute");
} else {
diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java
index 8ea70a06034..f8cb983bd16 100644
--- a/test/jdk/tools/jpackage/share/InOutPathTest.java
+++ b/test/jdk/tools/jpackage/share/InOutPathTest.java
@@ -72,11 +72,20 @@ public static Collection input() {
data.addAll(additionalContentInput(packageTypes, "--app-content"));
}
- data.addAll(List.of(new Object[][]{
- {PackageType.IMAGE.toString(), wrap(cmd -> {
- additionalContent(cmd, "--app-content", cmd.outputBundle());
- }, "--app-content same as output bundle")},
- }));
+ if (!TKit.isOSX()) {
+ data.addAll(List.of(new Object[][]{
+ {PackageType.IMAGE.toString(), wrap(cmd -> {
+ additionalContent(cmd, "--app-content", cmd.outputBundle());
+ }, "--app-content same as output bundle")},
+ }));
+ } else {
+ var contentsFolder = "Contents/MacOS";
+ data.addAll(List.of(new Object[][]{
+ {PackageType.IMAGE.toString(), wrap(cmd -> {
+ additionalContent(cmd, "--app-content", cmd.outputBundle().resolve(contentsFolder));
+ }, String.format("--app-content same as the \"%s\" folder in the output bundle", contentsFolder))},
+ }));
+ }
if (TKit.isOSX()) {
data.addAll(additionalContentInput(PackageType.MAC_DMG.toString(),
@@ -172,6 +181,16 @@ private static void runTest(Set packageTypes,
if (isAppImageValid(cmd)) {
verifyAppImage(cmd);
}
+
+ if (cmd.hasArgument("--app-content")) {
+ // `--app-content` can be set to the app image directory which
+ // should not exist before jpackage is executed:
+ // jpackage --name Foo --dest output --app-content output/Foo
+ // Verify the directory exists after jpackage execution.
+ // At least this will catch the case when the value of
+ // `--app-content` option refers to a path unrelated to jpackage I/O.
+ TKit.assertDirectoryExists(Path.of(cmd.getArgumentValue("--app-content")));
+ }
} else {
new PackageTest()
.forTypes(packageTypes)
diff --git a/test/langtools/tools/javac/annotations/ParameterArrayLimit.java b/test/langtools/tools/javac/annotations/ParameterArrayLimit.java
new file mode 100644
index 00000000000..6e782dd0b83
--- /dev/null
+++ b/test/langtools/tools/javac/annotations/ParameterArrayLimit.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Check if error is thrown if annotation array exceeds limit
+ * @library /tools/lib
+ * @run main ParameterArrayLimit
+ */
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.List;
+import javax.tools.*;
+
+import com.sun.source.util.JavacTask;
+
+public class ParameterArrayLimit {
+
+ public static void main(String[] args) throws IOException {
+
+ int[] values = new int[]{65536, 65537, 512000};
+ String[] retPolicies = {"RUNTIME", "CLASS"};
+
+ for (var value : values) {
+ Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));
+
+ for (String retPolicy : retPolicies) {
+ String className = MessageFormat.format("ClassAnnotationWithLength_{0,number,#}_{1}.java",
+ value,
+ retPolicy);
+ Path out = tmpDir.resolve(className);
+ createAnnotationFile(out, value, retPolicy, false);
+ checkParamArrayWarning(className, out);
+ }
+
+ for (String retPolicy : retPolicies) {
+ String className = MessageFormat.format("TypeAnnotationWithLength_{0,number,#}_{1}.java",
+ value,
+ retPolicy);
+ Path out = tmpDir.resolve(className);
+ createAnnotationFile(out, value, retPolicy, true);
+ checkParamArrayWarning(className, out);
+ }
+ }
+ }
+
+ private static void checkParamArrayWarning(String className, Path out) throws IOException {
+ JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
+ DiagnosticCollector d = new DiagnosticCollector<>();
+ JavacTask task = (JavacTask) javaCompiler.getTask(
+ null,
+ null,
+ d,
+ null,
+ null,
+ Collections.singletonList(
+ SimpleJavaFileObject.forSource(
+ URI.create("myfo:/" + className),
+ Files.readString(out)
+ )));
+ task.call();
+
+ List> diagnosticList = d.getDiagnostics();
+ if (diagnosticList.isEmpty()) {
+ throw new RuntimeException("No diagnostic found");
+ }
+
+ for (Diagnostic extends JavaFileObject> diagnostic : diagnosticList) {
+ if (!(diagnostic.getKind() == Diagnostic.Kind.ERROR
+ && diagnostic.getCode()
+ .equals("compiler.err.annotation.array.too.large"))) {
+ throw new RuntimeException("Unexpected diagnostic: " + diagnostic.getMessage(null));
+ }
+ }
+ }
+
+ private static void createAnnotationFile(Path out, int value, String retPolicy, boolean isTypeAnnotation) throws IOException {
+ StringBuilder sb = new StringBuilder();
+
+ if (isTypeAnnotation) {
+ sb.append(MessageFormat.format("""
+ import java.lang.annotation.*;
+ @Retention(RetentionPolicy.{0})
+ @Target(ElementType.TYPE_USE)
+ @interface TypeAnno '{'
+ long[] arr();
+ '}'
+ """, retPolicy));
+ sb.append(MessageFormat.format("""
+ public class TypeAnnotationWithLength_{0,number,#}_{1}'{'
+ @TypeAnno(arr = '{'
+ """, value, retPolicy));
+ } else {
+ sb.append(MessageFormat.format("""
+ import java.lang.annotation.*;
+ @Retention(RetentionPolicy.{0})
+ @interface MyCustomAnno '{'
+ String value() default "default value";
+ long[] arr();
+ int count() default 0;
+ '}'
+ """, retPolicy));
+ sb.append(MessageFormat.format("""
+ public class ClassAnnotationWithLength_{0,number,#}_{1}'{'
+ @MyCustomAnno(value = "custom", count = 42, arr = '{'
+ """, value, retPolicy));
+ }
+
+ sb.append("-1,".repeat(Math.max(0, value - 1)));
+ sb.append("-1})");
+
+ sb.append("""
+ static int x = 3;
+
+ public void myAnnotatedMethod() { }
+ }
+ """);
+
+ try (BufferedWriter bufferedWriter = Files.newBufferedWriter(out)) {
+ bufferedWriter.write(sb.toString());
+ }
+ }
+}
diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt
index 329e716a780..e158366a171 100644
--- a/test/langtools/tools/javac/diags/examples.not-yet.txt
+++ b/test/langtools/tools/javac/diags/examples.not-yet.txt
@@ -16,6 +16,7 @@ compiler.err.limit.code # Code
compiler.err.limit.code.too.large.for.try.stmt # Gen
compiler.err.limit.dimensions # Gen
compiler.err.limit.locals # Code
+compiler.err.annotation.array.too.large # Code
compiler.err.limit.parameters # Gen
compiler.err.limit.pool # Gen,JavaCompiler
compiler.err.limit.pool.in.class # UNUSED?
diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.java
new file mode 100644
index 00000000000..9ee54f8ef6b
--- /dev/null
+++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.bench.java.lang.foreign;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.ValueLayout;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.CompilerControl;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.TearDown;
+import jdk.internal.misc.Unsafe;
+
+@BenchmarkMode(Mode.AverageTime)
+@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
+@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
+@State(org.openjdk.jmh.annotations.Scope.Thread)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" })
+public class LoopOverRandom extends JavaLayouts {
+ static final int SEED = 0;
+
+ static final long ELEM_SIZE = ValueLayout.JAVA_INT.byteSize();
+ static final int ELEM_COUNT = 1_000;
+ static final long ALLOC_SIZE = ELEM_COUNT * ELEM_SIZE;
+
+ static final Unsafe unsafe = Utils.unsafe;
+
+ Arena arena;
+ MemorySegment segment;
+ int[] indices;
+
+ static final MemorySegment ALL = MemorySegment.NULL.reinterpret(Long.MAX_VALUE);
+
+ @Setup
+ public void setup() {
+ indices = new Random(SEED).ints(0, ELEM_COUNT).limit(ELEM_COUNT).toArray();
+ arena = Arena.ofConfined();
+ segment = arena.allocate(ALLOC_SIZE);
+ for (int i = 0; i < ELEM_COUNT; i++) {
+ segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
+ }
+ }
+
+ @TearDown
+ public void tearDown() {
+ arena.close();
+ }
+
+ @Benchmark
+ public long segment_loop() {
+ int sum = 0;
+ for (int i = 0; i < ELEM_COUNT; i++) {
+ sum += segment.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED, indices[i]);
+ target_dontInline();
+ }
+ return sum;
+ }
+
+ @Benchmark
+ public long segment_loop_all() {
+ int sum = 0;
+ for (int i = 0; i < ELEM_COUNT; i++) {
+ sum += ALL.get(ValueLayout.JAVA_INT_UNALIGNED, segment.address() + indices[i] * ELEM_SIZE);
+ target_dontInline();
+ }
+ return sum;
+ }
+
+ @Benchmark
+ public long segment_loop_asUnchecked() {
+ int sum = 0;
+ for (int i = 0; i < ELEM_COUNT; i++) {
+ sum += asUnchecked(segment).getAtIndex(ValueLayout.JAVA_INT_UNALIGNED, indices[i]);
+ target_dontInline();
+ }
+ return sum;
+ }
+
+ @Benchmark
+ public long unsafe_loop() {
+ int sum = 0;
+ for (int i = 0; i < ELEM_COUNT; i++) {
+ sum += unsafe.getInt(segment.address() + indices[i] * ELEM_SIZE);
+ target_dontInline();
+ }
+ return sum;
+ }
+
+ MemorySegment asUnchecked(MemorySegment segment) {
+ return MemorySegment.ofAddress(segment.address()).reinterpret(Long.MAX_VALUE);
+ }
+
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public void target_dontInline() {
+ // this method was intentionally left blank
+ }
+}