Skip to content

Commit

Permalink
8287186: JDK modules participating in preview
Browse files Browse the repository at this point in the history
Reviewed-by: alanb, jlahoda
  • Loading branch information
Paul Sandoz committed Jun 14, 2022
1 parent 0530f4e commit fb29770
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 75 deletions.
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.javac;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Indicates, when declared on a module declaration, that the module participates
* in preview features and therefore does not need to be compiled with "--enable-preview".
*/
@Target(ElementType.MODULE)
@Retention(RetentionPolicy.CLASS)
public @interface ParticipatesInPreview {
}
8 changes: 8 additions & 0 deletions src/java.base/share/classes/module-info.java
Expand Up @@ -141,9 +141,17 @@
jdk.compiler;
exports com.sun.security.ntlm to
java.security.sasl;
// Note: all modules in the exported list participate in preview features
// and therefore if they use preview features they do not need to be
// compiled with "--enable-preview".
// It is recommended for any modules that do participate that their
// module declaration be annotated with jdk.internal.javac.ParticipatesInPreview
exports jdk.internal.javac to
java.compiler,
java.management, // participates in preview features
jdk.compiler,
jdk.incubator.concurrent, // participates in preview features
jdk.incubator.vector, // participates in preview features
jdk.jdi,
jdk.jfr,
jdk.jshell,
Expand Down
Expand Up @@ -29,8 +29,6 @@
import javax.management.openmbean.CompositeData;
import sun.management.ManagementFactoryHelper;
import sun.management.ThreadInfoCompositeData;
import sun.management.Util;
import static java.lang.Thread.State.*;

/**
* Thread information. {@code ThreadInfo} contains the information
Expand Down Expand Up @@ -226,7 +224,7 @@ private void initialize(Thread t, int state, Object lockObj, Thread lockOwner,
StackTraceElement[] stackTrace,
MonitorInfo[] lockedMonitors,
LockInfo[] lockedSynchronizers) {
this.virtual = Util.isVirtual(t);
this.virtual = t.isVirtual();
this.threadId = t.threadId();
this.threadName = t.getName();
this.threadState = ManagementFactoryHelper.toThreadState(state);
Expand Down
5 changes: 4 additions & 1 deletion src/java.management/share/classes/module-info.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -23,6 +23,8 @@
* questions.
*/

import jdk.internal.javac.ParticipatesInPreview;

/**
* Defines the Java Management Extensions (JMX) API.
* <P>
Expand All @@ -35,6 +37,7 @@
* @moduleGraph
* @since 9
*/
@ParticipatesInPreview
module java.management {

exports java.lang.management;
Expand Down
13 changes: 6 additions & 7 deletions src/java.management/share/classes/sun/management/ThreadImpl.java
Expand Up @@ -31,7 +31,6 @@
import java.util.stream.Stream;
import javax.management.ObjectName;
import java.util.Objects;
import sun.management.Util;

/**
* Implementation for java.lang.management.ThreadMXBean as well as providing the
Expand Down Expand Up @@ -222,7 +221,7 @@ public void setThreadContentionMonitoringEnabled(boolean enable) {

private boolean verifyCurrentThreadCpuTime() {
// check if Thread CPU time measurement is supported.
if (Util.isVirtual(Thread.currentThread())) {
if (Thread.currentThread().isVirtual()) {
throw new UnsupportedOperationException("Not supported by virtual threads");
}
if (!isCurrentThreadCpuTimeSupported()) {
Expand Down Expand Up @@ -284,7 +283,7 @@ protected long[] getThreadCpuTime(long[] ids) {
long id = ids[0];
Thread thread = Thread.currentThread();
if (id == thread.threadId()) {
if (Util.isVirtual(thread)) {
if (thread.isVirtual()) {
times[0] = -1;
} else {
times[0] = getThreadTotalCpuTime0(0);
Expand Down Expand Up @@ -327,7 +326,7 @@ protected long[] getThreadUserTime(long[] ids) {
long id = ids[0];
Thread thread = Thread.currentThread();
if (id == thread.threadId()) {
if (Util.isVirtual(thread)) {
if (thread.isVirtual()) {
times[0] = -1;
} else {
times[0] = getThreadUserCpuTime0(0);
Expand Down Expand Up @@ -361,7 +360,7 @@ public void setThreadCpuTimeEnabled(boolean enable) {
}

protected long getCurrentThreadAllocatedBytes() {
if (isThreadAllocatedMemoryEnabled() && !Util.isVirtual(Thread.currentThread())) {
if (isThreadAllocatedMemoryEnabled() && !Thread.currentThread().isVirtual()) {
return getThreadAllocatedMemory0(0);
}
return -1;
Expand All @@ -377,7 +376,7 @@ protected long getThreadAllocatedBytes(long id) {
if (verified) {
Thread thread = Thread.currentThread();
if (id == thread.threadId()) {
if (Util.isVirtual(thread)) {
if (thread.isVirtual()) {
return -1L;
} else {
return getThreadAllocatedMemory0(0);
Expand Down Expand Up @@ -577,7 +576,7 @@ public ObjectName getObjectName() {
*/
private static long[] platformThreadIds(Thread[] threads) {
return Stream.of(threads)
.filter(t -> !Util.isVirtual(t))
.filter(t -> !t.isVirtual())
.mapToLong(Thread::threadId)
.toArray();
}
Expand Down
26 changes: 0 additions & 26 deletions src/java.management/share/classes/sun/management/Util.java
Expand Up @@ -25,7 +25,6 @@

package sun.management;

import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.management.ManagementPermission;
import java.lang.management.ThreadInfo;
Expand Down Expand Up @@ -88,20 +87,6 @@ public static void checkControlAccess() throws SecurityException {
checkAccess(controlPermission);
}

/**
* Returns true if the given Thread is a virtual thread.
*
* @implNote This method uses reflection because Thread::isVirtual is a preview API
* and the java.management module cannot be compiled with --enable-preview.
*/
public static boolean isVirtual(Thread thread) {
try {
return (boolean) THREAD_IS_VIRTUAL.invoke(thread);
} catch (Exception e) {
throw new InternalError(e);
}
}

/**
* Returns true if the given ThreadInfo is for a virtual thread.
*/
Expand All @@ -113,16 +98,6 @@ public static boolean isVirtual(ThreadInfo threadInfo) {
}
}

@SuppressWarnings("removal")
private static Method threadIsVirtual() {
PrivilegedExceptionAction<Method> pa = () -> Thread.class.getMethod("isVirtual");
try {
return AccessController.doPrivileged(pa);
} catch (PrivilegedActionException e) {
throw new InternalError(e);
}
}

@SuppressWarnings("removal")
private static Field threadInfoVirtual() {
PrivilegedExceptionAction<Field> pa = () -> {
Expand All @@ -137,6 +112,5 @@ private static Field threadInfoVirtual() {
}
}

private static final Method THREAD_IS_VIRTUAL = threadIsVirtual();
private static final Field THREADINFO_VIRTUAL = threadInfoVirtual();
}
Expand Up @@ -124,15 +124,22 @@ private Map<Integer, Source> initMajorVersionToSourceMap() {
* Returns true if {@code s} is deemed to participate in the preview of {@code previewSymbol}, and
* therefore no warnings or errors will be produced.
*
* @parem syms the symbol table
* @param s the symbol depending on the preview symbol
* @param previewSymbol the preview symbol marked with @Preview
* @return true if {@code s} is participating in the preview of {@code previewSymbol}
*/
public boolean participatesInPreview(Symbol s, Symbol previewSymbol) {
// Hardcode the incubating vector API module for now
// Will generalize with an annotation, @PreviewParticipating say, later
return previewSymbol.packge().modle == s.packge().modle ||
s.packge().modle.name == names.jdk_incubator_vector;
public boolean participatesInPreview(Symtab syms, Symbol s, Symbol previewSymbol) {
// All symbols in the same module as the preview symbol participate in the preview API
if (previewSymbol.packge().modle == s.packge().modle) {
return true;
}

// If java.base's jdk.internal.javac package is exported to s's module then
// s participates in the preview API
return syms.java_base.exports.stream()
.filter(ed -> ed.packge.fullname == names.jdk_internal_javac)
.anyMatch(ed -> ed.modules.contains(s.packge().modle));
}

/**
Expand Down
Expand Up @@ -3600,7 +3600,7 @@ void checkProfile(final DiagnosticPosition pos, final Symbol s) {
}

void checkPreview(DiagnosticPosition pos, Symbol other, Symbol s) {
if ((s.flags() & PREVIEW_API) != 0 && !preview.participatesInPreview(other, s)) {
if ((s.flags() & PREVIEW_API) != 0 && !preview.participatesInPreview(syms, other, s)) {
if ((s.flags() & PREVIEW_REFLECTIVE) == 0) {
if (!preview.isEnabled()) {
log.error(pos, Errors.IsPreview(s));
Expand Down
Expand Up @@ -120,11 +120,11 @@ public static Names instance(Context context) {
// package names
public final Name java;
public final Name java_lang;
public final Name jdk_internal_javac;

// module names
public final Name java_base;
public final Name jdk_unsupported;
public final Name jdk_incubator_vector;

// attribute names
public final Name Annotation;
Expand Down Expand Up @@ -302,11 +302,11 @@ public Names(Context context) {
// package names
java = fromString("java");
java_lang = fromString("java.lang");
jdk_internal_javac = fromString("jdk.internal.javac");

// module names
java_base = fromString("java.base");
jdk_unsupported = fromString("jdk.unsupported");
jdk_incubator_vector = fromString("jdk.incubator.vector");

// attribute names
Annotation = fromString("Annotation");
Expand Down
Expand Up @@ -26,7 +26,6 @@

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.time.Duration;
Expand Down Expand Up @@ -300,7 +299,7 @@ public StructuredTaskScope(String name, ThreadFactory factory) {
*/
public StructuredTaskScope() {
PreviewFeatures.ensureEnabled();
this.factory = FactoryHolder.VIRTUAL_THREAD_FACTORY;
this.factory = Thread.ofVirtual().factory();
this.flock = ThreadFlock.open(null);
}

Expand Down Expand Up @@ -839,7 +838,7 @@ public ShutdownOnSuccess(String name, ThreadFactory factory) {
* name of {@code null} and a thread factory that creates virtual threads.
*/
public ShutdownOnSuccess() {
super(null, FactoryHolder.VIRTUAL_THREAD_FACTORY);
super(null, Thread.ofVirtual().factory());
}

/**
Expand Down Expand Up @@ -1015,7 +1014,7 @@ public ShutdownOnFailure(String name, ThreadFactory factory) {
* name of {@code null} and a thread factory that creates virtual threads.
*/
public ShutdownOnFailure() {
super(null, FactoryHolder.VIRTUAL_THREAD_FACTORY);
super(null, Thread.ofVirtual().factory());
}

/**
Expand Down Expand Up @@ -1161,29 +1160,4 @@ void throwIfFailed(Function<Throwable, ? extends X> esf) throws X {
}
}
}

/**
* Holder class for the virtual thread factory. It uses reflection to allow
* this class be compiled in an incubator module without also enabling preview
* features.
*/
private static class FactoryHolder {
static final ThreadFactory VIRTUAL_THREAD_FACTORY = virtualThreadFactory();

@SuppressWarnings("removal")
private static ThreadFactory virtualThreadFactory() {
PrivilegedAction<ThreadFactory> pa = () -> {
try {
Method ofVirtualMethod = Thread.class.getDeclaredMethod("ofVirtual");
Object virtualThreadBuilder = ofVirtualMethod.invoke(null);
Class<?> ofVirtualClass = Class.forName("java.lang.Thread$Builder$OfVirtual");
Method factoryMethod = ofVirtualClass.getMethod("factory");
return (ThreadFactory) factoryMethod.invoke(virtualThreadBuilder);
} catch (Exception e) {
throw new InternalError(e);
}
};
return AccessController.doPrivileged(pa);
}
}
}
3 changes: 3 additions & 0 deletions src/jdk.incubator.concurrent/share/classes/module-info.java
Expand Up @@ -23,12 +23,15 @@
* questions.
*/

import jdk.internal.javac.ParticipatesInPreview;

/**
* Defines non-final APIs for concurrent programming.
* {@Incubating}
*
* @moduleGraph
*/
@ParticipatesInPreview
module jdk.incubator.concurrent {
exports jdk.incubator.concurrent;
}
Expand Down
5 changes: 4 additions & 1 deletion src/jdk.incubator.vector/share/classes/module-info.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -23,6 +23,8 @@
* questions.
*/

import jdk.internal.javac.ParticipatesInPreview;

/**
* Defines an API for expressing computations that can be reliably compiled
* at runtime into SIMD instructions, such as AVX instructions on x64, and
Expand All @@ -31,6 +33,7 @@
*
* @moduleGraph
*/
@ParticipatesInPreview
module jdk.incubator.vector {
exports jdk.incubator.vector;
}

1 comment on commit fb29770

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.