8301578: Perform output outside synchronization in Module.class

Reviewed-by: alanb
This commit is contained in:
Per Minborg 2023-02-10 13:46:46 +00:00
parent 5830c03e53
commit c25b4f4619

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -57,6 +57,7 @@ import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.BootLoader; import jdk.internal.loader.BootLoader;
import jdk.internal.loader.ClassLoaders; import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.CDS; import jdk.internal.misc.CDS;
import jdk.internal.misc.Unsafe;
import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ModuleBootstrap;
import jdk.internal.module.ModuleLoaderMap; import jdk.internal.module.ModuleLoaderMap;
import jdk.internal.module.ServicesCatalog; import jdk.internal.module.ServicesCatalog;
@ -113,6 +114,8 @@ public final class Module implements AnnotatedElement {
private final ModuleDescriptor descriptor; private final ModuleDescriptor descriptor;
// true, if this module allows restricted native access // true, if this module allows restricted native access
// Accessing this variable is made through Unsafe in order to use the
// memory semantics that preserves ordering and visibility across threads.
@Stable @Stable
private boolean enableNativeAccess; private boolean enableNativeAccess;
@ -258,8 +261,8 @@ public final class Module implements AnnotatedElement {
/** /**
* Update this module to allow access to restricted methods. * Update this module to allow access to restricted methods.
*/ */
synchronized Module implAddEnableNativeAccess() { Module implAddEnableNativeAccess() {
enableNativeAccess = true; EnableNativeAccess.trySetEnableNativeAccess(this);
return this; return this;
} }
@ -267,15 +270,34 @@ public final class Module implements AnnotatedElement {
* Returns {@code true} if this module can access * Returns {@code true} if this module can access
* <a href="foreign/package-summary.html#restricted"><em>restricted</em></a> methods. * <a href="foreign/package-summary.html#restricted"><em>restricted</em></a> methods.
* *
* @since 20
*
* @return {@code true} if this module can access <em>restricted</em> methods. * @return {@code true} if this module can access <em>restricted</em> methods.
* @since 20
*/ */
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN) @PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
public boolean isNativeAccessEnabled() { public boolean isNativeAccessEnabled() {
Module target = moduleForNativeAccess(); Module target = moduleForNativeAccess();
synchronized(target) { return EnableNativeAccess.isNativeAccessEnabled(target);
return target.enableNativeAccess; }
/**
* This class is used to be able to bootstrap without using Unsafe
* in the outer Module class as that would create a circular initializer dependency.
*/
private static final class EnableNativeAccess {
private EnableNativeAccess() {}
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final long FIELD_OFFSET = UNSAFE.objectFieldOffset(Module.class, "enableNativeAccess");
private static boolean isNativeAccessEnabled(Module target) {
return UNSAFE.getBooleanVolatile(target, FIELD_OFFSET);
}
// Atomically sets enableNativeAccess if not already set
// returning if the value was updated
private static boolean trySetEnableNativeAccess(Module target) {
return UNSAFE.compareAndSetBoolean(target, FIELD_OFFSET, false, true);
} }
} }
@ -289,20 +311,11 @@ public final class Module implements AnnotatedElement {
void ensureNativeAccess(Class<?> owner, String methodName) { void ensureNativeAccess(Class<?> owner, String methodName) {
// The target module whose enableNativeAccess flag is ensured // The target module whose enableNativeAccess flag is ensured
Module target = moduleForNativeAccess(); Module target = moduleForNativeAccess();
// racy read of the enable native access flag if (!EnableNativeAccess.isNativeAccessEnabled(target)) {
boolean isNativeAccessEnabled = target.enableNativeAccess; if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
if (!isNativeAccessEnabled) {
synchronized (target) {
// safe read of the enableNativeAccess of the target module
isNativeAccessEnabled = target.enableNativeAccess;
// check again with the safely read flag
if (isNativeAccessEnabled) {
// another thread beat us to it - nothing to do
return;
} else if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
throw new IllegalCallerException("Illegal native access from: " + this); throw new IllegalCallerException("Illegal native access from: " + this);
} else { }
if (EnableNativeAccess.trySetEnableNativeAccess(target)) {
// warn and set flag, so that only one warning is reported per module // warn and set flag, so that only one warning is reported per module
String cls = owner.getName(); String cls = owner.getName();
String mtd = cls + "::" + methodName; String mtd = cls + "::" + methodName;
@ -313,22 +326,15 @@ public final class Module implements AnnotatedElement {
WARNING: %s has been called by %s WARNING: %s has been called by %s
WARNING: Use --enable-native-access=%s to avoid a warning for this module WARNING: Use --enable-native-access=%s to avoid a warning for this module
%n""", cls, mtd, mod, modflag); %n""", cls, mtd, mod, modflag);
// set the flag
target.enableNativeAccess = true;
} }
} }
} }
}
/** /**
* Update all unnamed modules to allow access to restricted methods. * Update all unnamed modules to allow access to restricted methods.
*/ */
static void implAddEnableNativeAccessToAllUnnamed() { static void implAddEnableNativeAccessToAllUnnamed() {
synchronized (ALL_UNNAMED_MODULE) { EnableNativeAccess.trySetEnableNativeAccess(ALL_UNNAMED_MODULE);
ALL_UNNAMED_MODULE.enableNativeAccess = true;
}
} }
// -- // --