30
30
import java .util .Map ;
31
31
import java .util .Objects ;
32
32
import java .util .Set ;
33
- import java .util .stream .Collectors ;
34
33
35
34
import javax .lang .model .SourceVersion ;
36
35
37
36
import com .oracle .svm .core .SubstrateUtil ;
38
37
39
- public final class ModuleUtil {
40
- private ModuleUtil () {
38
+ public final class ModuleNative {
39
+ private ModuleNative () {
41
40
}
42
41
42
+ /**
43
+ * Re-implementations of native methods from {@code src/hotspot/share/classfile/modules.cpp}.
44
+ * See {@link Target_java_lang_Module} for more information on module system native
45
+ * substitutions.
46
+ */
47
+
48
+ /**
49
+ * {@code Modules::define_module}.
50
+ */
51
+ public static void defineModule (Module module , boolean isOpen , Object [] pns ) {
52
+ if (Objects .isNull (module )) {
53
+ throw new NullPointerException ("Null module object" );
54
+ }
55
+
56
+ if (Objects .isNull (module .getName ())) {
57
+ throw new IllegalArgumentException ("Module name cannot be null" );
58
+ }
59
+
60
+ if (module .getName ().equals ("java.base" )) {
61
+ if (isOpen ) {
62
+ // Checkstyle: stop
63
+ throw new AssertionError ("java.base module cannot be open" );
64
+ // Checkstyle: resume
65
+ }
66
+
67
+ for (Object pn : pns ) {
68
+ checkPackageNameForModule (pn , "java.base" );
69
+ }
70
+
71
+ if (module .getClassLoader () != null ) {
72
+ throw new IllegalArgumentException ("Class loader must be the boot class loader" );
73
+ }
74
+
75
+ synchronized (moduleLock ) {
76
+ boolean duplicateJavaBase = bootLayerContainsModule ("java.base" );
77
+ if (duplicateJavaBase ) {
78
+ throw new InternalError ("Module java.base is already defined" );
79
+ }
80
+ }
81
+
82
+ return ;
83
+ }
84
+
85
+ ClassLoader loader = module .getClassLoader ();
86
+ if (Objects .nonNull (loader ) && loader .getClass ().getName ().equals ("jdk.internal.reflect.DelegatingClassLoader" )) {
87
+ throw new IllegalArgumentException ("Class loader is an invalid delegating class loader" );
88
+ }
89
+
90
+ boolean javaPkgDisallowed = !Objects .isNull (loader ) && !Objects .equals (loader , ClassLoader .getPlatformClassLoader ());
91
+ for (Object pn : pns ) {
92
+ checkPackageNameForModule (pn , module .getName ());
93
+ if (javaPkgDisallowed && isPackageNameForbidden (pn .toString ())) {
94
+ throw new IllegalArgumentException ("Class loader (instance of): " + loader .getClass ().getName () +
95
+ " tried to define prohibited package name: " + pn );
96
+ }
97
+ }
98
+
99
+ String definedPackage = null ;
100
+ boolean moduleAlreadyDefined ;
101
+ synchronized (moduleLock ) {
102
+ moduleAlreadyDefined = isModuleDefinedToLoader (loader , module .getName ());
103
+ if (!moduleAlreadyDefined ) {
104
+ List <String > definedPackages = getPackagesDefinedToLoader (loader );
105
+ for (Object pn : pns ) {
106
+ String pnString = pn .toString ();
107
+ if (definedPackages .contains (pnString )) {
108
+ definedPackage = pnString ;
109
+ break ;
110
+ }
111
+ }
112
+ }
113
+ }
114
+
115
+ if (moduleAlreadyDefined ) {
116
+ throw new IllegalStateException ("Module " + module .getName () + " is already defined" );
117
+ } else if (Objects .nonNull (definedPackage )) {
118
+ Module moduleContainingDefinedPackage = SubstrateUtil .cast (getModuleContainingPackage (loader , definedPackage ), Module .class );
119
+ if (moduleContainingDefinedPackage .isNamed ()) {
120
+ throw new IllegalStateException ("Package " + definedPackage + " is already in another module, " + moduleContainingDefinedPackage .getName () + ", defined to the class loader" );
121
+ } else {
122
+ throw new IllegalStateException ("Package " + definedPackage + " is already in the unnamed module defined to the class loader" );
123
+ }
124
+ }
125
+
126
+ synchronized (moduleLock ) {
127
+ addDefinedModule (loader , module );
128
+ }
129
+ }
130
+
131
+ /**
132
+ * {@code Modules::add_reads_module}.
133
+ */
134
+ public static void addReads (Module from , @ SuppressWarnings ("unused" ) Module to ) {
135
+ checkIsNull (from , FROM_MODULE_TAG );
136
+ }
137
+
138
+ /**
139
+ * {@code Modules::add_module_exports_qualified}.
140
+ */
141
+ public static void addExports (Module from , String pn , Module to ) {
142
+ checkIsNull (to , TO_MODULE_TAG );
143
+ addExportsToAll (from , pn );
144
+ }
145
+
146
+ /**
147
+ * {@code Modules::add_module_exports}.
148
+ */
149
+ public static void addExportsToAll (Module from , String pn ) {
150
+ checkIsNull (pn , PACKAGE_TAG );
151
+ checkIsNull (from , FROM_MODULE_TAG );
152
+ checkIsPackageContainedInModule (pn , from , FROM_MODULE_TAG );
153
+ }
154
+
155
+ /**
156
+ * {@code Modules::add_module_exports_to_all_unnamed}.
157
+ */
158
+ public static void addExportsToAllUnnamed (Module module , String pn ) {
159
+ checkIsNull (module , MODULE_TAG );
160
+ checkIsNull (pn , PACKAGE_TAG );
161
+ checkIsPackageContainedInModule (pn , module , MODULE_TAG );
162
+ }
163
+
164
+ /**
165
+ * Module bookkeeping and utility methods used by substitutions.
166
+ */
167
+
168
+ private static final String PACKAGE_TAG = "module" ;
169
+ private static final String MODULE_TAG = "module" ;
170
+ private static final String FROM_MODULE_TAG = "from_" + MODULE_TAG ;
171
+ private static final String TO_MODULE_TAG = "to_" + MODULE_TAG ;
43
172
private static final Object moduleLock = new Object ();
44
173
private static final Map <ClassLoader , Set <Module >> definedModules = new HashMap <>();
45
174
46
- public static Map <ClassLoader , Set <Module >> getDefinedModules () {
47
- if (definedModules .size () == 0 ) {
175
+ private static Map <ClassLoader , Set <Module >> getDefinedModules () {
176
+ if (definedModules .isEmpty () ) {
48
177
for (Module module : ModuleLayer .boot ().modules ()) {
49
178
Set <Module > modules = definedModules .get (module .getClassLoader ());
50
179
if (Objects .isNull (modules )) {
@@ -59,35 +188,37 @@ public static Map<ClassLoader, Set<Module>> getDefinedModules() {
59
188
return definedModules ;
60
189
}
61
190
62
- public static void checkFromModuleAndPackageNullability (Module from , String pn ) {
63
- if (Objects .isNull (from )) {
64
- throw new NullPointerException ("The from_module is null" );
65
- }
66
-
67
- if (Objects .isNull (pn )) {
68
- throw new NullPointerException ("The package is null" );
191
+ private static void checkIsNull (Object o , String tag ) {
192
+ if (Objects .isNull (o )) {
193
+ throw new NullPointerException (tag + " is null" );
69
194
}
70
195
}
71
196
72
- public static boolean isPackageNameForbidden (String pn ) {
197
+ private static boolean isPackageNameForbidden (String pn ) {
73
198
if (!pn .startsWith ("java" )) {
74
199
return false ;
75
200
}
76
201
char trailingChar = pn .length () < 5 ? '.' : pn .charAt ("java" .length ());
77
202
return trailingChar == '.' ;
78
203
}
79
204
80
- public static boolean isValidPackageName (String pn ) {
205
+ private static void checkPackageNameForModule (Object pn , String module ) {
206
+ if (Objects .isNull (pn ) || !(pn instanceof String pnString )) {
207
+ throw new IllegalArgumentException ("Bad package name" );
208
+ }
209
+
81
210
// It is OK to use SourceVersion.isName here even though it calls String.split()
82
211
// because pattern "\\." will take the fast path in the String.split() method
83
- return Objects .nonNull (pn ) && SourceVersion .isName (pn );
212
+ if (!SourceVersion .isName (pnString )) {
213
+ throw new IllegalArgumentException ("Invalid package name: " + pnString + " for module: " + module );
214
+ }
84
215
}
85
216
86
- public static boolean isModuleDefinedToLoader (ClassLoader loader , String moduleName ) {
217
+ private static boolean isModuleDefinedToLoader (ClassLoader loader , String moduleName ) {
87
218
return getDefinedModules ().getOrDefault (loader , Set .of ()).stream ().anyMatch (m -> m .getName ().equals (moduleName ));
88
219
}
89
220
90
- public static void addDefinedModule (ClassLoader loader , Module module ) {
221
+ private static void addDefinedModule (ClassLoader loader , Module module ) {
91
222
Set <Module > modules = getDefinedModules ().get (loader );
92
223
if (Objects .isNull (modules )) {
93
224
modules = new HashSet <>();
@@ -98,30 +229,23 @@ public static void addDefinedModule(ClassLoader loader, Module module) {
98
229
}
99
230
}
100
231
101
- public static void checkIsPackageContainedInModule (String pn , Module module ) {
102
- ClassLoader loader = module .getClassLoader () == null ? ClassLoader .getPlatformClassLoader () : module .getClassLoader ();
103
- Package definedPackage = loader .getDefinedPackage (pn );
104
- if (definedPackage != null ) {
105
- Target_java_lang_NamedPackage namedPackage = SubstrateUtil .cast (definedPackage , Target_java_lang_NamedPackage .class );
106
- Module actualModule = namedPackage .module ;
107
- if (!actualModule .equals (module )) {
108
- throw new IllegalArgumentException ("Package " + pn + " found in module " + actualModule .getName () +
109
- ", not in module: " + module .getName ());
110
- }
232
+ private static void checkIsPackageContainedInModule (String pn , Module module , String tag ) {
233
+ if (!module .isNamed () || module .getDescriptor ().isOpen ()) {
234
+ return ;
111
235
}
112
236
if (!module .getPackages ().contains (pn )) {
113
- throw new IllegalArgumentException ("Package " + pn + " not found in from_module " + module .getName ());
237
+ throw new IllegalArgumentException ("Package " + pn + " not found in " + tag + " " + module .getName ());
114
238
}
115
239
}
116
240
117
- public static List <String > getPackagesDefinedToLoader (ClassLoader loader ) {
241
+ private static List <String > getPackagesDefinedToLoader (ClassLoader loader ) {
118
242
return getDefinedModules ().getOrDefault (loader , Set .of ())
119
243
.stream ()
120
244
.flatMap (m -> m .getPackages ().stream ())
121
- .collect ( Collectors . toUnmodifiableList () );
245
+ .toList ( );
122
246
}
123
247
124
- public static Object getModuleContainingPackage (ClassLoader loader , String pn ) {
248
+ private static Object getModuleContainingPackage (ClassLoader loader , String pn ) {
125
249
return getDefinedModules ().getOrDefault (loader , Set .of ())
126
250
.stream ()
127
251
.filter (m -> m .getPackages ().contains (pn ))
@@ -132,84 +256,4 @@ public static boolean bootLayerContainsModule(String name) {
132
256
return ModuleLayer .boot ().modules ().stream ().anyMatch (m -> m .getName ().equals (name ));
133
257
}
134
258
135
- public static void defineModule (Module module , boolean isOpen , List <String > pns ) {
136
- if (Objects .isNull (module )) {
137
- throw new NullPointerException ("Null module object" );
138
- }
139
-
140
- if (Objects .isNull (module .getName ())) {
141
- throw new IllegalArgumentException ("Module name cannot be null" );
142
- }
143
-
144
- if (module .getName ().equals ("java.base" )) {
145
- if (isOpen ) {
146
- throw new AssertionError ("The java.base module cannot be open" );
147
- }
148
-
149
- for (String pn : pns ) {
150
- if (!ModuleUtil .isValidPackageName (pn )) {
151
- throw new IllegalArgumentException ("Invalid package name: " + pn + " for module: java.base" );
152
- }
153
- }
154
-
155
- if (module .getClassLoader () != null ) {
156
- throw new IllegalArgumentException ("Class loader must be the boot class loader" );
157
- }
158
-
159
- synchronized (moduleLock ) {
160
- boolean duplicateJavaBase = ModuleUtil .bootLayerContainsModule ("java.base" );
161
- if (duplicateJavaBase ) {
162
- throw new InternalError ("Module java.base is already defined" );
163
- }
164
- }
165
-
166
- return ;
167
- }
168
-
169
- ClassLoader loader = module .getClassLoader ();
170
- if (Objects .isNull (loader ) || loader .getClass ().getName ().equals ("jdk.internal.reflect.DelegatingClassLoader" )) {
171
- throw new IllegalArgumentException ("Class loader is an invalid delegating class loader" );
172
- }
173
-
174
- for (String pn : pns ) {
175
- if (!ModuleUtil .isValidPackageName (pn )) {
176
- throw new IllegalArgumentException ("Invalid package name: " + pn + " for module: " + module .getName ());
177
- }
178
-
179
- if (loader != ClassLoader .getPlatformClassLoader () && ModuleUtil .isPackageNameForbidden (pn )) {
180
- throw new IllegalArgumentException ("Class loader (instance of): " + loader .getClass ().getName () +
181
- " tried to define prohibited package name: " + pn );
182
- }
183
- }
184
-
185
- String definedPackage = null ;
186
- boolean moduleAlreadyDefined ;
187
- synchronized (moduleLock ) {
188
- moduleAlreadyDefined = ModuleUtil .isModuleDefinedToLoader (loader , module .getName ());
189
- if (!moduleAlreadyDefined ) {
190
- List <String > definedPackages = ModuleUtil .getPackagesDefinedToLoader (loader );
191
- for (String pn : pns ) {
192
- if (definedPackages .contains (pn )) {
193
- definedPackage = pn ;
194
- break ;
195
- }
196
- }
197
- }
198
- }
199
-
200
- if (moduleAlreadyDefined ) {
201
- throw new IllegalStateException ("Module " + module .getName () + " is already defined" );
202
- } else if (Objects .nonNull (definedPackage )) {
203
- Module moduleContainingDefinedPackage = SubstrateUtil .cast (ModuleUtil .getModuleContainingPackage (loader , definedPackage ), Module .class );
204
- if (moduleContainingDefinedPackage .isNamed ()) {
205
- throw new IllegalStateException ("Package " + definedPackage + " is already in another module, " + moduleContainingDefinedPackage .getName () + ", defined to the class loader" );
206
- } else {
207
- throw new IllegalStateException ("Package " + definedPackage + " is already in the unnamed module defined to the class loader" );
208
- }
209
- }
210
-
211
- synchronized (moduleLock ) {
212
- ModuleUtil .addDefinedModule (loader , module );
213
- }
214
- }
215
259
}
0 commit comments