Skip to content

Commit c25b4f4

Browse files
committed
8301578: Perform output outside synchronization in Module.class
Reviewed-by: alanb
1 parent 5830c03 commit c25b4f4

File tree

1 file changed

+42
-36
lines changed

1 file changed

+42
-36
lines changed

src/java.base/share/classes/java/lang/Module.java

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,7 @@
5757
import jdk.internal.loader.BootLoader;
5858
import jdk.internal.loader.ClassLoaders;
5959
import jdk.internal.misc.CDS;
60+
import jdk.internal.misc.Unsafe;
6061
import jdk.internal.module.ModuleBootstrap;
6162
import jdk.internal.module.ModuleLoaderMap;
6263
import jdk.internal.module.ServicesCatalog;
@@ -113,6 +114,8 @@ public final class Module implements AnnotatedElement {
113114
private final ModuleDescriptor descriptor;
114115

115116
// true, if this module allows restricted native access
117+
// Accessing this variable is made through Unsafe in order to use the
118+
// memory semantics that preserves ordering and visibility across threads.
116119
@Stable
117120
private boolean enableNativeAccess;
118121

@@ -258,24 +261,43 @@ public ModuleLayer getLayer() {
258261
/**
259262
* Update this module to allow access to restricted methods.
260263
*/
261-
synchronized Module implAddEnableNativeAccess() {
262-
enableNativeAccess = true;
264+
Module implAddEnableNativeAccess() {
265+
EnableNativeAccess.trySetEnableNativeAccess(this);
263266
return this;
264267
}
265268

266269
/**
267270
* Returns {@code true} if this module can access
268271
* <a href="foreign/package-summary.html#restricted"><em>restricted</em></a> methods.
269272
*
270-
* @since 20
271-
*
272273
* @return {@code true} if this module can access <em>restricted</em> methods.
274+
* @since 20
273275
*/
274-
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
276+
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
275277
public boolean isNativeAccessEnabled() {
276278
Module target = moduleForNativeAccess();
277-
synchronized(target) {
278-
return target.enableNativeAccess;
279+
return EnableNativeAccess.isNativeAccessEnabled(target);
280+
}
281+
282+
/**
283+
* This class is used to be able to bootstrap without using Unsafe
284+
* in the outer Module class as that would create a circular initializer dependency.
285+
*/
286+
private static final class EnableNativeAccess {
287+
288+
private EnableNativeAccess() {}
289+
290+
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
291+
private static final long FIELD_OFFSET = UNSAFE.objectFieldOffset(Module.class, "enableNativeAccess");
292+
293+
private static boolean isNativeAccessEnabled(Module target) {
294+
return UNSAFE.getBooleanVolatile(target, FIELD_OFFSET);
295+
}
296+
297+
// Atomically sets enableNativeAccess if not already set
298+
// returning if the value was updated
299+
private static boolean trySetEnableNativeAccess(Module target) {
300+
return UNSAFE.compareAndSetBoolean(target, FIELD_OFFSET, false, true);
279301
}
280302
}
281303

@@ -289,46 +311,30 @@ private Module moduleForNativeAccess() {
289311
void ensureNativeAccess(Class<?> owner, String methodName) {
290312
// The target module whose enableNativeAccess flag is ensured
291313
Module target = moduleForNativeAccess();
292-
// racy read of the enable native access flag
293-
boolean isNativeAccessEnabled = target.enableNativeAccess;
294-
if (!isNativeAccessEnabled) {
295-
synchronized (target) {
296-
// safe read of the enableNativeAccess of the target module
297-
isNativeAccessEnabled = target.enableNativeAccess;
298-
299-
// check again with the safely read flag
300-
if (isNativeAccessEnabled) {
301-
// another thread beat us to it - nothing to do
302-
return;
303-
} else if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
304-
throw new IllegalCallerException("Illegal native access from: " + this);
305-
} else {
306-
// warn and set flag, so that only one warning is reported per module
307-
String cls = owner.getName();
308-
String mtd = cls + "::" + methodName;
309-
String mod = isNamed() ? "module " + getName() : "the unnamed module";
310-
String modflag = isNamed() ? getName() : "ALL-UNNAMED";
311-
System.err.printf("""
314+
if (!EnableNativeAccess.isNativeAccessEnabled(target)) {
315+
if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
316+
throw new IllegalCallerException("Illegal native access from: " + this);
317+
}
318+
if (EnableNativeAccess.trySetEnableNativeAccess(target)) {
319+
// warn and set flag, so that only one warning is reported per module
320+
String cls = owner.getName();
321+
String mtd = cls + "::" + methodName;
322+
String mod = isNamed() ? "module " + getName() : "the unnamed module";
323+
String modflag = isNamed() ? getName() : "ALL-UNNAMED";
324+
System.err.printf("""
312325
WARNING: A restricted method in %s has been called
313326
WARNING: %s has been called by %s
314327
WARNING: Use --enable-native-access=%s to avoid a warning for this module
315328
%n""", cls, mtd, mod, modflag);
316-
317-
// set the flag
318-
target.enableNativeAccess = true;
319-
}
320329
}
321330
}
322331
}
323332

324-
325333
/**
326334
* Update all unnamed modules to allow access to restricted methods.
327335
*/
328336
static void implAddEnableNativeAccessToAllUnnamed() {
329-
synchronized (ALL_UNNAMED_MODULE) {
330-
ALL_UNNAMED_MODULE.enableNativeAccess = true;
331-
}
337+
EnableNativeAccess.trySetEnableNativeAccess(ALL_UNNAMED_MODULE);
332338
}
333339

334340
// --

0 commit comments

Comments
 (0)