diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java
index 6f4da2219c1..aafe1b89a4b 100644
--- a/src/java.base/share/classes/java/lang/Module.java
+++ b/src/java.base/share/classes/java/lang/Module.java
@@ -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.
*
* 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.ClassLoaders;
import jdk.internal.misc.CDS;
+import jdk.internal.misc.Unsafe;
import jdk.internal.module.ModuleBootstrap;
import jdk.internal.module.ModuleLoaderMap;
import jdk.internal.module.ServicesCatalog;
@@ -113,6 +114,8 @@ public final class Module implements AnnotatedElement {
private final ModuleDescriptor descriptor;
// 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
private boolean enableNativeAccess;
@@ -258,8 +261,8 @@ public final class Module implements AnnotatedElement {
/**
* Update this module to allow access to restricted methods.
*/
- synchronized Module implAddEnableNativeAccess() {
- enableNativeAccess = true;
+ Module implAddEnableNativeAccess() {
+ EnableNativeAccess.trySetEnableNativeAccess(this);
return this;
}
@@ -267,15 +270,34 @@ public final class Module implements AnnotatedElement {
* Returns {@code true} if this module can access
* restricted methods.
*
- * @since 20
- *
* @return {@code true} if this module can access restricted methods.
+ * @since 20
*/
- @PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
+ @PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
public boolean isNativeAccessEnabled() {
Module target = moduleForNativeAccess();
- synchronized(target) {
- return target.enableNativeAccess;
+ return EnableNativeAccess.isNativeAccessEnabled(target);
+ }
+
+ /**
+ * 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,46 +311,30 @@ public final class Module implements AnnotatedElement {
void ensureNativeAccess(Class> owner, String methodName) {
// The target module whose enableNativeAccess flag is ensured
Module target = moduleForNativeAccess();
- // racy read of the enable native access flag
- boolean isNativeAccessEnabled = target.enableNativeAccess;
- 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);
- } else {
- // warn and set flag, so that only one warning is reported per module
- String cls = owner.getName();
- String mtd = cls + "::" + methodName;
- String mod = isNamed() ? "module " + getName() : "the unnamed module";
- String modflag = isNamed() ? getName() : "ALL-UNNAMED";
- System.err.printf("""
+ if (!EnableNativeAccess.isNativeAccessEnabled(target)) {
+ if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
+ throw new IllegalCallerException("Illegal native access from: " + this);
+ }
+ if (EnableNativeAccess.trySetEnableNativeAccess(target)) {
+ // warn and set flag, so that only one warning is reported per module
+ String cls = owner.getName();
+ String mtd = cls + "::" + methodName;
+ String mod = isNamed() ? "module " + getName() : "the unnamed module";
+ String modflag = isNamed() ? getName() : "ALL-UNNAMED";
+ System.err.printf("""
WARNING: A restricted method in %s has been called
WARNING: %s has been called by %s
WARNING: Use --enable-native-access=%s to avoid a warning for this module
%n""", cls, mtd, mod, modflag);
-
- // set the flag
- target.enableNativeAccess = true;
- }
}
}
}
-
/**
* Update all unnamed modules to allow access to restricted methods.
*/
static void implAddEnableNativeAccessToAllUnnamed() {
- synchronized (ALL_UNNAMED_MODULE) {
- ALL_UNNAMED_MODULE.enableNativeAccess = true;
- }
+ EnableNativeAccess.trySetEnableNativeAccess(ALL_UNNAMED_MODULE);
}
// --