8273000: Remove WeakReference-based class initialisation barrier implementation

Reviewed-by: psandoz, mchung
This commit is contained in:
Vladimir Ivanov 2021-09-08 11:28:17 +00:00
parent 21012f2bbe
commit faa942c8ba
2 changed files with 15 additions and 38 deletions
src/java.base/share/classes
java/lang/invoke
jdk/internal/misc

@ -33,7 +33,6 @@ import sun.invoke.util.VerifyAccess;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;
@ -363,27 +362,12 @@ class DirectMethodHandle extends MethodHandle {
VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
// It is a system class. It is probably in the process of
// being initialized, but we will help it along just to be safe.
if (UNSAFE.shouldBeInitialized(cls)) {
UNSAFE.ensureClassInitialized(cls);
}
UNSAFE.ensureClassInitialized(cls);
return false;
}
return UNSAFE.shouldBeInitialized(cls);
}
private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
@Override
protected WeakReference<Thread> computeValue(Class<?> type) {
UNSAFE.ensureClassInitialized(type);
if (UNSAFE.shouldBeInitialized(type))
// If the previous call didn't block, this can happen.
// We are executing inside <clinit>.
return new WeakReference<>(Thread.currentThread());
return null;
}
static final EnsureInitialized INSTANCE = new EnsureInitialized();
}
private void ensureInitialized() {
if (checkInitialized(member)) {
// The coast is clear. Delete the <clinit> barrier.
@ -397,24 +381,12 @@ class DirectMethodHandle extends MethodHandle {
}
private static boolean checkInitialized(MemberName member) {
Class<?> defc = member.getDeclaringClass();
WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
if (ref == null) {
return true; // the final state
}
// Somebody may still be running defc.<clinit>.
if (ref.refersTo(Thread.currentThread())) {
// If anybody is running defc.<clinit>, it is this thread.
if (UNSAFE.shouldBeInitialized(defc))
// Yes, we are running it; keep the barrier for now.
return false;
} else {
// We are in a random thread. Block.
UNSAFE.ensureClassInitialized(defc);
}
assert(!UNSAFE.shouldBeInitialized(defc));
// put it into the final state
EnsureInitialized.INSTANCE.remove(defc);
return true;
UNSAFE.ensureClassInitialized(defc);
// Once we get here either defc was fully initialized by another thread, or
// defc was already being initialized by the current thread. In the latter case
// the barrier must remain. We can detect this simply by checking if initialization
// is still needed.
return !UNSAFE.shouldBeInitialized(defc);
}
/*non-public*/

@ -1143,9 +1143,14 @@ public final class Unsafe {
}
/**
* Ensures the given class has been initialized. This is often
* needed in conjunction with obtaining the static field base of a
* class.
* Ensures the given class has been initialized (see JVMS-5.5 for details).
* This is often needed in conjunction with obtaining the static field base
* of a class.
*
* The call returns when either class {@code c} is fully initialized or
* class {@code c} is being initialized and the call is performed from
* the initializing thread. In the latter case a subsequent call to
* {@link #shouldBeInitialized} will return {@code true}.
*/
public void ensureClassInitialized(Class<?> c) {
if (c == null) {