View Javadoc
1   /*
2    * Copyright (c) 2010, 2013, 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.nashorn.internal.runtime.linker;
27  
28  import java.security.AccessControlContext;
29  import java.security.AccessController;
30  import java.security.PrivilegedAction;
31  import java.security.ProtectionDomain;
32  import java.security.SecureClassLoader;
33  import jdk.internal.dynalink.beans.StaticClass;
34  
35  /**
36   * This class encapsulates the bytecode of the adapter class and can be used to load it into the JVM as an actual Class.
37   * It can be invoked repeatedly to create multiple adapter classes from the same bytecode; adapter classes that have
38   * class-level overrides must be re-created for every set of such overrides. Note that while this class is named
39   * "class loader", it does not, in fact, extend {@code ClassLoader}, but rather uses them internally. Instances of this
40   * class are normally created by {@link JavaAdapterBytecodeGenerator}.
41   */
42  @SuppressWarnings("javadoc")
43  final class JavaAdapterClassLoader {
44      private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader");
45  
46      private final String className;
47      private final byte[] classBytes;
48  
49      JavaAdapterClassLoader(String className, byte[] classBytes) {
50          this.className = className.replace('/', '.');
51          this.classBytes = classBytes;
52      }
53  
54      /**
55       * Loads the generated adapter class into the JVM.
56       * @param parentLoader the parent class loader for the generated class loader
57       * @param protectionDomain the protection domain for the generated class
58       * @return the generated adapter class
59       */
60      StaticClass generateClass(final ClassLoader parentLoader, final ProtectionDomain protectionDomain) {
61          assert protectionDomain != null;
62          return AccessController.doPrivileged(new PrivilegedAction<StaticClass>() {
63              @Override
64              public StaticClass run() {
65                  try {
66                      return StaticClass.forClass(Class.forName(className, true, createClassLoader(parentLoader, protectionDomain)));
67                  } catch (final ClassNotFoundException e) {
68                      throw new AssertionError(e); // cannot happen
69                  }
70              }
71          }, CREATE_LOADER_ACC_CTXT);
72      }
73  
74      // Note that the adapter class is created in the protection domain of the class/interface being
75      // extended/implemented, and only the privileged global setter action class is generated in the protection domain
76      // of Nashorn itself. Also note that the creation and loading of the global setter is deferred until it is
77      // required by JVM linker, which will only happen on first invocation of any of the adapted method. We could defer
78      // it even more by separating its invocation into a separate static method on the adapter class, but then someone
79      // with ability to introspect on the class and use setAccessible(true) on it could invoke the method. It's a
80      // security tradeoff...
81      private ClassLoader createClassLoader(final ClassLoader parentLoader, final ProtectionDomain protectionDomain) {
82          return new SecureClassLoader(parentLoader) {
83              private final ClassLoader myLoader = getClass().getClassLoader();
84  
85              @Override
86              public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
87                  try {
88                      return super.loadClass(name, resolve);
89                  } catch (final SecurityException se) {
90                      // we may be implementing an interface or extending a class that was
91                      // loaded by a loader that prevents package.access. If so, it'd throw
92                      // SecurityException for nashorn's classes!. For adapter's to work, we
93                      // should be able to refer to nashorn classes.
94                      if (name.startsWith("jdk.nashorn.internal.")) {
95                          return myLoader.loadClass(name);
96                      }
97                      throw se;
98                  }
99              }
100 
101             @Override
102             protected Class<?> findClass(final String name) throws ClassNotFoundException {
103                 if(name.equals(className)) {
104                     assert classBytes != null : "what? already cleared .class bytes!!";
105                     return defineClass(name, classBytes, 0, classBytes.length, protectionDomain);
106                 }
107                 throw new ClassNotFoundException(name);
108             }
109         };
110     }
111 }