1.1 --- a/rt/emul/compact/src/main/java/sun/invoke/anon/AnonymousClassLoader.java Sun Aug 10 05:56:32 2014 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,230 +0,0 @@
1.4 -/*
1.5 - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 - *
1.8 - * This code is free software; you can redistribute it and/or modify it
1.9 - * under the terms of the GNU General Public License version 2 only, as
1.10 - * published by the Free Software Foundation. Oracle designates this
1.11 - * particular file as subject to the "Classpath" exception as provided
1.12 - * by Oracle in the LICENSE file that accompanied this code.
1.13 - *
1.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 - * version 2 for more details (a copy is included in the LICENSE file that
1.18 - * accompanied this code).
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License version
1.21 - * 2 along with this work; if not, write to the Free Software Foundation,
1.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 - *
1.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 - * or visit www.oracle.com if you need additional information or have any
1.26 - * questions.
1.27 - */
1.28 -
1.29 -package sun.invoke.anon;
1.30 -
1.31 -import java.io.IOException;
1.32 -import java.lang.reflect.InvocationTargetException;
1.33 -import java.lang.reflect.Method;
1.34 -import sun.misc.IOUtils;
1.35 -
1.36 -/**
1.37 - * Anonymous class loader. Will load any valid classfile, producing
1.38 - * a {@link Class} metaobject, without installing that class in the
1.39 - * system dictionary. Therefore, {@link Class#forName(String)} will never
1.40 - * produce a reference to an anonymous class.
1.41 - * <p>
1.42 - * The access permissions of the anonymous class are borrowed from
1.43 - * a <em>host class</em>. The new class behaves as if it were an
1.44 - * inner class of the host class. It can access the host's private
1.45 - * members, if the creator of the class loader has permission to
1.46 - * do so (or to create accessible reflective objects).
1.47 - * <p>
1.48 - * When the anonymous class is loaded, elements of its constant pool
1.49 - * can be patched to new values. This provides a hook to pre-resolve
1.50 - * named classes in the constant pool to other classes, including
1.51 - * anonymous ones. Also, string constants can be pre-resolved to
1.52 - * any reference. (The verifier treats non-string, non-class reference
1.53 - * constants as plain objects.)
1.54 - * <p>
1.55 - * Why include the patching function? It makes some use cases much easier.
1.56 - * Second, the constant pool needed some internal patching anyway,
1.57 - * to anonymize the loaded class itself. Finally, if you are going
1.58 - * to use this seriously, you'll want to build anonymous classes
1.59 - * on top of pre-existing anonymous classes, and that requires patching.
1.60 - *
1.61 - * <p>%%% TO-DO:
1.62 - * <ul>
1.63 - * <li>needs better documentation</li>
1.64 - * <li>needs more security work (for safe delegation)</li>
1.65 - * <li>needs a clearer story about error processing</li>
1.66 - * <li>patch member references also (use ';' as delimiter char)</li>
1.67 - * <li>patch method references to (conforming) method handles</li>
1.68 - * </ul>
1.69 - *
1.70 - * @author jrose
1.71 - * @author Remi Forax
1.72 - * @see <a href="http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm">
1.73 - * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm</a>
1.74 - */
1.75 -
1.76 -public class AnonymousClassLoader {
1.77 - final Class<?> hostClass;
1.78 -
1.79 - // Privileged constructor.
1.80 - private AnonymousClassLoader(Class<?> hostClass) {
1.81 - this.hostClass = hostClass;
1.82 - }
1.83 -
1.84 - public static AnonymousClassLoader make(sun.misc.Unsafe unsafe, Class<?> hostClass) {
1.85 - if (unsafe == null) throw new NullPointerException();
1.86 - return new AnonymousClassLoader(hostClass);
1.87 - }
1.88 -
1.89 - public Class<?> loadClass(byte[] classFile) {
1.90 - if (defineAnonymousClass == null) {
1.91 - // no JVM support; try to fake an approximation
1.92 - try {
1.93 - return fakeLoadClass(new ConstantPoolParser(classFile).createPatch());
1.94 - } catch (InvalidConstantPoolFormatException ee) {
1.95 - throw new IllegalArgumentException(ee);
1.96 - }
1.97 - }
1.98 - return loadClass(classFile, null);
1.99 - }
1.100 -
1.101 - public Class<?> loadClass(ConstantPoolPatch classPatch) {
1.102 - if (defineAnonymousClass == null) {
1.103 - // no JVM support; try to fake an approximation
1.104 - return fakeLoadClass(classPatch);
1.105 - }
1.106 - Object[] patches = classPatch.patchArray;
1.107 - // Convert class names (this late in the game)
1.108 - // to use slash '/' instead of dot '.'.
1.109 - // Java likes dots, but the JVM likes slashes.
1.110 - for (int i = 0; i < patches.length; i++) {
1.111 - Object value = patches[i];
1.112 - if (value != null) {
1.113 - byte tag = classPatch.getTag(i);
1.114 - switch (tag) {
1.115 - case ConstantPoolVisitor.CONSTANT_Class:
1.116 - if (value instanceof String) {
1.117 - if (patches == classPatch.patchArray)
1.118 - patches = patches.clone();
1.119 - patches[i] = ((String)value).replace('.', '/');
1.120 - }
1.121 - break;
1.122 - case ConstantPoolVisitor.CONSTANT_Fieldref:
1.123 - case ConstantPoolVisitor.CONSTANT_Methodref:
1.124 - case ConstantPoolVisitor.CONSTANT_InterfaceMethodref:
1.125 - case ConstantPoolVisitor.CONSTANT_NameAndType:
1.126 - // When/if the JVM supports these patches,
1.127 - // we'll probably need to reformat them also.
1.128 - // Meanwhile, let the class loader create the error.
1.129 - break;
1.130 - }
1.131 - }
1.132 - }
1.133 - return loadClass(classPatch.outer.classFile, classPatch.patchArray);
1.134 - }
1.135 -
1.136 - private Class<?> loadClass(byte[] classFile, Object[] patchArray) {
1.137 - try {
1.138 - return (Class<?>)
1.139 - defineAnonymousClass.invoke(unsafe,
1.140 - hostClass, classFile, patchArray);
1.141 - } catch (Exception ex) {
1.142 - throwReflectedException(ex);
1.143 - throw new RuntimeException("error loading into "+hostClass, ex);
1.144 - }
1.145 - }
1.146 -
1.147 - private static void throwReflectedException(Exception ex) {
1.148 - if (ex instanceof InvocationTargetException) {
1.149 - Throwable tex = ((InvocationTargetException)ex).getTargetException();
1.150 - if (tex instanceof Error)
1.151 - throw (Error) tex;
1.152 - ex = (Exception) tex;
1.153 - }
1.154 - if (ex instanceof RuntimeException) {
1.155 - throw (RuntimeException) ex;
1.156 - }
1.157 - }
1.158 -
1.159 - private Class<?> fakeLoadClass(ConstantPoolPatch classPatch) {
1.160 - // Implementation:
1.161 - // 1. Make up a new name nobody has used yet.
1.162 - // 2. Inspect the tail-header of the class to find the this_class index.
1.163 - // 3. Patch the CONSTANT_Class for this_class to the new name.
1.164 - // 4. Add other CP entries required by (e.g.) string patches.
1.165 - // 5. Flatten Class constants down to their names, making sure that
1.166 - // the host class loader can pick them up again accurately.
1.167 - // 6. Generate the edited class file bytes.
1.168 - //
1.169 - // Potential limitations:
1.170 - // * The class won't be truly anonymous, and may interfere with others.
1.171 - // * Flattened class constants might not work, because of loader issues.
1.172 - // * Pseudo-string constants will not flatten down to real strings.
1.173 - // * Method handles will (of course) fail to flatten to linkage strings.
1.174 - if (true) throw new UnsupportedOperationException("NYI");
1.175 - Object[] cpArray;
1.176 - try {
1.177 - cpArray = classPatch.getOriginalCP();
1.178 - } catch (InvalidConstantPoolFormatException ex) {
1.179 - throw new RuntimeException(ex);
1.180 - }
1.181 - int thisClassIndex = classPatch.getParser().getThisClassIndex();
1.182 - String thisClassName = (String) cpArray[thisClassIndex];
1.183 - synchronized (AnonymousClassLoader.class) {
1.184 - thisClassName = thisClassName+"\\|"+(++fakeNameCounter);
1.185 - }
1.186 - classPatch.putUTF8(thisClassIndex, thisClassName);
1.187 - byte[] classFile = null;
1.188 - return unsafe.defineClass(null, classFile, 0, classFile.length,
1.189 - hostClass.getClassLoader(),
1.190 - hostClass.getProtectionDomain());
1.191 - }
1.192 - private static int fakeNameCounter = 99999;
1.193 -
1.194 - // ignore two warnings on this line:
1.195 - private static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
1.196 - // preceding line requires that this class be on the boot class path
1.197 -
1.198 - static private final Method defineAnonymousClass;
1.199 - static {
1.200 - Method dac = null;
1.201 - Class<? extends sun.misc.Unsafe> unsafeClass = unsafe.getClass();
1.202 - try {
1.203 - dac = unsafeClass.getMethod("defineAnonymousClass",
1.204 - Class.class,
1.205 - byte[].class,
1.206 - Object[].class);
1.207 - } catch (Exception ee) {
1.208 - dac = null;
1.209 - }
1.210 - defineAnonymousClass = dac;
1.211 - }
1.212 -
1.213 - private static void noJVMSupport() {
1.214 - throw new UnsupportedOperationException("no JVM support for anonymous classes");
1.215 - }
1.216 -
1.217 -
1.218 - private static native Class<?> loadClassInternal(Class<?> hostClass,
1.219 - byte[] classFile,
1.220 - Object[] patchArray);
1.221 -
1.222 - public static byte[] readClassFile(Class<?> templateClass) throws IOException {
1.223 - String templateName = templateClass.getName();
1.224 - int lastDot = templateName.lastIndexOf('.');
1.225 - java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class");
1.226 - java.net.URLConnection connection = url.openConnection();
1.227 - int contentLength = connection.getContentLength();
1.228 - if (contentLength < 0)
1.229 - throw new IOException("invalid content length "+contentLength);
1.230 -
1.231 - return IOUtils.readFully(connection.getInputStream(), contentLength, true);
1.232 - }
1.233 -}