1
1
/*
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.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
57
57
import jdk .internal .loader .BootLoader ;
58
58
import jdk .internal .loader .ClassLoaders ;
59
59
import jdk .internal .misc .CDS ;
60
+ import jdk .internal .misc .Unsafe ;
60
61
import jdk .internal .module .ModuleBootstrap ;
61
62
import jdk .internal .module .ModuleLoaderMap ;
62
63
import jdk .internal .module .ServicesCatalog ;
@@ -113,6 +114,8 @@ public final class Module implements AnnotatedElement {
113
114
private final ModuleDescriptor descriptor ;
114
115
115
116
// 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.
116
119
@ Stable
117
120
private boolean enableNativeAccess ;
118
121
@@ -258,24 +261,43 @@ public ModuleLayer getLayer() {
258
261
/**
259
262
* Update this module to allow access to restricted methods.
260
263
*/
261
- synchronized Module implAddEnableNativeAccess () {
262
- enableNativeAccess = true ;
264
+ Module implAddEnableNativeAccess () {
265
+ EnableNativeAccess . trySetEnableNativeAccess ( this ) ;
263
266
return this ;
264
267
}
265
268
266
269
/**
267
270
* Returns {@code true} if this module can access
268
271
* <a href="foreign/package-summary.html#restricted"><em>restricted</em></a> methods.
269
272
*
270
- * @since 20
271
- *
272
273
* @return {@code true} if this module can access <em>restricted</em> methods.
274
+ * @since 20
273
275
*/
274
- @ PreviewFeature (feature = PreviewFeature .Feature .FOREIGN )
276
+ @ PreviewFeature (feature = PreviewFeature .Feature .FOREIGN )
275
277
public boolean isNativeAccessEnabled () {
276
278
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 );
279
301
}
280
302
}
281
303
@@ -289,46 +311,30 @@ private Module moduleForNativeAccess() {
289
311
void ensureNativeAccess (Class <?> owner , String methodName ) {
290
312
// The target module whose enableNativeAccess flag is ensured
291
313
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 ("""
312
325
WARNING: A restricted method in %s has been called
313
326
WARNING: %s has been called by %s
314
327
WARNING: Use --enable-native-access=%s to avoid a warning for this module
315
328
%n""" , cls , mtd , mod , modflag );
316
-
317
- // set the flag
318
- target .enableNativeAccess = true ;
319
- }
320
329
}
321
330
}
322
331
}
323
332
324
-
325
333
/**
326
334
* Update all unnamed modules to allow access to restricted methods.
327
335
*/
328
336
static void implAddEnableNativeAccessToAllUnnamed () {
329
- synchronized (ALL_UNNAMED_MODULE ) {
330
- ALL_UNNAMED_MODULE .enableNativeAccess = true ;
331
- }
337
+ EnableNativeAccess .trySetEnableNativeAccess (ALL_UNNAMED_MODULE );
332
338
}
333
339
334
340
// --
0 commit comments