1 | /* |
2 | * Copyright (c) 2016, 2019, 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 "jvm.h" |
27 | #include "classfile/classFileParser.hpp" |
28 | #include "classfile/classLoader.hpp" |
29 | #include "classfile/classLoaderData.inline.hpp" |
30 | #include "classfile/javaAssertions.hpp" |
31 | #include "classfile/javaClasses.hpp" |
32 | #include "classfile/javaClasses.inline.hpp" |
33 | #include "classfile/moduleEntry.hpp" |
34 | #include "classfile/modules.hpp" |
35 | #include "classfile/packageEntry.hpp" |
36 | #include "classfile/stringTable.hpp" |
37 | #include "classfile/symbolTable.hpp" |
38 | #include "classfile/systemDictionary.hpp" |
39 | #include "classfile/vmSymbols.hpp" |
40 | #include "logging/log.hpp" |
41 | #include "logging/logStream.hpp" |
42 | #include "memory/resourceArea.hpp" |
43 | #include "oops/instanceKlass.hpp" |
44 | #include "runtime/arguments.hpp" |
45 | #include "runtime/handles.inline.hpp" |
46 | #include "runtime/javaCalls.hpp" |
47 | #include "runtime/jniHandles.inline.hpp" |
48 | #include "runtime/reflection.hpp" |
49 | #include "utilities/stringUtils.hpp" |
50 | #include "utilities/utf8.hpp" |
51 | |
52 | static bool verify_module_name(const char *module_name) { |
53 | if (module_name == NULL) return false; |
54 | int len = (int)strlen(module_name); |
55 | return (len > 0 && len <= Symbol::max_length()); |
56 | } |
57 | |
58 | bool Modules::verify_package_name(const char* package_name) { |
59 | if (package_name == NULL) return false; |
60 | int len = (int)strlen(package_name); |
61 | return (len > 0 && len <= Symbol::max_length() && |
62 | UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) && |
63 | ClassFileParser::verify_unqualified_name(package_name, len, |
64 | ClassFileParser::LegalClass)); |
65 | } |
66 | |
67 | static char* get_module_name(oop module, TRAPS) { |
68 | oop name_oop = java_lang_Module::name(module); |
69 | if (name_oop == NULL) { |
70 | THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), "Null module name" ); |
71 | } |
72 | char* module_name = java_lang_String::as_utf8_string(name_oop); |
73 | if (!verify_module_name(module_name)) { |
74 | THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), |
75 | err_msg("Invalid module name: %s" , |
76 | module_name != NULL ? module_name : "NULL" )); |
77 | } |
78 | return module_name; |
79 | } |
80 | |
81 | static const char* get_module_version(jstring version) { |
82 | if (version == NULL) { |
83 | return NULL; |
84 | } |
85 | return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version)); |
86 | } |
87 | |
88 | ModuleEntryTable* Modules::get_module_entry_table(Handle h_loader) { |
89 | // This code can be called during start-up, before the classLoader's classLoader data got |
90 | // created. So, call register_loader() to make sure the classLoader data gets created. |
91 | ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader); |
92 | return loader_cld->modules(); |
93 | } |
94 | |
95 | static PackageEntryTable* get_package_entry_table(Handle h_loader) { |
96 | // This code can be called during start-up, before the classLoader's classLoader data got |
97 | // created. So, call register_loader() to make sure the classLoader data gets created. |
98 | ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader); |
99 | return loader_cld->packages(); |
100 | } |
101 | |
102 | static ModuleEntry* get_module_entry(jobject module, TRAPS) { |
103 | oop m = JNIHandles::resolve(module); |
104 | if (!java_lang_Module::is_instance(m)) { |
105 | THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), |
106 | "module is not an instance of type java.lang.Module" ); |
107 | } |
108 | return java_lang_Module::module_entry(m); |
109 | } |
110 | |
111 | static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) { |
112 | ResourceMark rm(THREAD); |
113 | if (package_name == NULL) return NULL; |
114 | TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name); |
115 | PackageEntryTable* package_entry_table = module_entry->loader_data()->packages(); |
116 | assert(package_entry_table != NULL, "Unexpected null package entry table" ); |
117 | return package_entry_table->lookup_only(pkg_symbol); |
118 | } |
119 | |
120 | static PackageEntry* get_package_entry_by_name(Symbol* package, |
121 | Handle h_loader, |
122 | TRAPS) { |
123 | if (package != NULL) { |
124 | ResourceMark rm(THREAD); |
125 | if (Modules::verify_package_name(package->as_C_string())) { |
126 | PackageEntryTable* const package_entry_table = |
127 | get_package_entry_table(h_loader); |
128 | assert(package_entry_table != NULL, "Unexpected null package entry table" ); |
129 | return package_entry_table->lookup_only(package); |
130 | } |
131 | } |
132 | return NULL; |
133 | } |
134 | |
135 | bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) { |
136 | PackageEntry* res = get_package_entry_by_name(package, h_loader, CHECK_false); |
137 | return res != NULL; |
138 | } |
139 | |
140 | static void define_javabase_module(jobject module, jstring version, |
141 | jstring location, const char* const* packages, |
142 | jsize num_packages, TRAPS) { |
143 | ResourceMark rm(THREAD); |
144 | |
145 | Handle module_handle(THREAD, JNIHandles::resolve(module)); |
146 | |
147 | // Obtain java.base's module version |
148 | const char* module_version = get_module_version(version); |
149 | TempNewSymbol version_symbol; |
150 | if (module_version != NULL) { |
151 | version_symbol = SymbolTable::new_symbol(module_version); |
152 | } else { |
153 | version_symbol = NULL; |
154 | } |
155 | |
156 | // Obtain java.base's location |
157 | const char* module_location = NULL; |
158 | TempNewSymbol location_symbol = NULL; |
159 | if (location != NULL) { |
160 | module_location = |
161 | java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); |
162 | if (module_location != NULL) { |
163 | location_symbol = SymbolTable::new_symbol(module_location); |
164 | } |
165 | } |
166 | |
167 | |
168 | // Check that the packages are syntactically ok. |
169 | GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages); |
170 | for (int x = 0; x < num_packages; x++) { |
171 | const char *package_name = packages[x]; |
172 | if (!Modules::verify_package_name(package_name)) { |
173 | THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
174 | err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name)); |
175 | } |
176 | Symbol* pkg_symbol = SymbolTable::new_symbol(package_name); |
177 | pkg_list->append(pkg_symbol); |
178 | } |
179 | |
180 | // Validate java_base's loader is the boot loader. |
181 | oop loader = java_lang_Module::loader(module_handle()); |
182 | if (loader != NULL) { |
183 | THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
184 | "Class loader must be the boot class loader" ); |
185 | } |
186 | Handle h_loader(THREAD, loader); |
187 | |
188 | // Ensure the boot loader's PackageEntryTable has been created |
189 | PackageEntryTable* package_table = get_package_entry_table(h_loader); |
190 | assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table" ); |
191 | |
192 | // Ensure java.base's ModuleEntry has been created |
193 | assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for " JAVA_BASE_NAME); |
194 | |
195 | bool duplicate_javabase = false; |
196 | { |
197 | MutexLocker m1(Module_lock, THREAD); |
198 | |
199 | if (ModuleEntryTable::javabase_defined()) { |
200 | duplicate_javabase = true; |
201 | } else { |
202 | |
203 | // Verify that all java.base packages created during bootstrapping are in |
204 | // pkg_list. If any are not in pkg_list, than a non-java.base class was |
205 | // loaded erroneously pre java.base module definition. |
206 | package_table->verify_javabase_packages(pkg_list); |
207 | |
208 | // loop through and add any new packages for java.base |
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 | package_table->locked_create_entry_if_not_exist(pkg_list->at(x), |
212 | ModuleEntryTable::javabase_moduleEntry()); |
213 | assert(package_table->locked_lookup_only(pkg_list->at(x)) != NULL, |
214 | "Unable to create a " JAVA_BASE_NAME " package entry" ); |
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 (!oopDesc::equals(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 | // define_module can be called during start-up, before the class loader's ClassLoaderData |
315 | // has been created. SystemDictionary::register_loader ensures creation, if needed. |
316 | ClassLoaderData* loader_data = SystemDictionary::register_loader(h_loader); |
317 | assert(loader_data != NULL, "class loader data shouldn't be null" ); |
318 | |
319 | // Check that the list of packages has no duplicates and that the |
320 | // packages are syntactically ok. |
321 | GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages); |
322 | for (int x = 0; x < num_packages; x++) { |
323 | const char* package_name = packages[x]; |
324 | if (!verify_package_name(package_name)) { |
325 | THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
326 | err_msg("Invalid package name: %s for module: %s" , |
327 | package_name, module_name)); |
328 | } |
329 | |
330 | // Only modules defined to either the boot or platform class loader, can define a "java/" package. |
331 | if (!h_loader.is_null() && |
332 | !SystemDictionary::is_platform_class_loader(h_loader()) && |
333 | (strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0 && |
334 | (package_name[JAVAPKG_LEN] == '/' || package_name[JAVAPKG_LEN] == '\0'))) { |
335 | const char* class_loader_name = loader_data->loader_name_and_id(); |
336 | size_t pkg_len = strlen(package_name); |
337 | char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len + 1); |
338 | strncpy(pkg_name, package_name, pkg_len + 1); |
339 | StringUtils::replace_no_expand(pkg_name, "/" , "." ); |
340 | const char* msg_text1 = "Class loader (instance of): " ; |
341 | const char* msg_text2 = " tried to define prohibited package name: " ; |
342 | size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1; |
343 | char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); |
344 | jio_snprintf(message, len, "%s%s%s%s" , msg_text1, class_loader_name, msg_text2, pkg_name); |
345 | THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message); |
346 | } |
347 | |
348 | Symbol* pkg_symbol = SymbolTable::new_symbol(package_name); |
349 | pkg_list->append(pkg_symbol); |
350 | } |
351 | |
352 | ModuleEntryTable* module_table = get_module_entry_table(h_loader); |
353 | assert(module_table != NULL, "module entry table shouldn't be null" ); |
354 | |
355 | // Create symbol* entry for module name. |
356 | TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name); |
357 | |
358 | bool dupl_modules = false; |
359 | |
360 | // Create symbol* entry for module version. |
361 | TempNewSymbol version_symbol; |
362 | if (module_version != NULL) { |
363 | version_symbol = SymbolTable::new_symbol(module_version); |
364 | } else { |
365 | version_symbol = NULL; |
366 | } |
367 | |
368 | // Create symbol* entry for module location. |
369 | const char* module_location = NULL; |
370 | TempNewSymbol location_symbol = NULL; |
371 | if (location != NULL) { |
372 | module_location = |
373 | java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); |
374 | if (module_location != NULL) { |
375 | location_symbol = SymbolTable::new_symbol(module_location); |
376 | } |
377 | } |
378 | |
379 | PackageEntryTable* package_table = NULL; |
380 | PackageEntry* existing_pkg = NULL; |
381 | { |
382 | MutexLocker ml(Module_lock, THREAD); |
383 | |
384 | if (num_packages > 0) { |
385 | package_table = get_package_entry_table(h_loader); |
386 | assert(package_table != NULL, "Missing package_table" ); |
387 | |
388 | // Check that none of the packages exist in the class loader's package table. |
389 | for (int x = 0; x < pkg_list->length(); x++) { |
390 | existing_pkg = package_table->locked_lookup_only(pkg_list->at(x)); |
391 | if (existing_pkg != NULL) { |
392 | // This could be because the module was already defined. If so, |
393 | // report that error instead of the package error. |
394 | if (module_table->lookup_only(module_symbol) != NULL) { |
395 | dupl_modules = true; |
396 | } |
397 | break; |
398 | } |
399 | } |
400 | } // if (num_packages > 0)... |
401 | |
402 | // Add the module and its packages. |
403 | if (!dupl_modules && existing_pkg == NULL) { |
404 | if (module_table->lookup_only(module_symbol) == NULL) { |
405 | // Create the entry for this module in the class loader's module entry table. |
406 | ModuleEntry* module_entry = module_table->locked_create_entry(module_handle, |
407 | (is_open == JNI_TRUE), module_symbol, |
408 | version_symbol, location_symbol, loader_data); |
409 | assert(module_entry != NULL, "module_entry creation failed" ); |
410 | |
411 | // Add the packages. |
412 | assert(pkg_list->length() == 0 || package_table != NULL, "Bad package table" ); |
413 | for (int y = 0; y < pkg_list->length(); y++) { |
414 | package_table->locked_create_entry(pkg_list->at(y), module_entry); |
415 | |
416 | // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of |
417 | // the Symbol* that was created above for each package. The refcount was incremented |
418 | // by SymbolTable::new_symbol and as well by the PackageEntry creation. |
419 | pkg_list->at(y)->decrement_refcount(); |
420 | } |
421 | |
422 | // Store pointer to ModuleEntry record in java.lang.Module object. |
423 | java_lang_Module::set_module_entry(module_handle(), module_entry); |
424 | } else { |
425 | dupl_modules = true; |
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); |
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 | } |
728 | |