8158338: Nashorn's ScriptLoader split delegation has to be adjusted
authorsundar
Wed, 01 Jun 2016 15:17:37 +0530
changeset 38808 102fd16b8798
parent 38807 79e9bf5bb792
child 38809 98a5507b1c86
8158338: Nashorn's ScriptLoader split delegation has to be adjusted Reviewed-by: lagergren, hannesw
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Tue May 31 21:12:34 2016 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Jun 01 15:17:37 2016 +0530
@@ -486,6 +486,11 @@
     /** class loader to resolve classes from script. */
     private final ClassLoader appLoader;
 
+    /*package-private*/
+    ClassLoader getAppLoader() {
+        return appLoader;
+    }
+
     /** Class loader to load classes compiled from scripts. */
     private final ScriptLoader scriptLoader;
 
@@ -501,12 +506,13 @@
     /** Optional class filter to use for Java classes. Can be null. */
     private final ClassFilter classFilter;
 
-    private static final StructureLoader sharedLoader;
+    /** Process-wide singleton structure loader */
+    private static final StructureLoader theStructLoader;
     private static final ConcurrentMap<String, Class<?>> structureClasses = new ConcurrentHashMap<>();
 
     /*package-private*/ @SuppressWarnings("static-method")
-    StructureLoader getSharedLoader() {
-        return sharedLoader;
+    StructureLoader getStructLoader() {
+        return theStructLoader;
     }
 
     private static AccessControlContext createNoPermAccCtxt() {
@@ -526,7 +532,7 @@
 
     static {
         final ClassLoader myLoader = Context.class.getClassLoader();
-        sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
+        theStructLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
             @Override
             public StructureLoader run() {
                 return new StructureLoader(myLoader);
@@ -1038,7 +1044,7 @@
         }
         return (Class<? extends ScriptObject>)structureClasses.computeIfAbsent(fullName, (name) -> {
             try {
-                return Class.forName(name, true, sharedLoader);
+                return Class.forName(name, true, theStructLoader);
             } catch (final ClassNotFoundException e) {
                 throw new AssertionError(e);
             }
@@ -1191,7 +1197,7 @@
             // No verification when security manager is around as verifier
             // may load further classes - which should be avoided.
             if (System.getSecurityManager() == null) {
-                CheckClassAdapter.verify(new ClassReader(bytecode), sharedLoader, false, new PrintWriter(System.err, true));
+                CheckClassAdapter.verify(new ClassReader(bytecode), theStructLoader, false, new PrintWriter(System.err, true));
             }
         }
     }
@@ -1551,7 +1557,7 @@
              new PrivilegedAction<ScriptLoader>() {
                 @Override
                 public ScriptLoader run() {
-                    return new ScriptLoader(appLoader, Context.this);
+                    return new ScriptLoader(Context.this);
                 }
              }, CREATE_LOADER_ACC_CTXT);
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java	Tue May 31 21:12:34 2016 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java	Wed Jun 01 15:17:37 2016 +0530
@@ -38,8 +38,8 @@
     private static final String NASHORN_PKG_PREFIX = "jdk.nashorn.internal.";
 
     private volatile boolean structureAccessAdded;
+    private final Context context;
     private final Module scriptModule;
-    private final Context context;
 
     /*package-private*/ Context getContext() {
         return context;
@@ -48,8 +48,8 @@
     /**
      * Constructor.
      */
-    ScriptLoader(final ClassLoader parent, final Context context) {
-        super(parent);
+    ScriptLoader(final Context context) {
+        super(context.getStructLoader());
         this.context = context;
 
         // new scripts module, it's specific exports and read-edges
@@ -67,7 +67,7 @@
     }
 
     private Module createModule(final String moduleName) {
-        final Module structMod = context.getSharedLoader().getModule();
+        final Module structMod = context.getStructLoader().getModule();
         final ModuleDescriptor descriptor
                 = new ModuleDescriptor.Builder(moduleName)
                     .requires(NASHORN_MODULE.getName())
@@ -80,20 +80,45 @@
         return mod;
     }
 
-
     @Override
     protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
         checkPackageAccess(name);
-        if (name.startsWith(NASHORN_PKG_PREFIX)) {
-            final StructureLoader sharedCl = context.getSharedLoader();
-            final Class<?> cl = sharedCl.loadClass(name);
-            if (!structureAccessAdded && cl.getClassLoader() == sharedCl) {
+        final Class<?> cl = super.loadClass(name, resolve);
+        if (!structureAccessAdded) {
+            final StructureLoader structLoader = context.getStructLoader();
+            if (cl.getClassLoader() == structLoader) {
                 structureAccessAdded = true;
-                sharedCl.addModuleExport(scriptModule);
+                structLoader.addModuleExport(scriptModule);
             }
-            return cl;
         }
-        return super.loadClass(name, resolve);
+        return cl;
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        final ClassLoader appLoader = context.getAppLoader();
+
+        /*
+         * If the appLoader is null, don't bother side-delegating to it!
+         * Bootloader has been already attempted via parent loader
+         * delegation from the "loadClass" method.
+         *
+         * Also, make sure that we don't delegate to the app loader
+         * for nashorn's own classes or nashorn generated classes!
+         */
+        if (appLoader == null || name.startsWith(NASHORN_PKG_PREFIX)) {
+            throw new ClassNotFoundException(name);
+        }
+
+        /*
+         * This split-delegation is used so that caller loader
+         * based resolutions of classes would work. For example,
+         * java.sql.DriverManager uses caller's class loader to
+         * get Driver instances. Without this split-delegation
+         * a script class evaluating DriverManager.getDrivers()
+         * will not get back any JDBC driver!
+         */
+        return appLoader.loadClass(name);
     }
 
     // package-private and private stuff below this point