20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.io.InputStream; 29 import java.io.IOException; 30 import java.io.UncheckedIOException; 31 import java.io.File; 32 import java.lang.reflect.Constructor; 33 import java.net.URL; 34 import java.security.AccessController; 35 import java.security.AccessControlContext; 36 import java.security.CodeSource; 37 import java.security.PrivilegedAction; 38 import java.security.ProtectionDomain; 39 import java.security.cert.Certificate; 40 import java.util.Collections; 41 import java.util.Enumeration; 42 import java.util.HashMap; 43 import java.util.Hashtable; 44 import java.util.Map; 45 import java.util.NoSuchElementException; 46 import java.util.Objects; 47 import java.util.Set; 48 import java.util.Spliterator; 49 import java.util.Spliterators; 50 import java.util.Stack; 51 import java.util.Vector; 52 import java.util.WeakHashMap; 53 import java.util.concurrent.ConcurrentHashMap; 54 import java.util.function.Supplier; 55 import java.util.stream.Stream; 56 import java.util.stream.StreamSupport; 57 58 import jdk.internal.perf.PerfCounter; 59 import jdk.internal.loader.BootLoader; 60 import jdk.internal.loader.ClassLoaders; 61 import jdk.internal.misc.SharedSecrets; 62 import jdk.internal.misc.Unsafe; 63 import jdk.internal.misc.VM; 64 import jdk.internal.reflect.CallerSensitive; 65 import jdk.internal.reflect.Reflection; 66 import sun.reflect.misc.ReflectUtil; 67 import sun.security.util.SecurityConstants; 68 69 /** 70 * A class loader is an object that is responsible for loading classes. The 71 * class {@code ClassLoader} is an abstract class. Given the <a 72 * href="#name">binary name</a> of a class, a class loader should attempt to 73 * locate or generate data that constitutes a definition for the class. A 74 * typical strategy is to transform the name into a file name and then read a 75 * "class file" of that name from a file system. 76 * 77 * <p> Every {@link java.lang.Class Class} object contains a {@link 78 * Class#getClassLoader() reference} to the {@code ClassLoader} that defined 79 * it. 80 * 81 * <p> {@code Class} objects for array classes are not created by class 82 * loaders, but are created automatically as required by the Java runtime. 83 * The class loader for an array class, as returned by {@link 2358 protected String findLibrary(String libname) { 2359 return null; 2360 } 2361 2362 /** 2363 * The inner class NativeLibrary denotes a loaded native library instance. 2364 * Every classloader contains a vector of loaded native libraries in the 2365 * private field {@code nativeLibraries}. The native libraries loaded 2366 * into the system are entered into the {@code systemNativeLibraries} 2367 * vector. 2368 * 2369 * <p> Every native library requires a particular version of JNI. This is 2370 * denoted by the private {@code jniVersion} field. This field is set by 2371 * the VM when it loads the library, and used by the VM to pass the correct 2372 * version of JNI to the native methods. </p> 2373 * 2374 * @see ClassLoader 2375 * @since 1.2 2376 */ 2377 static class NativeLibrary { 2378 // opaque handle to native library, used in native code. 2379 long handle; 2380 // the version of JNI environment the native library requires. 2381 private int jniVersion; 2382 // the class from which the library is loaded, also indicates 2383 // the loader this native library belongs. 2384 private final Class<?> fromClass; 2385 // the canonicalized name of the native library. 2386 // or static library name 2387 String name; 2388 // Indicates if the native library is linked into the VM 2389 boolean isBuiltin; 2390 // Indicates if the native library is loaded 2391 boolean loaded; 2392 native void load(String name, boolean isBuiltin); 2393 2394 native long find(String name); 2395 native void unload(String name, boolean isBuiltin); 2396 2397 public NativeLibrary(Class<?> fromClass, String name, boolean isBuiltin) { 2398 this.name = name; 2399 this.fromClass = fromClass; 2400 this.isBuiltin = isBuiltin; 2401 } 2402 2403 @SuppressWarnings("deprecation") 2404 protected void finalize() { 2405 synchronized (loadedLibraryNames) { 2406 if (fromClass.getClassLoader() != null && loaded) { 2407 /* remove the native library name */ 2408 int size = loadedLibraryNames.size(); 2409 for (int i = 0; i < size; i++) { 2410 if (name.equals(loadedLibraryNames.elementAt(i))) { 2411 loadedLibraryNames.removeElementAt(i); 2412 break; 2413 } 2414 } 2415 /* unload the library. */ 2416 ClassLoader.nativeLibraryContext.push(this); 2417 try { 2418 unload(name, isBuiltin); 2419 } finally { 2420 ClassLoader.nativeLibraryContext.pop(); 2421 } 2422 } 2423 } 2424 } 2425 // Invoked in the VM to determine the context class in 2426 // JNI_Load/JNI_Unload 2427 static Class<?> getFromClass() { 2428 return ClassLoader.nativeLibraryContext.peek().fromClass; 2429 } 2430 } 2431 2432 // All native library names we've loaded. 2433 private static Vector<String> loadedLibraryNames = new Vector<>(); 2434 2435 // Native libraries belonging to system classes. 2436 private static Vector<NativeLibrary> systemNativeLibraries 2437 = new Vector<>(); 2438 2439 // Native libraries associated with the class loader. 2440 private Vector<NativeLibrary> nativeLibraries = new Vector<>(); 2441 2442 // native libraries being loaded/unloaded. 2443 private static Stack<NativeLibrary> nativeLibraryContext = new Stack<>(); 2444 2445 // The paths searched for libraries 2446 private static String usr_paths[]; 2447 private static String sys_paths[]; 2448 2449 private static String[] initializePath(String propName) { 2450 String ldPath = System.getProperty(propName, ""); 2451 int ldLen = ldPath.length(); 2452 char ps = File.pathSeparatorChar; 2453 int psCount = 0; 2454 2455 if (ClassLoaderHelper.allowsQuotedPathElements && 2456 ldPath.indexOf('\"') >= 0) { 2457 // First, remove quotes put around quoted parts of paths. 2458 // Second, use a quotation mark as a new path separator. 2459 // This will preserve any quoted old path separators. 2460 char[] buf = new char[ldLen]; 2461 int bufLen = 0; 2462 for (int i = 0; i < ldLen; ++i) { 2463 char ch = ldPath.charAt(i); 2532 return; 2533 } 2534 libfile = ClassLoaderHelper.mapAlternativeName(libfile); 2535 if (libfile != null && loadLibrary0(fromClass, libfile)) { 2536 return; 2537 } 2538 } 2539 if (loader != null) { 2540 for (String usr_path : usr_paths) { 2541 File libfile = new File(usr_path, System.mapLibraryName(name)); 2542 if (loadLibrary0(fromClass, libfile)) { 2543 return; 2544 } 2545 libfile = ClassLoaderHelper.mapAlternativeName(libfile); 2546 if (libfile != null && loadLibrary0(fromClass, libfile)) { 2547 return; 2548 } 2549 } 2550 } 2551 // Oops, it failed 2552 throw new UnsatisfiedLinkError("no " + name + " in java.library.path"); 2553 } 2554 2555 static native String findBuiltinLib(String name); 2556 2557 private static boolean loadLibrary0(Class<?> fromClass, final File file) { 2558 // Check to see if we're attempting to access a static library 2559 String name = findBuiltinLib(file.getName()); 2560 boolean isBuiltin = (name != null); 2561 if (!isBuiltin) { 2562 name = AccessController.doPrivileged( 2563 new PrivilegedAction<>() { 2564 public String run() { 2565 try { 2566 return file.exists() ? file.getCanonicalPath() : null; 2567 } catch (IOException e) { 2568 return null; 2569 } 2570 } 2571 }); 2572 if (name == null) { 2573 return false; 2574 } 2575 } 2576 ClassLoader loader = 2577 (fromClass == null) ? null : fromClass.getClassLoader(); 2578 Vector<NativeLibrary> libs = 2579 loader != null ? loader.nativeLibraries : systemNativeLibraries; 2580 synchronized (libs) { 2581 int size = libs.size(); 2582 for (int i = 0; i < size; i++) { 2583 NativeLibrary lib = libs.elementAt(i); 2584 if (name.equals(lib.name)) { 2585 return true; 2586 } 2587 } 2588 2589 synchronized (loadedLibraryNames) { 2590 if (loadedLibraryNames.contains(name)) { 2591 throw new UnsatisfiedLinkError 2592 ("Native Library " + 2593 name + 2594 " already loaded in another classloader"); 2595 } 2596 /* If the library is being loaded (must be by the same thread, 2597 * because Runtime.load and Runtime.loadLibrary are 2598 * synchronous). The reason is can occur is that the JNI_OnLoad 2599 * function can cause another loadLibrary invocation. 2600 * 2601 * Thus we can use a static stack to hold the list of libraries 2602 * we are loading. 2603 * 2604 * If there is a pending load operation for the library, we 2605 * immediately return success; otherwise, we raise 2606 * UnsatisfiedLinkError. 2607 */ 2608 int n = nativeLibraryContext.size(); 2609 for (int i = 0; i < n; i++) { 2610 NativeLibrary lib = nativeLibraryContext.elementAt(i); 2611 if (name.equals(lib.name)) { 2612 if (loader == lib.fromClass.getClassLoader()) { 2613 return true; 2614 } else { 2615 throw new UnsatisfiedLinkError 2616 ("Native Library " + 2617 name + 2618 " is being loaded in another classloader"); 2619 } 2620 } 2621 } 2622 NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin); 2623 nativeLibraryContext.push(lib); 2624 try { 2625 lib.load(name, isBuiltin); 2626 } finally { 2627 nativeLibraryContext.pop(); 2628 } 2629 if (lib.loaded) { 2630 loadedLibraryNames.addElement(name); 2631 libs.addElement(lib); 2632 return true; 2633 } 2634 return false; 2635 } 2636 } 2637 } 2638 2639 // Invoked in the VM class linking code. 2640 static long findNative(ClassLoader loader, String name) { 2641 Vector<NativeLibrary> libs = 2642 loader != null ? loader.nativeLibraries : systemNativeLibraries; 2643 synchronized (libs) { 2644 int size = libs.size(); 2645 for (int i = 0; i < size; i++) { 2646 NativeLibrary lib = libs.elementAt(i); 2647 long entry = lib.find(name); 2648 if (entry != 0) 2649 return entry; 2650 } 2651 } 2652 return 0; 2653 } 2654 2655 2656 // -- Assertion management -- 2657 2658 final Object assertionLock; 2659 2660 // The default toggle for assertion checking. 2661 // @GuardedBy("assertionLock") 2662 private boolean defaultAssertionStatus = false; 2663 2664 // Maps String packageName to Boolean package default assertion status Note 2665 // that the default package is placed under a null map key. If this field 2666 // is null then we are delegating assertion status queries to the VM, i.e., 2667 // none of this ClassLoader's assertion status modification methods have 2668 // been invoked. 2669 // @GuardedBy("assertionLock") 2670 private Map<String, Boolean> packageAssertionStatus = null; 2671 2672 // Maps String fullyQualifiedClassName to Boolean assertionStatus If this 2673 // field is null then we are delegating assertion status queries to the VM, 2674 // i.e., none of this ClassLoader's assertion status modification methods | 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.io.InputStream; 29 import java.io.IOException; 30 import java.io.UncheckedIOException; 31 import java.io.File; 32 import java.lang.reflect.Constructor; 33 import java.net.URL; 34 import java.security.AccessController; 35 import java.security.AccessControlContext; 36 import java.security.CodeSource; 37 import java.security.PrivilegedAction; 38 import java.security.ProtectionDomain; 39 import java.security.cert.Certificate; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.Deque; 43 import java.util.Enumeration; 44 import java.util.HashMap; 45 import java.util.HashSet; 46 import java.util.Hashtable; 47 import java.util.LinkedList; 48 import java.util.Map; 49 import java.util.NoSuchElementException; 50 import java.util.Objects; 51 import java.util.Set; 52 import java.util.Spliterator; 53 import java.util.Spliterators; 54 import java.util.Vector; 55 import java.util.WeakHashMap; 56 import java.util.concurrent.ConcurrentHashMap; 57 import java.util.function.Supplier; 58 import java.util.stream.Stream; 59 import java.util.stream.StreamSupport; 60 61 import jdk.internal.perf.PerfCounter; 62 import jdk.internal.loader.BootLoader; 63 import jdk.internal.loader.ClassLoaders; 64 import jdk.internal.misc.Unsafe; 65 import jdk.internal.misc.VM; 66 import jdk.internal.ref.CleanerFactory; 67 import jdk.internal.reflect.CallerSensitive; 68 import jdk.internal.reflect.Reflection; 69 import sun.reflect.misc.ReflectUtil; 70 import sun.security.util.SecurityConstants; 71 72 /** 73 * A class loader is an object that is responsible for loading classes. The 74 * class {@code ClassLoader} is an abstract class. Given the <a 75 * href="#name">binary name</a> of a class, a class loader should attempt to 76 * locate or generate data that constitutes a definition for the class. A 77 * typical strategy is to transform the name into a file name and then read a 78 * "class file" of that name from a file system. 79 * 80 * <p> Every {@link java.lang.Class Class} object contains a {@link 81 * Class#getClassLoader() reference} to the {@code ClassLoader} that defined 82 * it. 83 * 84 * <p> {@code Class} objects for array classes are not created by class 85 * loaders, but are created automatically as required by the Java runtime. 86 * The class loader for an array class, as returned by {@link 2361 protected String findLibrary(String libname) { 2362 return null; 2363 } 2364 2365 /** 2366 * The inner class NativeLibrary denotes a loaded native library instance. 2367 * Every classloader contains a vector of loaded native libraries in the 2368 * private field {@code nativeLibraries}. The native libraries loaded 2369 * into the system are entered into the {@code systemNativeLibraries} 2370 * vector. 2371 * 2372 * <p> Every native library requires a particular version of JNI. This is 2373 * denoted by the private {@code jniVersion} field. This field is set by 2374 * the VM when it loads the library, and used by the VM to pass the correct 2375 * version of JNI to the native methods. </p> 2376 * 2377 * @see ClassLoader 2378 * @since 1.2 2379 */ 2380 static class NativeLibrary { 2381 // the class from which the library is loaded, also indicates 2382 // the loader this native library belongs. 2383 final Class<?> fromClass; 2384 // the canonicalized name of the native library. 2385 // or static library name 2386 final String name; 2387 // Indicates if the native library is linked into the VM 2388 final boolean isBuiltin; 2389 2390 // opaque handle to native library, used in native code. 2391 long handle; 2392 // the version of JNI environment the native library requires. 2393 int jniVersion; 2394 2395 native boolean load0(String name, boolean isBuiltin); 2396 2397 native long findEntry(String name); 2398 2399 NativeLibrary(Class<?> fromClass, String name, boolean isBuiltin) { 2400 this.name = name; 2401 this.fromClass = fromClass; 2402 this.isBuiltin = isBuiltin; 2403 } 2404 2405 /* 2406 * Loads the native library and registers for cleanup when its 2407 * associated class loader is unloaded 2408 */ 2409 boolean load() { 2410 if (handle != 0) { 2411 throw new InternalError("Native library " + name + " has been loaded"); 2412 } 2413 2414 if (!load0(name, isBuiltin)) return false; 2415 2416 // register the class loader for cleanup when unloaded 2417 // built class loaders are never unloaded 2418 ClassLoader loader = fromClass.getClassLoader(); 2419 if (loader != null && 2420 loader != getBuiltinPlatformClassLoader() && 2421 loader != getBuiltinAppClassLoader()) { 2422 CleanerFactory.cleaner().register(loader, 2423 new Unloader(name, handle, isBuiltin)); 2424 } 2425 return true; 2426 } 2427 2428 static boolean loadLibrary(Class<?> fromClass, String name, boolean isBuiltin) { 2429 ClassLoader loader = 2430 fromClass == null ? null : fromClass.getClassLoader(); 2431 2432 synchronized (loadedLibraryNames) { 2433 Map<String, NativeLibrary> libs = 2434 loader != null ? loader.nativeLibraries() : systemNativeLibraries(); 2435 if (libs.containsKey(name)) { 2436 return true; 2437 } 2438 2439 if (loadedLibraryNames.contains(name)) { 2440 throw new UnsatisfiedLinkError("Native Library " + name + 2441 " already loaded in another classloader"); 2442 } 2443 2444 /* 2445 * When a library is being loaded, JNI_OnLoad function can cause 2446 * another loadLibrary invocation that should succeed. 2447 * 2448 * We use a static stack to hold the list of libraries we are 2449 * loading because this can happen only when called by the 2450 * same thread because Runtime.load and Runtime.loadLibrary 2451 * are synchronous. 2452 * 2453 * If there is a pending load operation for the library, we 2454 * immediately return success; otherwise, we raise 2455 * UnsatisfiedLinkError. 2456 */ 2457 for (NativeLibrary lib : nativeLibraryContext) { 2458 if (name.equals(lib.name)) { 2459 if (loader == lib.fromClass.getClassLoader()) { 2460 return true; 2461 } else { 2462 throw new UnsatisfiedLinkError("Native Library " + 2463 name + " is being loaded in another classloader"); 2464 } 2465 } 2466 } 2467 NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin); 2468 // load the native library 2469 nativeLibraryContext.push(lib); 2470 try { 2471 if (!lib.load()) return false; 2472 } finally { 2473 nativeLibraryContext.pop(); 2474 } 2475 // register the loaded native library 2476 loadedLibraryNames.add(name); 2477 libs.put(name, lib); 2478 } 2479 return true; 2480 } 2481 2482 // Invoked in the VM to determine the context class in JNI_OnLoad 2483 // and JNI_OnUnload 2484 static Class<?> getFromClass() { 2485 return nativeLibraryContext.peek().fromClass; 2486 } 2487 2488 // native libraries being loaded 2489 static Deque<NativeLibrary> nativeLibraryContext = new LinkedList<>(); 2490 2491 /* 2492 * The run() method will be invoked when this class loader becomes 2493 * phantom reachable to unload the native library. 2494 */ 2495 static class Unloader implements Runnable { 2496 // This represents the context when a native library is unloaded 2497 // and getFromClass() will return null, 2498 static final NativeLibrary UNLOADER = 2499 new NativeLibrary(null, "dummy", false); 2500 final String name; 2501 final long handle; 2502 final boolean isBuiltin; 2503 2504 Unloader(String name, long handle, boolean isBuiltin) { 2505 if (handle == 0) { 2506 throw new IllegalArgumentException( 2507 "Invalid handle for native library " + name); 2508 } 2509 2510 this.name = name; 2511 this.handle = handle; 2512 this.isBuiltin = isBuiltin; 2513 } 2514 2515 @Override 2516 public void run() { 2517 synchronized (loadedLibraryNames) { 2518 /* remove the native library name */ 2519 loadedLibraryNames.remove(name); 2520 nativeLibraryContext.push(UNLOADER); 2521 try { 2522 unload(name, isBuiltin, handle); 2523 } finally { 2524 nativeLibraryContext.pop(); 2525 } 2526 2527 } 2528 } 2529 } 2530 2531 // JNI FindClass expects the caller class if invoked from JNI_OnLoad 2532 // and JNI_OnUnload is NativeLibrary class 2533 static native void unload(String name, boolean isBuiltin, long handle); 2534 } 2535 2536 // The paths searched for libraries 2537 private static String usr_paths[]; 2538 private static String sys_paths[]; 2539 2540 private static String[] initializePath(String propName) { 2541 String ldPath = System.getProperty(propName, ""); 2542 int ldLen = ldPath.length(); 2543 char ps = File.pathSeparatorChar; 2544 int psCount = 0; 2545 2546 if (ClassLoaderHelper.allowsQuotedPathElements && 2547 ldPath.indexOf('\"') >= 0) { 2548 // First, remove quotes put around quoted parts of paths. 2549 // Second, use a quotation mark as a new path separator. 2550 // This will preserve any quoted old path separators. 2551 char[] buf = new char[ldLen]; 2552 int bufLen = 0; 2553 for (int i = 0; i < ldLen; ++i) { 2554 char ch = ldPath.charAt(i); 2623 return; 2624 } 2625 libfile = ClassLoaderHelper.mapAlternativeName(libfile); 2626 if (libfile != null && loadLibrary0(fromClass, libfile)) { 2627 return; 2628 } 2629 } 2630 if (loader != null) { 2631 for (String usr_path : usr_paths) { 2632 File libfile = new File(usr_path, System.mapLibraryName(name)); 2633 if (loadLibrary0(fromClass, libfile)) { 2634 return; 2635 } 2636 libfile = ClassLoaderHelper.mapAlternativeName(libfile); 2637 if (libfile != null && loadLibrary0(fromClass, libfile)) { 2638 return; 2639 } 2640 } 2641 } 2642 // Oops, it failed 2643 throw new UnsatisfiedLinkError("no " + name + 2644 " in java.library.path: " + Arrays.toString(usr_paths)); 2645 } 2646 2647 private static native String findBuiltinLib(String name); 2648 2649 private static boolean loadLibrary0(Class<?> fromClass, final File file) { 2650 // Check to see if we're attempting to access a static library 2651 String name = findBuiltinLib(file.getName()); 2652 boolean isBuiltin = (name != null); 2653 if (!isBuiltin) { 2654 name = AccessController.doPrivileged( 2655 new PrivilegedAction<>() { 2656 public String run() { 2657 try { 2658 return file.exists() ? file.getCanonicalPath() : null; 2659 } catch (IOException e) { 2660 return null; 2661 } 2662 } 2663 }); 2664 if (name == null) { 2665 return false; 2666 } 2667 } 2668 return NativeLibrary.loadLibrary(fromClass, name, isBuiltin); 2669 } 2670 2671 /* 2672 * Invoked in the VM class linking code. 2673 */ 2674 private static long findNative(ClassLoader loader, String name) { 2675 Map<String, NativeLibrary> libs = 2676 loader != null ? loader.nativeLibraries() : systemNativeLibraries(); 2677 if (libs.isEmpty()) 2678 return 0; 2679 2680 // the native libraries map may be updated in another thread 2681 // when a native library is being loaded. No symbol will be 2682 // searched from it yet. 2683 for (NativeLibrary lib : libs.values()) { 2684 long entry = lib.findEntry(name); 2685 if (entry != 0) return entry; 2686 } 2687 return 0; 2688 } 2689 2690 // All native library names we've loaded. 2691 // This also serves as the lock to obtain nativeLibraries 2692 // and write to nativeLibraryContext. 2693 private static final Set<String> loadedLibraryNames = new HashSet<>(); 2694 2695 // Native libraries belonging to system classes. 2696 private static volatile Map<String, NativeLibrary> systemNativeLibraries; 2697 2698 // Native libraries associated with the class loader. 2699 private volatile Map<String, NativeLibrary> nativeLibraries; 2700 2701 /* 2702 * Returns the native libraries map associated with bootstrap class loader 2703 * This method will create the map at the first time when called. 2704 */ 2705 private static Map<String, NativeLibrary> systemNativeLibraries() { 2706 Map<String, NativeLibrary> libs = systemNativeLibraries; 2707 if (libs == null) { 2708 synchronized (loadedLibraryNames) { 2709 libs = systemNativeLibraries; 2710 if (libs == null) { 2711 libs = systemNativeLibraries = new ConcurrentHashMap<>(); 2712 } 2713 } 2714 } 2715 return libs; 2716 } 2717 2718 /* 2719 * Returns the native libraries map associated with this class loader 2720 * This method will create the map at the first time when called. 2721 */ 2722 private Map<String, NativeLibrary> nativeLibraries() { 2723 Map<String, NativeLibrary> libs = nativeLibraries; 2724 if (libs == null) { 2725 synchronized (loadedLibraryNames) { 2726 libs = nativeLibraries; 2727 if (libs == null) { 2728 libs = nativeLibraries = new ConcurrentHashMap<>(); 2729 } 2730 } 2731 } 2732 return libs; 2733 } 2734 2735 // -- Assertion management -- 2736 2737 final Object assertionLock; 2738 2739 // The default toggle for assertion checking. 2740 // @GuardedBy("assertionLock") 2741 private boolean defaultAssertionStatus = false; 2742 2743 // Maps String packageName to Boolean package default assertion status Note 2744 // that the default package is placed under a null map key. If this field 2745 // is null then we are delegating assertion status queries to the VM, i.e., 2746 // none of this ClassLoader's assertion status modification methods have 2747 // been invoked. 2748 // @GuardedBy("assertionLock") 2749 private Map<String, Boolean> packageAssertionStatus = null; 2750 2751 // Maps String fullyQualifiedClassName to Boolean assertionStatus If this 2752 // field is null then we are delegating assertion status queries to the VM, 2753 // i.e., none of this ClassLoader's assertion status modification methods |