1 /*
   2  * Copyright (c) 2015, 2022, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  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 jdk.internal.loader;
  27 
  28 import java.io.IOException;
  29 import java.io.InputStream;
  30 import java.lang.module.ModuleDescriptor;
  31 import java.lang.module.ModuleReference;
  32 import java.lang.module.ModuleReader;
  33 import java.lang.ref.SoftReference;
  34 import java.net.MalformedURLException;
  35 import java.net.URI;
  36 import java.net.URL;
  37 import java.nio.ByteBuffer;
  38 import java.security.AccessController;
  39 import java.security.CodeSigner;
  40 import java.security.CodeSource;
  41 import java.security.PermissionCollection;
  42 import java.security.PrivilegedAction;
  43 import java.security.PrivilegedActionException;
  44 import java.security.PrivilegedExceptionAction;
  45 import java.security.SecureClassLoader;
  46 import java.util.ArrayList;
  47 import java.util.Collections;
  48 import java.util.Enumeration;
  49 import java.util.Iterator;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.NoSuchElementException;
  53 import java.util.Optional;
  54 import java.util.Set;
  55 import java.util.concurrent.ConcurrentHashMap;
  56 import java.util.function.Function;
  57 import java.util.jar.Attributes;
  58 import java.util.jar.Manifest;
  59 import java.util.stream.Stream;
  60 
  61 import jdk.internal.access.SharedSecrets;
  62 import jdk.internal.misc.CDS;
  63 import jdk.internal.misc.VM;
  64 import jdk.internal.module.ModulePatcher.PatchedModuleReader;
  65 import jdk.internal.module.Resources;
  66 import jdk.internal.vm.annotation.Stable;
  67 import sun.security.util.LazyCodeSourcePermissionCollection;
  68 
  69 
  70 /**
  71  * The platform or application class loader. Resources loaded from modules
  72  * defined to the boot class loader are also loaded via an instance of this
  73  * ClassLoader type.
  74  *
  75  * <p> This ClassLoader supports loading of classes and resources from modules.
  76  * Modules are defined to the ClassLoader by invoking the {@link #loadModule}
  77  * method. Defining a module to this ClassLoader has the effect of making the
  78  * types in the module visible. </p>
  79  *
  80  * <p> This ClassLoader also supports loading of classes and resources from a
  81  * class path of URLs that are specified to the ClassLoader at construction
  82  * time. The class path may expand at runtime (the Class-Path attribute in JAR
  83  * files or via instrumentation agents). </p>
  84  *
  85  * <p> The delegation model used by this ClassLoader differs to the regular
  86  * delegation model. When requested to load a class then this ClassLoader first
  87  * maps the class name to its package name. If there is a module defined to a
  88  * BuiltinClassLoader containing this package then the class loader delegates
  89  * directly to that class loader. If there isn't a module containing the
  90  * package then it delegates the search to the parent class loader and if not
  91  * found in the parent then it searches the class path. The main difference
  92  * between this and the usual delegation model is that it allows the platform
  93  * class loader to delegate to the application class loader, important with
  94  * upgraded modules defined to the platform class loader.
  95  */
  96 
  97 public class BuiltinClassLoader
  98     extends SecureClassLoader
  99 {
 100     static {
 101         if (!ClassLoader.registerAsParallelCapable())
 102             throw new InternalError("Unable to register as parallel capable");
 103     }
 104 
 105     // parent ClassLoader
 106     private final BuiltinClassLoader parent;
 107 
 108     // the URL class path, or null if there is no class path
 109     private @Stable URLClassPath ucp;
 110 
 111     private Set<String> negativeLookupCache;
 112     private Map<String, Class<? extends Object>> positiveLookupCache;
 113 
 114     public boolean useNegativeCache = false;
 115     public boolean usePositiveCache = false;
 116 
 117     /**
 118      * A module defined/loaded by a built-in class loader.
 119      *
 120      * A LoadedModule encapsulates a ModuleReference along with its CodeSource
 121      * URL to avoid needing to create this URL when defining classes.
 122      */
 123     private static class LoadedModule {
 124         private final BuiltinClassLoader loader;
 125         private final ModuleReference mref;
 126         private final URI uri;                      // may be null
 127         private @Stable URL codeSourceURL;          // may be null
 128 
 129         LoadedModule(BuiltinClassLoader loader, ModuleReference mref) {
 130             URL url = null;
 131             this.uri = mref.location().orElse(null);
 132 
 133             // for non-jrt schemes we need to resolve the codeSourceURL
 134             // eagerly during bootstrap since the handler might be
 135             // overridden
 136             if (uri != null && !"jrt".equals(uri.getScheme())) {
 137                 url = createURL(uri);
 138             }
 139             this.loader = loader;
 140             this.mref = mref;
 141             this.codeSourceURL = url;
 142         }
 143 
 144         BuiltinClassLoader loader() { return loader; }
 145         ModuleReference mref() { return mref; }
 146         String name() { return mref.descriptor().name(); }
 147 
 148         URL codeSourceURL() {
 149             URL url = codeSourceURL;
 150             if (url == null && uri != null) {
 151                 codeSourceURL = url = createURL(uri);
 152             }
 153             return url;
 154         }
 155 
 156         private URL createURL(URI uri) {
 157             URL url = null;
 158             try {
 159                 url = uri.toURL();
 160             } catch (MalformedURLException | IllegalArgumentException e) {
 161             }
 162             return url;
 163         }
 164     }
 165 
 166     // maps package name to loaded module for modules in the boot layer
 167     private static final Map<String, LoadedModule> packageToModule;
 168     static {
 169         ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get();
 170         if (archivedClassLoaders != null) {
 171             @SuppressWarnings("unchecked")
 172             Map<String, LoadedModule> map
 173                 = (Map<String, LoadedModule>) archivedClassLoaders.packageToModule();
 174             packageToModule = map;
 175         } else {
 176             packageToModule = new ConcurrentHashMap<>(1024);
 177         }
 178     }
 179 
 180     /**
 181      * Invoked by ArchivedClassLoaders to archive the package-to-module map.
 182      */
 183     static Map<String, ?> packageToModule() {
 184         return packageToModule;
 185     }
 186 
 187     // maps a module name to a module reference
 188     private final Map<String, ModuleReference> nameToModule;
 189 
 190     // maps a module reference to a module reader
 191     private final Map<ModuleReference, ModuleReader> moduleToReader;
 192 
 193     // cache of resource name -> list of URLs.
 194     // used only for resources that are not in module packages
 195     private volatile SoftReference<Map<String, List<URL>>> resourceCache;
 196 
 197     /**
 198      * Create a new instance.
 199      */
 200     BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) {
 201         // ensure getParent() returns null when the parent is the boot loader
 202         super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent);
 203 
 204         this.parent = parent;
 205         this.ucp = ucp;
 206 
 207         this.nameToModule = new ConcurrentHashMap<>(32);
 208         this.moduleToReader = new ConcurrentHashMap<>();
 209         this.negativeLookupCache = ConcurrentHashMap.newKeySet();
 210         this.positiveLookupCache = new ConcurrentHashMap<>();
 211     }
 212 
 213     /**
 214      * Appends to the given file path to the class path.
 215      */
 216     void appendClassPath(String path) {
 217         // assert ucp != null;
 218         ucp.addFile(path);
 219     }
 220 
 221     /**
 222      * Sets the class path, called to reset the class path during -Xshare:dump
 223      */
 224     void setClassPath(URLClassPath ucp) {
 225         this.ucp = ucp;
 226     }
 227 
 228     /**
 229      * Returns {@code true} if there is a class path associated with this
 230      * class loader.
 231      */
 232     boolean hasClassPath() {
 233         return ucp != null;
 234     }
 235 
 236     /**
 237      * Register a module this class loader. This has the effect of making the
 238      * types in the module visible.
 239      */
 240     public void loadModule(ModuleReference mref) {
 241         ModuleDescriptor descriptor = mref.descriptor();
 242         String mn = descriptor.name();
 243         if (nameToModule.putIfAbsent(mn, mref) != null) {
 244             throw new InternalError(mn + " already defined to this loader");
 245         }
 246 
 247         LoadedModule loadedModule = new LoadedModule(this, mref);
 248         for (String pn : descriptor.packages()) {
 249             LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule);
 250             if (other != null) {
 251                 throw new InternalError(pn + " in modules " + mn + " and "
 252                                         + other.name());
 253             }
 254         }
 255 
 256         // clear resources cache if VM is already initialized
 257         if (resourceCache != null && VM.isModuleSystemInited()) {
 258             resourceCache = null;
 259         }
 260     }
 261 
 262     /**
 263      * Returns the {@code ModuleReference} for the named module defined to
 264      * this class loader; or {@code null} if not defined.
 265      *
 266      * @param name The name of the module to find
 267      */
 268     protected ModuleReference findModule(String name) {
 269         return nameToModule.get(name);
 270     }
 271 
 272 
 273     // -- finding resources
 274 
 275     /**
 276      * Returns a URL to a resource of the given name in a module defined to
 277      * this class loader.
 278      */
 279     @Override
 280     public URL findResource(String mn, String name) throws IOException {
 281         URL url = null;
 282 
 283         if (mn != null) {
 284             // find in module
 285             ModuleReference mref = nameToModule.get(mn);
 286             if (mref != null) {
 287                 url = findResource(mref, name);
 288             }
 289         } else {
 290             // find on class path
 291             url = findResourceOnClassPath(name);
 292         }
 293 
 294         return checkURL(url);  // check access before returning
 295     }
 296 
 297     /**
 298      * Returns an input stream to a resource of the given name in a module
 299      * defined to this class loader.
 300      */
 301     @SuppressWarnings("removal")
 302     public InputStream findResourceAsStream(String mn, String name)
 303         throws IOException
 304     {
 305         // Need URL to resource when running with a security manager so that
 306         // the right permission check is done.
 307         if (System.getSecurityManager() != null || mn == null) {
 308             URL url = findResource(mn, name);
 309             return (url != null) ? url.openStream() : null;
 310         }
 311 
 312         // find in module defined to this loader, no security manager
 313         ModuleReference mref = nameToModule.get(mn);
 314         if (mref != null) {
 315             return moduleReaderFor(mref).open(name).orElse(null);
 316         } else {
 317             return null;
 318         }
 319     }
 320 
 321     /**
 322      * Finds a resource with the given name in the modules defined to this
 323      * class loader or its class path.
 324      */
 325     @Override
 326     public URL findResource(String name) {
 327         String pn = Resources.toPackageName(name);
 328         LoadedModule module = packageToModule.get(pn);
 329         if (module != null) {
 330 
 331             // resource is in a package of a module defined to this loader
 332             if (module.loader() == this) {
 333                 URL url;
 334                 try {
 335                     url = findResource(module.name(), name); // checks URL
 336                 } catch (IOException ioe) {
 337                     return null;
 338                 }
 339                 if (url != null
 340                     && (name.endsWith(".class")
 341                         || url.toString().endsWith("/")
 342                         || isOpen(module.mref(), pn))) {
 343                     return url;
 344                 }
 345             }
 346 
 347         } else {
 348 
 349             // not in a module package but may be in module defined to this loader
 350             try {
 351                 List<URL> urls = findMiscResource(name);
 352                 if (!urls.isEmpty()) {
 353                     URL url = urls.get(0);
 354                     if (url != null) {
 355                         return checkURL(url); // check access before returning
 356                     }
 357                 }
 358             } catch (IOException ioe) {
 359                 return null;
 360             }
 361 
 362         }
 363 
 364         // search class path
 365         URL url = findResourceOnClassPath(name);
 366         return checkURL(url);
 367     }
 368 
 369     /**
 370      * Returns an enumeration of URL objects to all the resources with the
 371      * given name in modules defined to this class loader or on the class
 372      * path of this loader.
 373      */
 374     @Override
 375     public Enumeration<URL> findResources(String name) throws IOException {
 376         List<URL> checked = new ArrayList<>();  // list of checked URLs
 377 
 378         String pn = Resources.toPackageName(name);
 379         LoadedModule module = packageToModule.get(pn);
 380         if (module != null) {
 381 
 382             // resource is in a package of a module defined to this loader
 383             if (module.loader() == this) {
 384                 URL url = findResource(module.name(), name); // checks URL
 385                 if (url != null
 386                     && (name.endsWith(".class")
 387                         || url.toString().endsWith("/")
 388                         || isOpen(module.mref(), pn))) {
 389                     checked.add(url);
 390                 }
 391             }
 392 
 393         } else {
 394             // not in a package of a module defined to this loader
 395             for (URL url : findMiscResource(name)) {
 396                 url = checkURL(url);
 397                 if (url != null) {
 398                     checked.add(url);
 399                 }
 400             }
 401         }
 402 
 403         // class path (not checked)
 404         Enumeration<URL> e = findResourcesOnClassPath(name);
 405 
 406         // concat the checked URLs and the (not checked) class path
 407         return new Enumeration<>() {
 408             final Iterator<URL> iterator = checked.iterator();
 409             URL next;
 410             private boolean hasNext() {
 411                 if (next != null) {
 412                     return true;
 413                 } else if (iterator.hasNext()) {
 414                     next = iterator.next();
 415                     return true;
 416                 } else {
 417                     // need to check each URL
 418                     while (e.hasMoreElements() && next == null) {
 419                         next = checkURL(e.nextElement());
 420                     }
 421                     return next != null;
 422                 }
 423             }
 424             @Override
 425             public boolean hasMoreElements() {
 426                 return hasNext();
 427             }
 428             @Override
 429             public URL nextElement() {
 430                 if (hasNext()) {
 431                     URL result = next;
 432                     next = null;
 433                     return result;
 434                 } else {
 435                     throw new NoSuchElementException();
 436                 }
 437             }
 438         };
 439 
 440     }
 441 
 442     /**
 443      * Returns the list of URLs to a "miscellaneous" resource in modules
 444      * defined to this loader. A miscellaneous resource is not in a module
 445      * package, e.g. META-INF/services/p.S.
 446      *
 447      * The cache used by this method avoids repeated searching of all modules.
 448      */
 449     @SuppressWarnings("removal")
 450     private List<URL> findMiscResource(String name) throws IOException {
 451         SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
 452         Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
 453         if (map == null) {
 454             // only cache resources after VM is fully initialized
 455             if (VM.isModuleSystemInited()) {
 456                 map = new ConcurrentHashMap<>();
 457                 this.resourceCache = new SoftReference<>(map);
 458             }
 459         } else {
 460             List<URL> urls = map.get(name);
 461             if (urls != null)
 462                 return urls;
 463         }
 464 
 465         // search all modules for the resource
 466         List<URL> urls;
 467         try {
 468             urls = AccessController.doPrivileged(
 469                 new PrivilegedExceptionAction<>() {
 470                     @Override
 471                     public List<URL> run() throws IOException {
 472                         List<URL> result = null;
 473                         for (ModuleReference mref : nameToModule.values()) {
 474                             URI u = moduleReaderFor(mref).find(name).orElse(null);
 475                             if (u != null) {
 476                                 try {
 477                                     if (result == null)
 478                                         result = new ArrayList<>();
 479                                     result.add(u.toURL());
 480                                 } catch (MalformedURLException |
 481                                          IllegalArgumentException e) {
 482                                 }
 483                             }
 484                         }
 485                         return (result != null) ? result : Collections.emptyList();
 486                     }
 487                 });
 488         } catch (PrivilegedActionException pae) {
 489             throw (IOException) pae.getCause();
 490         }
 491 
 492         // only cache resources after VM is fully initialized
 493         if (map != null) {
 494             map.putIfAbsent(name, urls);
 495         }
 496 
 497         return urls;
 498     }
 499 
 500     /**
 501      * Returns the URL to a resource in a module or {@code null} if not found.
 502      */
 503     @SuppressWarnings("removal")
 504     private URL findResource(ModuleReference mref, String name) throws IOException {
 505         URI u;
 506         if (System.getSecurityManager() == null) {
 507             u = moduleReaderFor(mref).find(name).orElse(null);
 508         } else {
 509             try {
 510                 u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () {
 511                     @Override
 512                     public URI run() throws IOException {
 513                         return moduleReaderFor(mref).find(name).orElse(null);
 514                     }
 515                 });
 516             } catch (PrivilegedActionException pae) {
 517                 throw (IOException) pae.getCause();
 518             }
 519         }
 520         if (u != null) {
 521             try {
 522                 return u.toURL();
 523             } catch (MalformedURLException | IllegalArgumentException e) { }
 524         }
 525         return null;
 526     }
 527 
 528     /**
 529      * Returns the URL to a resource in a module. Returns {@code null} if not found
 530      * or an I/O error occurs.
 531      */
 532     private URL findResourceOrNull(ModuleReference mref, String name) {
 533         try {
 534             return findResource(mref, name);
 535         } catch (IOException ignore) {
 536             return null;
 537         }
 538     }
 539 
 540     /**
 541      * Returns a URL to a resource on the class path.
 542      */
 543     @SuppressWarnings("removal")
 544     private URL findResourceOnClassPath(String name) {
 545         if (hasClassPath()) {
 546             if (System.getSecurityManager() == null) {
 547                 return ucp.findResource(name, false);
 548             } else {
 549                 PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
 550                 return AccessController.doPrivileged(pa);
 551             }
 552         } else {
 553             // no class path
 554             return null;
 555         }
 556     }
 557 
 558     /**
 559      * Returns the URLs of all resources of the given name on the class path.
 560      */
 561     @SuppressWarnings("removal")
 562     private Enumeration<URL> findResourcesOnClassPath(String name) {
 563         if (hasClassPath()) {
 564             if (System.getSecurityManager() == null) {
 565                 return ucp.findResources(name, false);
 566             } else {
 567                 PrivilegedAction<Enumeration<URL>> pa;
 568                 pa = () -> ucp.findResources(name, false);
 569                 return AccessController.doPrivileged(pa);
 570             }
 571         } else {
 572             // no class path
 573             return Collections.emptyEnumeration();
 574         }
 575     }
 576 
 577     // -- finding/loading classes
 578 
 579     /**
 580      * Finds the class with the specified binary name.
 581      */
 582     @Override
 583     protected Class<?> findClass(String cn) throws ClassNotFoundException {
 584         // no class loading until VM is fully initialized
 585         if (!VM.isModuleSystemInited())
 586             throw new ClassNotFoundException(cn);
 587 
 588         // find the candidate module for this class
 589         LoadedModule loadedModule = findLoadedModule(cn);
 590 
 591         Class<?> c = null;
 592         if (loadedModule != null) {
 593 
 594             // attempt to load class in module defined to this loader
 595             if (loadedModule.loader() == this) {
 596                 c = findClassInModuleOrNull(loadedModule, cn);
 597             }
 598 
 599         } else {
 600 
 601             // search class path
 602             if (hasClassPath()) {
 603                 c = findClassOnClassPathOrNull(cn);
 604             }
 605 
 606         }
 607 
 608         // not found
 609         if (c == null)
 610             throw new ClassNotFoundException(cn);
 611 
 612         return c;
 613     }
 614 
 615     /**
 616      * Finds the class with the specified binary name in a module.
 617      * This method returns {@code null} if the class cannot be found
 618      * or not defined in the specified module.
 619      */
 620     @Override
 621     protected Class<?> findClass(String mn, String cn) {
 622         if (mn != null) {
 623             // find the candidate module for this class
 624             LoadedModule loadedModule = findLoadedModule(mn, cn);
 625             if (loadedModule == null) {
 626                 return null;
 627             }
 628 
 629             // attempt to load class in module defined to this loader
 630             assert loadedModule.loader() == this;
 631             return findClassInModuleOrNull(loadedModule, cn);
 632         }
 633 
 634         // search class path
 635         if (hasClassPath()) {
 636             return findClassOnClassPathOrNull(cn);
 637         }
 638 
 639         return null;
 640     }
 641 
 642     /**
 643      * Loads the class with the specified binary name.
 644      */
 645     @Override
 646     protected Class<?> loadClass(String cn, boolean resolve)
 647         throws ClassNotFoundException
 648     {
 649         if (useNegativeCache && checkNegativeLookupCache(cn)) {
 650             throw new ClassNotFoundException(cn);
 651         }
 652         Class<?> c = loadClassOrNull(cn, resolve);
 653         if (c == null) {
 654             addToNegativeLookupCache(cn);
 655             throw new ClassNotFoundException(cn);
 656         }
 657 
 658         return c;
 659     }
 660 
 661     /**
 662      * A variation of {@code loadClass} to load a class with the specified
 663      * binary name. This method returns {@code null} when the class is not
 664      * found.
 665      */
 666     protected Class<?> loadClassOrNull(String cn, boolean resolve) {
 667         synchronized (getClassLoadingLock(cn)) {
 668             // check if already loaded
 669             Class<?> c = findLoadedClass(cn);
 670 
 671             if (c == null) {
 672 
 673                 // find the candidate module for this class
 674                 LoadedModule loadedModule = findLoadedModule(cn);
 675                 if (loadedModule != null) {
 676 
 677                     // package is in a module
 678                     BuiltinClassLoader loader = loadedModule.loader();
 679                     if (loader == this) {
 680                         if (VM.isModuleSystemInited()) {
 681                             c = findClassInModuleOrNull(loadedModule, cn);
 682                         }
 683                     } else {
 684                         // delegate to the other loader
 685                         c = loader.loadClassOrNull(cn);
 686                     }
 687 
 688                 } else {
 689 
 690                     // check parent
 691                     if (parent != null) {
 692                         c = parent.loadClassOrNull(cn);
 693                     }
 694 
 695                     // check class path
 696                     if (c == null && hasClassPath() && VM.isModuleSystemInited()) {
 697                         c = findClassOnClassPathOrNull(cn);
 698                     }
 699                 }
 700 
 701             }
 702 
 703             if (resolve && c != null)
 704                 resolveClass(c);
 705 
 706             return c;
 707         }
 708     }
 709 
 710     /**
 711      * A variation of {@code loadClass} to load a class with the specified
 712      * binary name. This method returns {@code null} when the class is not
 713      * found.
 714      */
 715     protected final Class<?> loadClassOrNull(String cn) {
 716         return loadClassOrNull(cn, false);
 717     }
 718 
 719     /**
 720      * Finds the candidate loaded module for the given class name.
 721      * Returns {@code null} if none of the modules defined to this
 722      * class loader contain the API package for the class.
 723      */
 724     private LoadedModule findLoadedModule(String cn) {
 725         int pos = cn.lastIndexOf('.');
 726         if (pos < 0)
 727             return null; // unnamed package
 728 
 729         String pn = cn.substring(0, pos);
 730         return packageToModule.get(pn);
 731     }
 732 
 733     /**
 734      * Finds the candidate loaded module for the given class name
 735      * in the named module.  Returns {@code null} if the named module
 736      * is not defined to this class loader or does not contain
 737      * the API package for the class.
 738      */
 739     private LoadedModule findLoadedModule(String mn, String cn) {
 740         LoadedModule loadedModule = findLoadedModule(cn);
 741         if (loadedModule != null && mn.equals(loadedModule.name())) {
 742             return loadedModule;
 743         } else {
 744             return null;
 745         }
 746     }
 747 
 748     /**
 749      * Finds the class with the specified binary name if in a module
 750      * defined to this ClassLoader.
 751      *
 752      * @return the resulting Class or {@code null} if not found
 753      */
 754     @SuppressWarnings("removal")
 755     private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
 756         if (System.getSecurityManager() == null) {
 757             return defineClass(cn, loadedModule);
 758         } else {
 759             PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
 760             return AccessController.doPrivileged(pa);
 761         }
 762     }
 763 
 764     /**
 765      * Finds the class with the specified binary name on the class path.
 766      *
 767      * @return the resulting Class or {@code null} if not found
 768      */
 769     @SuppressWarnings("removal")
 770     private Class<?> findClassOnClassPathOrNull(String cn) {
 771         String path = cn.replace('.', '/').concat(".class");
 772         if (System.getSecurityManager() == null) {
 773             Resource res = ucp.getResource(path, false);
 774             if (res != null) {
 775                 try {
 776                     return defineClass(cn, res);
 777                 } catch (IOException ioe) {
 778                     // TBD on how I/O errors should be propagated
 779                 }
 780             }
 781             return null;
 782         } else {
 783             // avoid use of lambda here
 784             PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() {
 785                 public Class<?> run() {
 786                     Resource res = ucp.getResource(path, false);
 787                     if (res != null) {
 788                         try {
 789                             return defineClass(cn, res);
 790                         } catch (IOException ioe) {
 791                             // TBD on how I/O errors should be propagated
 792                         }
 793                     }
 794                     return null;
 795                 }
 796             };
 797             return AccessController.doPrivileged(pa);
 798         }
 799     }
 800 
 801     /**
 802      * Defines the given binary class name to the VM, loading the class
 803      * bytes from the given module.
 804      *
 805      * @return the resulting Class or {@code null} if an I/O error occurs
 806      */
 807     private Class<?> defineClass(String cn, LoadedModule loadedModule) {
 808         ModuleReference mref = loadedModule.mref();
 809         ModuleReader reader = moduleReaderFor(mref);
 810 
 811         try {
 812             ByteBuffer bb = null;
 813             URL csURL = null;
 814 
 815             // locate class file, special handling for patched modules to
 816             // avoid locating the resource twice
 817             String rn = cn.replace('.', '/').concat(".class");
 818             if (reader instanceof PatchedModuleReader) {
 819                 Resource r = ((PatchedModuleReader)reader).findResource(rn);
 820                 if (r != null) {
 821                     bb = r.getByteBuffer();
 822                     csURL = r.getCodeSourceURL();
 823                 }
 824             } else {
 825                 bb = reader.read(rn).orElse(null);
 826                 csURL = loadedModule.codeSourceURL();
 827             }
 828 
 829             if (bb == null) {
 830                 // class not found
 831                 return null;
 832             }
 833 
 834             CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null);
 835             try {
 836                 // define class to VM
 837                 return defineClass(cn, bb, cs);
 838 
 839             } finally {
 840                 reader.release(bb);
 841             }
 842 
 843         } catch (IOException ioe) {
 844             // TBD on how I/O errors should be propagated
 845             return null;
 846         }
 847     }
 848 
 849     /**
 850      * Defines the given binary class name to the VM, loading the class
 851      * bytes via the given Resource object.
 852      *
 853      * @return the resulting Class
 854      * @throws IOException if reading the resource fails
 855      * @throws SecurityException if there is a sealing violation (JAR spec)
 856      */
 857     private Class<?> defineClass(String cn, Resource res) throws IOException {
 858         URL url = res.getCodeSourceURL();
 859 
 860         // if class is in a named package then ensure that the package is defined
 861         int pos = cn.lastIndexOf('.');
 862         if (pos != -1) {
 863             String pn = cn.substring(0, pos);
 864             Manifest man = res.getManifest();
 865             defineOrCheckPackage(pn, man, url);
 866         }
 867 
 868         // defines the class to the runtime
 869         ByteBuffer bb = res.getByteBuffer();
 870         if (bb != null) {
 871             CodeSigner[] signers = res.getCodeSigners();
 872             CodeSource cs = new CodeSource(url, signers);
 873             return defineClass(cn, bb, cs);
 874         } else {
 875             byte[] b = res.getBytes();
 876             CodeSigner[] signers = res.getCodeSigners();
 877             CodeSource cs = new CodeSource(url, signers);
 878             return defineClass(cn, b, 0, b.length, cs);
 879         }
 880     }
 881 
 882 
 883     // -- packages
 884 
 885     /**
 886      * Defines a package in this ClassLoader. If the package is already defined
 887      * then its sealing needs to be checked if sealed by the legacy sealing
 888      * mechanism.
 889      *
 890      * @throws SecurityException if there is a sealing violation (JAR spec)
 891      */
 892     protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
 893         Package pkg = getAndVerifyPackage(pn, man, url);
 894         if (pkg == null) {
 895             try {
 896                 if (man != null) {
 897                     pkg = definePackage(pn, man, url);
 898                 } else {
 899                     pkg = definePackage(pn, null, null, null, null, null, null, null);
 900                 }
 901             } catch (IllegalArgumentException iae) {
 902                 // defined by another thread so need to re-verify
 903                 pkg = getAndVerifyPackage(pn, man, url);
 904                 if (pkg == null)
 905                     throw new InternalError("Cannot find package: " + pn);
 906             }
 907         }
 908         return pkg;
 909     }
 910 
 911     /**
 912      * Gets the Package with the specified package name. If defined
 913      * then verifies it against the manifest and code source.
 914      *
 915      * @throws SecurityException if there is a sealing violation (JAR spec)
 916      */
 917     private Package getAndVerifyPackage(String pn, Manifest man, URL url) {
 918         Package pkg = getDefinedPackage(pn);
 919         if (pkg != null) {
 920             if (pkg.isSealed()) {
 921                 if (!pkg.isSealed(url)) {
 922                     throw new SecurityException(
 923                         "sealing violation: package " + pn + " is sealed");
 924                 }
 925             } else {
 926                 // can't seal package if already defined without sealing
 927                 if ((man != null) && isSealed(pn, man)) {
 928                     throw new SecurityException(
 929                         "sealing violation: can't seal package " + pn +
 930                         ": already defined");
 931                 }
 932             }
 933         }
 934         return pkg;
 935     }
 936 
 937     /**
 938      * Defines a new package in this ClassLoader. The attributes in the specified
 939      * Manifest are used to get the package version and sealing information.
 940      *
 941      * @throws IllegalArgumentException if the package name duplicates an
 942      *      existing package either in this class loader or one of its ancestors
 943      * @throws SecurityException if the package name is untrusted in the manifest
 944      */
 945     private Package definePackage(String pn, Manifest man, URL url) {
 946         String specTitle = null;
 947         String specVersion = null;
 948         String specVendor = null;
 949         String implTitle = null;
 950         String implVersion = null;
 951         String implVendor = null;
 952         String sealed = null;
 953         URL sealBase = null;
 954 
 955         if (man != null) {
 956             Attributes attr = SharedSecrets.javaUtilJarAccess()
 957                     .getTrustedAttributes(man, pn.replace('.', '/').concat("/"));
 958             if (attr != null) {
 959                 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
 960                 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
 961                 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
 962                 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
 963                 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
 964                 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
 965                 sealed = attr.getValue(Attributes.Name.SEALED);
 966             }
 967 
 968             attr = man.getMainAttributes();
 969             if (attr != null) {
 970                 if (specTitle == null)
 971                     specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
 972                 if (specVersion == null)
 973                     specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
 974                 if (specVendor == null)
 975                     specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
 976                 if (implTitle == null)
 977                     implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
 978                 if (implVersion == null)
 979                     implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
 980                 if (implVendor == null)
 981                     implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
 982                 if (sealed == null)
 983                     sealed = attr.getValue(Attributes.Name.SEALED);
 984             }
 985 
 986             // package is sealed
 987             if ("true".equalsIgnoreCase(sealed))
 988                 sealBase = url;
 989         }
 990         return definePackage(pn,
 991                 specTitle,
 992                 specVersion,
 993                 specVendor,
 994                 implTitle,
 995                 implVersion,
 996                 implVendor,
 997                 sealBase);
 998     }
 999 
1000     /**
1001      * Returns {@code true} if the specified package name is sealed according to
1002      * the given manifest.
1003      *
1004      * @throws SecurityException if the package name is untrusted in the manifest
1005      */
1006     private boolean isSealed(String pn, Manifest man) {
1007         Attributes attr = SharedSecrets.javaUtilJarAccess()
1008                 .getTrustedAttributes(man, pn.replace('.', '/').concat("/"));
1009         String sealed = null;
1010         if (attr != null)
1011             sealed = attr.getValue(Attributes.Name.SEALED);
1012         if (sealed == null && (attr = man.getMainAttributes()) != null)
1013             sealed = attr.getValue(Attributes.Name.SEALED);
1014         return "true".equalsIgnoreCase(sealed);
1015     }
1016 
1017     // -- permissions
1018 
1019     /**
1020      * Returns the permissions for the given CodeSource.
1021      */
1022     @Override
1023     protected PermissionCollection getPermissions(CodeSource cs) {
1024         return new LazyCodeSourcePermissionCollection(super.getPermissions(cs), cs);
1025     }
1026 
1027     // -- miscellaneous supporting methods
1028 
1029     /**
1030      * Returns the ModuleReader for the given module, creating it if needed.
1031      */
1032     private ModuleReader moduleReaderFor(ModuleReference mref) {
1033         ModuleReader reader = moduleToReader.get(mref);
1034         if (reader == null) {
1035             // avoid method reference during startup
1036             Function<ModuleReference, ModuleReader> create = new Function<>() {
1037                 public ModuleReader apply(ModuleReference moduleReference) {
1038                     try {
1039                         return mref.open();
1040                     } catch (IOException e) {
1041                         // Return a null module reader to avoid a future class
1042                         // load attempting to open the module again.
1043                         return new NullModuleReader();
1044                     }
1045                 }
1046             };
1047             reader = moduleToReader.computeIfAbsent(mref, create);
1048         }
1049         return reader;
1050     }
1051 
1052     /**
1053      * A ModuleReader that doesn't read any resources.
1054      */
1055     private static class NullModuleReader implements ModuleReader {
1056         @Override
1057         public Optional<URI> find(String name) {
1058             return Optional.empty();
1059         }
1060         @Override
1061         public Stream<String> list() {
1062             return Stream.empty();
1063         }
1064         @Override
1065         public void close() {
1066             throw new InternalError("Should not get here");
1067         }
1068     };
1069 
1070     /**
1071      * Returns true if the given module opens the given package
1072      * unconditionally.
1073      *
1074      * @implNote This method currently iterates over each of the open
1075      * packages. This will be replaced once the ModuleDescriptor.Opens
1076      * API is updated.
1077      */
1078     private boolean isOpen(ModuleReference mref, String pn) {
1079         ModuleDescriptor descriptor = mref.descriptor();
1080         if (descriptor.isOpen() || descriptor.isAutomatic())
1081             return true;
1082         for (ModuleDescriptor.Opens opens : descriptor.opens()) {
1083             String source = opens.source();
1084             if (!opens.isQualified() && source.equals(pn)) {
1085                 return true;
1086             }
1087         }
1088         return false;
1089     }
1090 
1091     /**
1092      * Checks access to the given URL. We use URLClassPath for consistent
1093      * checking with java.net.URLClassLoader.
1094      */
1095     private static URL checkURL(URL url) {
1096         return URLClassPath.checkURL(url);
1097     }
1098 
1099     // Called from VM only, during -Xshare:dump
1100     private void resetArchivedStates() {
1101         ucp = null;
1102         resourceCache = null;
1103     }
1104 
1105     public boolean checkNegativeLookupCache(String className) {
1106         return negativeLookupCache.contains(className);
1107     }
1108 
1109     public void addToNegativeLookupCache(String className) {
1110         negativeLookupCache.add(className);
1111     }
1112 
1113     public String negativeLookupCacheContents() {
1114         String[] contents = negativeLookupCache.toArray(new String[]{});
1115         StringBuilder builder = new StringBuilder();
1116         if (contents.length != 0) {
1117             for (String name: contents) {
1118                 if (builder.length() != 0) {
1119                     builder.append(" ");
1120                 }
1121                 builder.append(name);
1122             }
1123             return builder.toString();
1124         } else {
1125             return null;
1126         }
1127     }
1128 
1129     public void generateNegativeLookupCache(String contents) {
1130         String[] tokens = contents.split(" ");
1131         if (tokens.length > 0) {
1132             for (String token : tokens) {
1133                 negativeLookupCache.add(token);
1134             }
1135             useNegativeCache = true;
1136         }
1137     }
1138 
1139     public Class<?> checkPositiveLookupCache(String className) {
1140         return positiveLookupCache.get(className);
1141     }
1142 
1143     public void generatePositiveLookupCache(Class<?>[] cls) {
1144         if (cls.length > 0) {
1145             for (Class<?> c : cls) {
1146                 positiveLookupCache.put(c.getName(), c);
1147             }
1148             usePositiveCache = true;
1149         }
1150     }
1151 }
--- EOF ---