1193N/A/*
5440N/A * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
1193N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1193N/A *
1193N/A * This code is free software; you can redistribute it and/or modify it
1193N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
1193N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
1193N/A *
1193N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1193N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1193N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1193N/A * version 2 for more details (a copy is included in the LICENSE file that
1193N/A * accompanied this code).
1193N/A *
1193N/A * You should have received a copy of the GNU General Public License version
1193N/A * 2 along with this work; if not, write to the Free Software Foundation,
1193N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1193N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
1193N/A */
1193N/A
3793N/Apackage sun.invoke.anon;
1193N/A
1193N/Aimport java.io.IOException;
1193N/Aimport java.lang.reflect.InvocationTargetException;
1193N/Aimport java.lang.reflect.Method;
1822N/Aimport sun.misc.IOUtils;
1193N/A
1193N/A/**
1193N/A * Anonymous class loader. Will load any valid classfile, producing
1193N/A * a {@link Class} metaobject, without installing that class in the
1193N/A * system dictionary. Therefore, {@link Class#forName(String)} will never
1193N/A * produce a reference to an anonymous class.
1193N/A * <p>
1193N/A * The access permissions of the anonymous class are borrowed from
1193N/A * a <em>host class</em>. The new class behaves as if it were an
1193N/A * inner class of the host class. It can access the host's private
1193N/A * members, if the creator of the class loader has permission to
1193N/A * do so (or to create accessible reflective objects).
1193N/A * <p>
1193N/A * When the anonymous class is loaded, elements of its constant pool
1193N/A * can be patched to new values. This provides a hook to pre-resolve
1193N/A * named classes in the constant pool to other classes, including
1193N/A * anonymous ones. Also, string constants can be pre-resolved to
1193N/A * any reference. (The verifier treats non-string, non-class reference
1193N/A * constants as plain objects.)
1193N/A * <p>
1193N/A * Why include the patching function? It makes some use cases much easier.
1193N/A * Second, the constant pool needed some internal patching anyway,
1193N/A * to anonymize the loaded class itself. Finally, if you are going
1193N/A * to use this seriously, you'll want to build anonymous classes
1193N/A * on top of pre-existing anonymous classes, and that requires patching.
1193N/A *
1193N/A * <p>%%% TO-DO:
1193N/A * <ul>
1193N/A * <li>needs better documentation</li>
1193N/A * <li>needs more security work (for safe delegation)</li>
1193N/A * <li>needs a clearer story about error processing</li>
1193N/A * <li>patch member references also (use ';' as delimiter char)</li>
1193N/A * <li>patch method references to (conforming) method handles</li>
1193N/A * </ul>
1193N/A *
1193N/A * @author jrose
1193N/A * @author Remi Forax
1193N/A * @see <a href="http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm">
1193N/A * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm</a>
1193N/A */
1193N/A
1193N/Apublic class AnonymousClassLoader {
1193N/A final Class<?> hostClass;
1193N/A
5440N/A // Privileged constructor.
5440N/A private AnonymousClassLoader(Class<?> hostClass) {
5440N/A this.hostClass = hostClass;
1193N/A }
1193N/A
5440N/A public static AnonymousClassLoader make(sun.misc.Unsafe unsafe, Class<?> hostClass) {
5440N/A if (unsafe == null) throw new NullPointerException();
5440N/A return new AnonymousClassLoader(hostClass);
1193N/A }
1193N/A
1193N/A public Class<?> loadClass(byte[] classFile) {
1193N/A if (defineAnonymousClass == null) {
1193N/A // no JVM support; try to fake an approximation
1193N/A try {
1193N/A return fakeLoadClass(new ConstantPoolParser(classFile).createPatch());
1193N/A } catch (InvalidConstantPoolFormatException ee) {
1193N/A throw new IllegalArgumentException(ee);
1193N/A }
1193N/A }
1193N/A return loadClass(classFile, null);
1193N/A }
1193N/A
1193N/A public Class<?> loadClass(ConstantPoolPatch classPatch) {
1193N/A if (defineAnonymousClass == null) {
1193N/A // no JVM support; try to fake an approximation
1193N/A return fakeLoadClass(classPatch);
1193N/A }
1193N/A Object[] patches = classPatch.patchArray;
1193N/A // Convert class names (this late in the game)
1193N/A // to use slash '/' instead of dot '.'.
1193N/A // Java likes dots, but the JVM likes slashes.
1193N/A for (int i = 0; i < patches.length; i++) {
1193N/A Object value = patches[i];
1193N/A if (value != null) {
1193N/A byte tag = classPatch.getTag(i);
1193N/A switch (tag) {
1193N/A case ConstantPoolVisitor.CONSTANT_Class:
1193N/A if (value instanceof String) {
1193N/A if (patches == classPatch.patchArray)
1193N/A patches = patches.clone();
1193N/A patches[i] = ((String)value).replace('.', '/');
1193N/A }
1193N/A break;
1193N/A case ConstantPoolVisitor.CONSTANT_Fieldref:
1193N/A case ConstantPoolVisitor.CONSTANT_Methodref:
1193N/A case ConstantPoolVisitor.CONSTANT_InterfaceMethodref:
1193N/A case ConstantPoolVisitor.CONSTANT_NameAndType:
1193N/A // When/if the JVM supports these patches,
1193N/A // we'll probably need to reformat them also.
1193N/A // Meanwhile, let the class loader create the error.
1193N/A break;
1193N/A }
1193N/A }
1193N/A }
1193N/A return loadClass(classPatch.outer.classFile, classPatch.patchArray);
1193N/A }
1193N/A
1193N/A private Class<?> loadClass(byte[] classFile, Object[] patchArray) {
1193N/A try {
1193N/A return (Class<?>)
1193N/A defineAnonymousClass.invoke(unsafe,
1193N/A hostClass, classFile, patchArray);
1193N/A } catch (Exception ex) {
1193N/A throwReflectedException(ex);
1193N/A throw new RuntimeException("error loading into "+hostClass, ex);
1193N/A }
1193N/A }
1193N/A
1193N/A private static void throwReflectedException(Exception ex) {
1193N/A if (ex instanceof InvocationTargetException) {
1193N/A Throwable tex = ((InvocationTargetException)ex).getTargetException();
1193N/A if (tex instanceof Error)
1193N/A throw (Error) tex;
1193N/A ex = (Exception) tex;
1193N/A }
1193N/A if (ex instanceof RuntimeException) {
1193N/A throw (RuntimeException) ex;
1193N/A }
1193N/A }
1193N/A
1193N/A private Class<?> fakeLoadClass(ConstantPoolPatch classPatch) {
1193N/A // Implementation:
1193N/A // 1. Make up a new name nobody has used yet.
1193N/A // 2. Inspect the tail-header of the class to find the this_class index.
1193N/A // 3. Patch the CONSTANT_Class for this_class to the new name.
1193N/A // 4. Add other CP entries required by (e.g.) string patches.
1193N/A // 5. Flatten Class constants down to their names, making sure that
1193N/A // the host class loader can pick them up again accurately.
1193N/A // 6. Generate the edited class file bytes.
1193N/A //
1193N/A // Potential limitations:
1193N/A // * The class won't be truly anonymous, and may interfere with others.
1193N/A // * Flattened class constants might not work, because of loader issues.
1193N/A // * Pseudo-string constants will not flatten down to real strings.
1193N/A // * Method handles will (of course) fail to flatten to linkage strings.
1193N/A if (true) throw new UnsupportedOperationException("NYI");
1193N/A Object[] cpArray;
1193N/A try {
1193N/A cpArray = classPatch.getOriginalCP();
1193N/A } catch (InvalidConstantPoolFormatException ex) {
1193N/A throw new RuntimeException(ex);
1193N/A }
1193N/A int thisClassIndex = classPatch.getParser().getThisClassIndex();
1193N/A String thisClassName = (String) cpArray[thisClassIndex];
1193N/A synchronized (AnonymousClassLoader.class) {
1193N/A thisClassName = thisClassName+"\\|"+(++fakeNameCounter);
1193N/A }
1193N/A classPatch.putUTF8(thisClassIndex, thisClassName);
1193N/A byte[] classFile = null;
1193N/A return unsafe.defineClass(null, classFile, 0, classFile.length,
1193N/A hostClass.getClassLoader(),
1193N/A hostClass.getProtectionDomain());
1193N/A }
1193N/A private static int fakeNameCounter = 99999;
1193N/A
1193N/A // ignore two warnings on this line:
5440N/A private static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
1193N/A // preceding line requires that this class be on the boot class path
1193N/A
1193N/A static private final Method defineAnonymousClass;
1193N/A static {
1193N/A Method dac = null;
1193N/A Class<? extends sun.misc.Unsafe> unsafeClass = unsafe.getClass();
1193N/A try {
1193N/A dac = unsafeClass.getMethod("defineAnonymousClass",
1193N/A Class.class,
1193N/A byte[].class,
1193N/A Object[].class);
1193N/A } catch (Exception ee) {
1193N/A dac = null;
1193N/A }
1193N/A defineAnonymousClass = dac;
1193N/A }
1193N/A
1193N/A private static void noJVMSupport() {
1193N/A throw new UnsupportedOperationException("no JVM support for anonymous classes");
1193N/A }
1193N/A
1193N/A
1193N/A private static native Class<?> loadClassInternal(Class<?> hostClass,
1193N/A byte[] classFile,
1193N/A Object[] patchArray);
1193N/A
1193N/A public static byte[] readClassFile(Class<?> templateClass) throws IOException {
1193N/A String templateName = templateClass.getName();
1193N/A int lastDot = templateName.lastIndexOf('.');
1193N/A java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class");
1193N/A java.net.URLConnection connection = url.openConnection();
1193N/A int contentLength = connection.getContentLength();
1193N/A if (contentLength < 0)
1193N/A throw new IOException("invalid content length "+contentLength);
1193N/A
1822N/A return IOUtils.readFully(connection.getInputStream(), contentLength, true);
1193N/A }
1193N/A}