|
1 /* |
|
2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 #include "precompiled.hpp" |
|
26 #include "classfile/classFileParser.hpp" |
|
27 #include "classfile/classLoader.hpp" |
|
28 #include "classfile/classLoaderData.inline.hpp" |
|
29 #include "classfile/javaAssertions.hpp" |
|
30 #include "classfile/javaClasses.hpp" |
|
31 #include "classfile/javaClasses.inline.hpp" |
|
32 #include "classfile/moduleEntry.hpp" |
|
33 #include "classfile/modules.hpp" |
|
34 #include "classfile/packageEntry.hpp" |
|
35 #include "classfile/stringTable.hpp" |
|
36 #include "classfile/symbolTable.hpp" |
|
37 #include "classfile/systemDictionary.hpp" |
|
38 #include "classfile/vmSymbols.hpp" |
|
39 #include "logging/log.hpp" |
|
40 #include "logging/logStream.hpp" |
|
41 #include "memory/resourceArea.hpp" |
|
42 #include "oops/instanceKlass.hpp" |
|
43 #include "prims/jvm.h" |
|
44 #include "runtime/arguments.hpp" |
|
45 #include "runtime/handles.inline.hpp" |
|
46 #include "runtime/javaCalls.hpp" |
|
47 #include "runtime/reflection.hpp" |
|
48 #include "utilities/stringUtils.hpp" |
|
49 #include "utilities/utf8.hpp" |
|
50 |
|
51 static bool verify_module_name(const char *module_name) { |
|
52 if (module_name == NULL) return false; |
|
53 int len = (int)strlen(module_name); |
|
54 return (len > 0 && len <= Symbol::max_length()); |
|
55 } |
|
56 |
|
57 bool Modules::verify_package_name(const char* package_name) { |
|
58 if (package_name == NULL) return false; |
|
59 int len = (int)strlen(package_name); |
|
60 return (len > 0 && len <= Symbol::max_length() && |
|
61 UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) && |
|
62 ClassFileParser::verify_unqualified_name(package_name, len, |
|
63 ClassFileParser::LegalClass)); |
|
64 } |
|
65 |
|
66 static char* get_module_name(oop module, TRAPS) { |
|
67 oop name_oop = java_lang_Module::name(module); |
|
68 if (name_oop == NULL) { |
|
69 THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), "Null module name"); |
|
70 } |
|
71 char* module_name = java_lang_String::as_utf8_string(name_oop); |
|
72 if (!verify_module_name(module_name)) { |
|
73 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), |
|
74 err_msg("Invalid module name: %s", |
|
75 module_name != NULL ? module_name : "NULL")); |
|
76 } |
|
77 return module_name; |
|
78 } |
|
79 |
|
80 static const char* get_module_version(jstring version) { |
|
81 if (version == NULL) { |
|
82 return NULL; |
|
83 } |
|
84 return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version)); |
|
85 } |
|
86 |
|
87 static ModuleEntryTable* get_module_entry_table(Handle h_loader, TRAPS) { |
|
88 // This code can be called during start-up, before the classLoader's classLoader data got |
|
89 // created. So, call register_loader() to make sure the classLoader data gets created. |
|
90 ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); |
|
91 return loader_cld->modules(); |
|
92 } |
|
93 |
|
94 static PackageEntryTable* get_package_entry_table(Handle h_loader, TRAPS) { |
|
95 // This code can be called during start-up, before the classLoader's classLoader data got |
|
96 // created. So, call register_loader() to make sure the classLoader data gets created. |
|
97 ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); |
|
98 return loader_cld->packages(); |
|
99 } |
|
100 |
|
101 static ModuleEntry* get_module_entry(jobject module, TRAPS) { |
|
102 Handle module_h(THREAD, JNIHandles::resolve(module)); |
|
103 if (!java_lang_Module::is_instance(module_h())) { |
|
104 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), |
|
105 "module is not an instance of type java.lang.Module"); |
|
106 } |
|
107 return java_lang_Module::module_entry(module_h(), CHECK_NULL); |
|
108 } |
|
109 |
|
110 static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) { |
|
111 ResourceMark rm(THREAD); |
|
112 if (package_name == NULL) return NULL; |
|
113 TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL); |
|
114 PackageEntryTable* package_entry_table = module_entry->loader_data()->packages(); |
|
115 assert(package_entry_table != NULL, "Unexpected null package entry table"); |
|
116 return package_entry_table->lookup_only(pkg_symbol); |
|
117 } |
|
118 |
|
119 static PackageEntry* get_package_entry_by_name(Symbol* package, |
|
120 Handle h_loader, |
|
121 TRAPS) { |
|
122 if (package != NULL) { |
|
123 ResourceMark rm(THREAD); |
|
124 if (Modules::verify_package_name(package->as_C_string())) { |
|
125 PackageEntryTable* const package_entry_table = |
|
126 get_package_entry_table(h_loader, CHECK_NULL); |
|
127 assert(package_entry_table != NULL, "Unexpected null package entry table"); |
|
128 return package_entry_table->lookup_only(package); |
|
129 } |
|
130 } |
|
131 return NULL; |
|
132 } |
|
133 |
|
134 bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) { |
|
135 PackageEntry* res = get_package_entry_by_name(package, h_loader, CHECK_false); |
|
136 return res != NULL; |
|
137 } |
|
138 |
|
139 static void define_javabase_module(jobject module, jstring version, |
|
140 jstring location, const char* const* packages, |
|
141 jsize num_packages, TRAPS) { |
|
142 ResourceMark rm(THREAD); |
|
143 |
|
144 Handle module_handle(THREAD, JNIHandles::resolve(module)); |
|
145 |
|
146 // Obtain java.base's module version |
|
147 const char* module_version = get_module_version(version); |
|
148 TempNewSymbol version_symbol; |
|
149 if (module_version != NULL) { |
|
150 version_symbol = SymbolTable::new_symbol(module_version, CHECK); |
|
151 } else { |
|
152 version_symbol = NULL; |
|
153 } |
|
154 |
|
155 // Obtain java.base's location |
|
156 const char* module_location = NULL; |
|
157 TempNewSymbol location_symbol = NULL; |
|
158 if (location != NULL) { |
|
159 module_location = |
|
160 java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); |
|
161 if (module_location != NULL) { |
|
162 location_symbol = SymbolTable::new_symbol(module_location, CHECK); |
|
163 } |
|
164 } |
|
165 |
|
166 |
|
167 // Check that the packages are syntactically ok. |
|
168 GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages); |
|
169 for (int x = 0; x < num_packages; x++) { |
|
170 const char *package_name = packages[x]; |
|
171 if (!Modules::verify_package_name(package_name)) { |
|
172 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
173 err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name)); |
|
174 } |
|
175 Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); |
|
176 pkg_list->append(pkg_symbol); |
|
177 } |
|
178 |
|
179 // Validate java_base's loader is the boot loader. |
|
180 oop loader = java_lang_Module::loader(module_handle()); |
|
181 if (loader != NULL) { |
|
182 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
183 "Class loader must be the boot class loader"); |
|
184 } |
|
185 Handle h_loader(THREAD, loader); |
|
186 |
|
187 // Ensure the boot loader's PackageEntryTable has been created |
|
188 PackageEntryTable* package_table = get_package_entry_table(h_loader, CHECK); |
|
189 assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table"); |
|
190 |
|
191 // Ensure java.base's ModuleEntry has been created |
|
192 assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for " JAVA_BASE_NAME); |
|
193 |
|
194 bool duplicate_javabase = false; |
|
195 { |
|
196 MutexLocker m1(Module_lock, THREAD); |
|
197 |
|
198 if (ModuleEntryTable::javabase_defined()) { |
|
199 duplicate_javabase = true; |
|
200 } else { |
|
201 |
|
202 // Verify that all java.base packages created during bootstrapping are in |
|
203 // pkg_list. If any are not in pkg_list, than a non-java.base class was |
|
204 // loaded erroneously pre java.base module definition. |
|
205 package_table->verify_javabase_packages(pkg_list); |
|
206 |
|
207 // loop through and add any new packages for java.base |
|
208 PackageEntry* pkg; |
|
209 for (int x = 0; x < pkg_list->length(); x++) { |
|
210 // Some of java.base's packages were added early in bootstrapping, ignore duplicates. |
|
211 if (package_table->lookup_only(pkg_list->at(x)) == NULL) { |
|
212 pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_moduleEntry()); |
|
213 assert(pkg != NULL, "Unable to create a " JAVA_BASE_NAME " package entry"); |
|
214 } |
|
215 // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of |
|
216 // the Symbol* that was created above for each package. The refcount was incremented |
|
217 // by SymbolTable::new_symbol and as well by the PackageEntry creation. |
|
218 pkg_list->at(x)->decrement_refcount(); |
|
219 } |
|
220 |
|
221 // Finish defining java.base's ModuleEntry |
|
222 ModuleEntryTable::finalize_javabase(module_handle, version_symbol, location_symbol); |
|
223 } |
|
224 } |
|
225 if (duplicate_javabase) { |
|
226 THROW_MSG(vmSymbols::java_lang_InternalError(), |
|
227 "Module " JAVA_BASE_NAME " is already defined"); |
|
228 } |
|
229 |
|
230 // Only the thread that actually defined the base module will get here, |
|
231 // so no locking is needed. |
|
232 |
|
233 // Patch any previously loaded class's module field with java.base's java.lang.Module. |
|
234 ModuleEntryTable::patch_javabase_entries(module_handle); |
|
235 |
|
236 log_info(module, load)(JAVA_BASE_NAME " location: %s", |
|
237 module_location != NULL ? module_location : "NULL"); |
|
238 log_debug(module)("define_javabase_module(): Definition of module: " |
|
239 JAVA_BASE_NAME ", version: %s, location: %s, package #: %d", |
|
240 module_version != NULL ? module_version : "NULL", |
|
241 module_location != NULL ? module_location : "NULL", |
|
242 pkg_list->length()); |
|
243 |
|
244 // packages defined to java.base |
|
245 if (log_is_enabled(Trace, module)) { |
|
246 for (int x = 0; x < pkg_list->length(); x++) { |
|
247 log_trace(module)("define_javabase_module(): creation of package %s for module " JAVA_BASE_NAME, |
|
248 (pkg_list->at(x))->as_C_string()); |
|
249 } |
|
250 } |
|
251 } |
|
252 |
|
253 // Caller needs ResourceMark. |
|
254 void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) { |
|
255 const char* package_name = package->name()->as_C_string(); |
|
256 if (package->module()->is_named()) { |
|
257 THROW_MSG(vmSymbols::java_lang_IllegalStateException(), |
|
258 err_msg("Package %s for module %s is already in another module, %s, defined to the class loader", |
|
259 package_name, module_name, package->module()->name()->as_C_string())); |
|
260 } else { |
|
261 THROW_MSG(vmSymbols::java_lang_IllegalStateException(), |
|
262 err_msg("Package %s for module %s is already in the unnamed module defined to the class loader", |
|
263 package_name, module_name)); |
|
264 } |
|
265 } |
|
266 |
|
267 void Modules::define_module(jobject module, jboolean is_open, jstring version, |
|
268 jstring location, const char* const* packages, |
|
269 jsize num_packages, TRAPS) { |
|
270 ResourceMark rm(THREAD); |
|
271 |
|
272 if (module == NULL) { |
|
273 THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); |
|
274 } |
|
275 |
|
276 if (num_packages < 0) { |
|
277 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
278 "num_packages must be >= 0"); |
|
279 } |
|
280 |
|
281 if (packages == NULL && num_packages > 0) { |
|
282 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
283 "num_packages should be zero if packages is null"); |
|
284 } |
|
285 |
|
286 Handle module_handle(THREAD, JNIHandles::resolve(module)); |
|
287 if (!java_lang_Module::is_instance(module_handle())) { |
|
288 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
289 "module is not an instance of type java.lang.Module"); |
|
290 } |
|
291 |
|
292 char* module_name = get_module_name(module_handle(), CHECK); |
|
293 if (module_name == NULL) { |
|
294 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
295 "Module name cannot be null"); |
|
296 } |
|
297 |
|
298 // Special handling of java.base definition |
|
299 if (strcmp(module_name, JAVA_BASE_NAME) == 0) { |
|
300 assert(is_open == JNI_FALSE, "java.base module cannot be open"); |
|
301 define_javabase_module(module, version, location, packages, num_packages, CHECK); |
|
302 return; |
|
303 } |
|
304 |
|
305 const char* module_version = get_module_version(version); |
|
306 |
|
307 oop loader = java_lang_Module::loader(module_handle()); |
|
308 // Make sure loader is not the jdk.internal.reflect.DelegatingClassLoader. |
|
309 if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) { |
|
310 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
311 "Class loader is an invalid delegating class loader"); |
|
312 } |
|
313 Handle h_loader = Handle(THREAD, loader); |
|
314 |
|
315 // Check that the list of packages has no duplicates and that the |
|
316 // packages are syntactically ok. |
|
317 GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages); |
|
318 for (int x = 0; x < num_packages; x++) { |
|
319 const char* package_name = packages[x]; |
|
320 if (!verify_package_name(package_name)) { |
|
321 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
322 err_msg("Invalid package name: %s for module: %s", |
|
323 package_name, module_name)); |
|
324 } |
|
325 |
|
326 // Only modules defined to either the boot or platform class loader, can define a "java/" package. |
|
327 if (!h_loader.is_null() && |
|
328 !SystemDictionary::is_platform_class_loader(h_loader()) && |
|
329 (strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0 && |
|
330 (package_name[JAVAPKG_LEN] == '/' || package_name[JAVAPKG_LEN] == '\0'))) { |
|
331 const char* class_loader_name = SystemDictionary::loader_name(h_loader()); |
|
332 size_t pkg_len = strlen(package_name); |
|
333 char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); |
|
334 strncpy(pkg_name, package_name, pkg_len); |
|
335 StringUtils::replace_no_expand(pkg_name, "/", "."); |
|
336 const char* msg_text1 = "Class loader (instance of): "; |
|
337 const char* msg_text2 = " tried to define prohibited package name: "; |
|
338 size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1; |
|
339 char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); |
|
340 jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name); |
|
341 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message); |
|
342 } |
|
343 |
|
344 Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); |
|
345 pkg_list->append(pkg_symbol); |
|
346 } |
|
347 |
|
348 ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK); |
|
349 assert(module_table != NULL, "module entry table shouldn't be null"); |
|
350 |
|
351 // Create symbol* entry for module name. |
|
352 TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK); |
|
353 |
|
354 bool dupl_modules = false; |
|
355 |
|
356 // Create symbol* entry for module version. |
|
357 TempNewSymbol version_symbol; |
|
358 if (module_version != NULL) { |
|
359 version_symbol = SymbolTable::new_symbol(module_version, CHECK); |
|
360 } else { |
|
361 version_symbol = NULL; |
|
362 } |
|
363 |
|
364 // Create symbol* entry for module location. |
|
365 const char* module_location = NULL; |
|
366 TempNewSymbol location_symbol = NULL; |
|
367 if (location != NULL) { |
|
368 module_location = |
|
369 java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); |
|
370 if (module_location != NULL) { |
|
371 location_symbol = SymbolTable::new_symbol(module_location, CHECK); |
|
372 } |
|
373 } |
|
374 |
|
375 ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(h_loader()); |
|
376 assert(loader_data != NULL, "class loader data shouldn't be null"); |
|
377 |
|
378 PackageEntryTable* package_table = NULL; |
|
379 PackageEntry* existing_pkg = NULL; |
|
380 { |
|
381 MutexLocker ml(Module_lock, THREAD); |
|
382 |
|
383 if (num_packages > 0) { |
|
384 package_table = get_package_entry_table(h_loader, CHECK); |
|
385 assert(package_table != NULL, "Missing package_table"); |
|
386 |
|
387 // Check that none of the packages exist in the class loader's package table. |
|
388 for (int x = 0; x < pkg_list->length(); x++) { |
|
389 existing_pkg = package_table->lookup_only(pkg_list->at(x)); |
|
390 if (existing_pkg != NULL) { |
|
391 // This could be because the module was already defined. If so, |
|
392 // report that error instead of the package error. |
|
393 if (module_table->lookup_only(module_symbol) != NULL) { |
|
394 dupl_modules = true; |
|
395 } |
|
396 break; |
|
397 } |
|
398 } |
|
399 } // if (num_packages > 0)... |
|
400 |
|
401 // Add the module and its packages. |
|
402 if (!dupl_modules && existing_pkg == NULL) { |
|
403 // Create the entry for this module in the class loader's module entry table. |
|
404 ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, |
|
405 (is_open == JNI_TRUE), module_symbol, |
|
406 version_symbol, location_symbol, loader_data); |
|
407 |
|
408 if (module_entry == NULL) { |
|
409 dupl_modules = true; |
|
410 } else { |
|
411 // Add the packages. |
|
412 assert(pkg_list->length() == 0 || package_table != NULL, "Bad package table"); |
|
413 PackageEntry* pkg; |
|
414 for (int y = 0; y < pkg_list->length(); y++) { |
|
415 pkg = package_table->locked_create_entry_or_null(pkg_list->at(y), module_entry); |
|
416 assert(pkg != NULL, "Unable to create a module's package entry"); |
|
417 |
|
418 // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of |
|
419 // the Symbol* that was created above for each package. The refcount was incremented |
|
420 // by SymbolTable::new_symbol and as well by the PackageEntry creation. |
|
421 pkg_list->at(y)->decrement_refcount(); |
|
422 } |
|
423 |
|
424 // Store pointer to ModuleEntry record in java.lang.Module object. |
|
425 java_lang_Module::set_module_entry(module_handle(), module_entry); |
|
426 } |
|
427 } |
|
428 } // Release the lock |
|
429 |
|
430 // any errors ? |
|
431 if (dupl_modules) { |
|
432 THROW_MSG(vmSymbols::java_lang_IllegalStateException(), |
|
433 err_msg("Module %s is already defined", module_name)); |
|
434 } else if (existing_pkg != NULL) { |
|
435 throw_dup_pkg_exception(module_name, existing_pkg, CHECK); |
|
436 } |
|
437 |
|
438 log_info(module, load)("%s location: %s", module_name, |
|
439 module_location != NULL ? module_location : "NULL"); |
|
440 LogTarget(Debug, module) lt; |
|
441 if (lt.is_enabled()) { |
|
442 LogStream ls(lt); |
|
443 ls.print("define_module(): creation of module: %s, version: %s, location: %s, ", |
|
444 module_name, module_version != NULL ? module_version : "NULL", |
|
445 module_location != NULL ? module_location : "NULL"); |
|
446 loader_data->print_value_on(&ls); |
|
447 ls.print_cr(", package #: %d", pkg_list->length()); |
|
448 for (int y = 0; y < pkg_list->length(); y++) { |
|
449 log_trace(module)("define_module(): creation of package %s for module %s", |
|
450 (pkg_list->at(y))->as_C_string(), module_name); |
|
451 } |
|
452 } |
|
453 |
|
454 // If the module is defined to the boot loader and an exploded build is being |
|
455 // used, prepend <java.home>/modules/modules_name to the system boot class path. |
|
456 if (loader == NULL && !ClassLoader::has_jrt_entry()) { |
|
457 ClassLoader::add_to_exploded_build_list(module_symbol, CHECK); |
|
458 } |
|
459 } |
|
460 |
|
461 void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) { |
|
462 ResourceMark rm(THREAD); |
|
463 |
|
464 if (module == NULL) { |
|
465 THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); |
|
466 } |
|
467 Handle module_handle(THREAD, JNIHandles::resolve(module)); |
|
468 if (!java_lang_Module::is_instance(module_handle())) { |
|
469 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
470 "module is not an instance of type java.lang.Module"); |
|
471 } |
|
472 |
|
473 // Ensure that this is an unnamed module |
|
474 oop name = java_lang_Module::name(module_handle()); |
|
475 if (name != NULL) { |
|
476 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
477 "boot loader's unnamed module's java.lang.Module has a name"); |
|
478 } |
|
479 |
|
480 // Validate java_base's loader is the boot loader. |
|
481 oop loader = java_lang_Module::loader(module_handle()); |
|
482 if (loader != NULL) { |
|
483 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
484 "Class loader must be the boot class loader"); |
|
485 } |
|
486 Handle h_loader(THREAD, loader); |
|
487 |
|
488 log_debug(module)("set_bootloader_unnamed_module(): recording unnamed module for boot loader"); |
|
489 |
|
490 // Set java.lang.Module for the boot loader's unnamed module |
|
491 ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data(); |
|
492 ModuleEntry* unnamed_module = boot_loader_data->unnamed_module(); |
|
493 assert(unnamed_module != NULL, "boot loader's unnamed ModuleEntry not defined"); |
|
494 unnamed_module->set_module(boot_loader_data->add_handle(module_handle)); |
|
495 // Store pointer to the ModuleEntry in the unnamed module's java.lang.Module object. |
|
496 java_lang_Module::set_module_entry(module_handle(), unnamed_module); |
|
497 } |
|
498 |
|
499 void Modules::add_module_exports(jobject from_module, const char* package_name, jobject to_module, TRAPS) { |
|
500 if (package_name == NULL) { |
|
501 THROW_MSG(vmSymbols::java_lang_NullPointerException(), |
|
502 "package is null"); |
|
503 } |
|
504 if (from_module == NULL) { |
|
505 THROW_MSG(vmSymbols::java_lang_NullPointerException(), |
|
506 "from_module is null"); |
|
507 } |
|
508 ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK); |
|
509 if (from_module_entry == NULL) { |
|
510 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
511 "from_module cannot be found"); |
|
512 } |
|
513 |
|
514 // All packages in unnamed and open modules are exported by default. |
|
515 if (!from_module_entry->is_named() || from_module_entry->is_open()) return; |
|
516 |
|
517 ModuleEntry* to_module_entry; |
|
518 if (to_module == NULL) { |
|
519 to_module_entry = NULL; // It's an unqualified export. |
|
520 } else { |
|
521 to_module_entry = get_module_entry(to_module, CHECK); |
|
522 if (to_module_entry == NULL) { |
|
523 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
524 "to_module is invalid"); |
|
525 } |
|
526 } |
|
527 |
|
528 PackageEntry *package_entry = get_package_entry(from_module_entry, package_name, CHECK); |
|
529 ResourceMark rm(THREAD); |
|
530 if (package_entry == NULL) { |
|
531 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
532 err_msg("Package %s not found in from_module %s", |
|
533 package_name != NULL ? package_name : "", |
|
534 from_module_entry->name()->as_C_string())); |
|
535 } |
|
536 if (package_entry->module() != from_module_entry) { |
|
537 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
538 err_msg("Package: %s found in module %s, not in from_module: %s", |
|
539 package_entry->name()->as_C_string(), |
|
540 package_entry->module()->name()->as_C_string(), |
|
541 from_module_entry->name()->as_C_string())); |
|
542 } |
|
543 |
|
544 log_debug(module)("add_module_exports(): package %s in module %s is exported to module %s", |
|
545 package_entry->name()->as_C_string(), |
|
546 from_module_entry->name()->as_C_string(), |
|
547 to_module_entry == NULL ? "NULL" : |
|
548 to_module_entry->is_named() ? |
|
549 to_module_entry->name()->as_C_string() : UNNAMED_MODULE); |
|
550 |
|
551 // Do nothing if modules are the same. |
|
552 if (from_module_entry != to_module_entry) { |
|
553 package_entry->set_exported(to_module_entry); |
|
554 } |
|
555 } |
|
556 |
|
557 |
|
558 void Modules::add_module_exports_qualified(jobject from_module, const char* package, |
|
559 jobject to_module, TRAPS) { |
|
560 if (to_module == NULL) { |
|
561 THROW_MSG(vmSymbols::java_lang_NullPointerException(), |
|
562 "to_module is null"); |
|
563 } |
|
564 add_module_exports(from_module, package, to_module, CHECK); |
|
565 } |
|
566 |
|
567 void Modules::add_reads_module(jobject from_module, jobject to_module, TRAPS) { |
|
568 if (from_module == NULL) { |
|
569 THROW_MSG(vmSymbols::java_lang_NullPointerException(), |
|
570 "from_module is null"); |
|
571 } |
|
572 |
|
573 ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK); |
|
574 if (from_module_entry == NULL) { |
|
575 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
576 "from_module is not valid"); |
|
577 } |
|
578 |
|
579 ModuleEntry* to_module_entry; |
|
580 if (to_module != NULL) { |
|
581 to_module_entry = get_module_entry(to_module, CHECK); |
|
582 if (to_module_entry == NULL) { |
|
583 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
584 "to_module is invalid"); |
|
585 } |
|
586 } else { |
|
587 to_module_entry = NULL; |
|
588 } |
|
589 |
|
590 ResourceMark rm(THREAD); |
|
591 log_debug(module)("add_reads_module(): Adding read from module %s to module %s", |
|
592 from_module_entry->is_named() ? |
|
593 from_module_entry->name()->as_C_string() : UNNAMED_MODULE, |
|
594 to_module_entry == NULL ? "all unnamed" : |
|
595 (to_module_entry->is_named() ? |
|
596 to_module_entry->name()->as_C_string() : UNNAMED_MODULE)); |
|
597 |
|
598 // if modules are the same or if from_module is unnamed then no need to add the read. |
|
599 if (from_module_entry != to_module_entry && from_module_entry->is_named()) { |
|
600 from_module_entry->add_read(to_module_entry); |
|
601 } |
|
602 } |
|
603 |
|
604 // This method is called by JFR and JNI. |
|
605 jobject Modules::get_module(jclass clazz, TRAPS) { |
|
606 assert(ModuleEntryTable::javabase_defined(), |
|
607 "Attempt to call get_module before " JAVA_BASE_NAME " is defined"); |
|
608 |
|
609 if (clazz == NULL) { |
|
610 THROW_MSG_(vmSymbols::java_lang_NullPointerException(), |
|
611 "class is null", JNI_FALSE); |
|
612 } |
|
613 oop mirror = JNIHandles::resolve_non_null(clazz); |
|
614 if (mirror == NULL) { |
|
615 log_debug(module)("get_module(): no mirror, returning NULL"); |
|
616 return NULL; |
|
617 } |
|
618 if (!java_lang_Class::is_instance(mirror)) { |
|
619 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), |
|
620 "Invalid class", JNI_FALSE); |
|
621 } |
|
622 |
|
623 oop module = java_lang_Class::module(mirror); |
|
624 |
|
625 assert(module != NULL, "java.lang.Class module field not set"); |
|
626 assert(java_lang_Module::is_instance(module), "module is not an instance of type java.lang.Module"); |
|
627 |
|
628 LogTarget(Debug,module) lt; |
|
629 if (lt.is_enabled()) { |
|
630 ResourceMark rm(THREAD); |
|
631 LogStream ls(lt); |
|
632 Klass* klass = java_lang_Class::as_Klass(mirror); |
|
633 oop module_name = java_lang_Module::name(module); |
|
634 if (module_name != NULL) { |
|
635 ls.print("get_module(): module "); |
|
636 java_lang_String::print(module_name, tty); |
|
637 } else { |
|
638 ls.print("get_module(): Unamed Module"); |
|
639 } |
|
640 if (klass != NULL) { |
|
641 ls.print_cr(" for class %s", klass->external_name()); |
|
642 } else { |
|
643 ls.print_cr(" for primitive class"); |
|
644 } |
|
645 } |
|
646 |
|
647 return JNIHandles::make_local(THREAD, module); |
|
648 } |
|
649 |
|
650 jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRAPS) { |
|
651 assert(ModuleEntryTable::javabase_defined(), |
|
652 "Attempt to call get_named_module before " JAVA_BASE_NAME " is defined"); |
|
653 assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()), |
|
654 "Class loader is not a subclass of java.lang.ClassLoader"); |
|
655 assert(package_name != NULL, "the package_name should not be NULL"); |
|
656 |
|
657 if (strlen(package_name) == 0) { |
|
658 return NULL; |
|
659 } |
|
660 TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL); |
|
661 const PackageEntry* const pkg_entry = |
|
662 get_package_entry_by_name(package_sym, h_loader, THREAD); |
|
663 const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL); |
|
664 |
|
665 if (module_entry != NULL && module_entry->module() != NULL && module_entry->is_named()) { |
|
666 return JNIHandles::make_local(THREAD, module_entry->module()); |
|
667 } |
|
668 return NULL; |
|
669 } |
|
670 |
|
671 |
|
672 // This method is called by JFR and by the above method. |
|
673 jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) { |
|
674 const PackageEntry* const pkg_entry = |
|
675 get_package_entry_by_name(package_name, h_loader, THREAD); |
|
676 const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL); |
|
677 |
|
678 if (module_entry != NULL && |
|
679 module_entry->module() != NULL) { |
|
680 return JNIHandles::make_local(THREAD, module_entry->module()); |
|
681 } |
|
682 |
|
683 return NULL; |
|
684 } |
|
685 |
|
686 // Export package in module to all unnamed modules. |
|
687 void Modules::add_module_exports_to_all_unnamed(jobject module, const char* package_name, TRAPS) { |
|
688 if (module == NULL) { |
|
689 THROW_MSG(vmSymbols::java_lang_NullPointerException(), |
|
690 "module is null"); |
|
691 } |
|
692 if (package_name == NULL) { |
|
693 THROW_MSG(vmSymbols::java_lang_NullPointerException(), |
|
694 "package is null"); |
|
695 } |
|
696 ModuleEntry* module_entry = get_module_entry(module, CHECK); |
|
697 if (module_entry == NULL) { |
|
698 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
699 "module is invalid"); |
|
700 } |
|
701 |
|
702 if (module_entry->is_named()) { // No-op for unnamed module. |
|
703 PackageEntry *package_entry = get_package_entry(module_entry, package_name, CHECK); |
|
704 ResourceMark rm(THREAD); |
|
705 if (package_entry == NULL) { |
|
706 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
707 err_msg("Package %s not found in module %s", |
|
708 package_name != NULL ? package_name : "", |
|
709 module_entry->name()->as_C_string())); |
|
710 } |
|
711 if (package_entry->module() != module_entry) { |
|
712 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
|
713 err_msg("Package: %s found in module %s, not in module: %s", |
|
714 package_entry->name()->as_C_string(), |
|
715 package_entry->module()->name()->as_C_string(), |
|
716 module_entry->name()->as_C_string())); |
|
717 } |
|
718 |
|
719 log_debug(module)("add_module_exports_to_all_unnamed(): package %s in module" |
|
720 " %s is exported to all unnamed modules", |
|
721 package_entry->name()->as_C_string(), |
|
722 module_entry->name()->as_C_string()); |
|
723 |
|
724 // Mark package as exported to all unnamed modules. |
|
725 package_entry->set_is_exported_allUnnamed(); |
|
726 } |
|
727 } |