8301578: Perform output outside synchronization in Module.class
Reviewed-by: alanb
This commit is contained in:
parent
5830c03e53
commit
c25b4f4619
@ -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
|
||||
* <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.
|
||||
* @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);
|
||||
}
|
||||
|
||||
// --
|
||||
|
Loading…
Reference in New Issue
Block a user