# HG changeset patch # User Jaroslav Tulach # Date 1407644016 -7200 # Node ID 5c990ed353e98152a8d1cebb8d086a56ba29f21b # Parent 6799184bf769138f0763e5ad63428a2a7d88bb13 Almost compiled java.lang.invoke, except the parts that deal with Asm bytecode generator diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/CallSite.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/CallSite.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/CallSite.java Sun Aug 10 06:13:36 2014 +0200 @@ -232,21 +232,13 @@ throw new IllegalStateException("uninitialized call site"); } - // unsafe stuff: - private static final long TARGET_OFFSET; - static { - try { - TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target")); - } catch (Exception ex) { throw new Error(ex); } - } - /*package-private*/ void setTargetNormal(MethodHandle newTarget) { MethodHandleNatives.setCallSiteTargetNormal(this, newTarget); } /*package-private*/ MethodHandle getTargetVolatile() { - return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET); + return target; } /*package-private*/ void setTargetVolatile(MethodHandle newTarget) { diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java Sun Aug 10 06:13:36 2014 +0200 @@ -83,16 +83,6 @@ // Used to ensure that each spun class name is unique private static final AtomicInteger counter = new AtomicInteger(0); - // For dumping generated classes to disk, for debugging purposes - private static final ProxyClassesDumper dumper; - - static { - final String key = "jdk.internal.lambda.dumpProxyClasses"; - String path = AccessController.doPrivileged( - new GetPropertyAction(key), null, - new PropertyPermission(key , "read")); - dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path); - } // See context values in AbstractValidatingLambdaMetafactory private final String implMethodClassName; // Name of type containing implementation "CC" diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandle.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandle.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandle.java Sun Aug 10 06:13:36 2014 +0200 @@ -28,7 +28,6 @@ import java.util.*; import sun.invoke.util.*; -import sun.misc.Unsafe; import static java.lang.invoke.MethodHandleStatics.*; import java.util.logging.Level; @@ -434,7 +433,7 @@ @interface PolymorphicSignature { } private final MethodType type; - /*private*/ final LambdaForm form; + /*private*/ LambdaForm form; // form is not private so that invokers can easily fetch it /*private*/ MethodHandle asTypeCache; // asTypeCache is not private so that invokers can easily fetch it @@ -1395,7 +1394,7 @@ // CURRENT RESTRICTIONS // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others) - assert pos == 0 && basicType == 'L' && value instanceof Unsafe; +// assert pos == 0 && basicType == 'L' && value instanceof Unsafe; MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver! LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos return copyWith(type2, form2); @@ -1489,17 +1488,7 @@ /*non-public*/ void updateForm(LambdaForm newForm) { if (form == newForm) return; - // ISSUE: Should we have a memory fence here? - UNSAFE.putObject(this, FORM_OFFSET, newForm); + this.form = newForm; this.form.prepare(); // as in MethodHandle. } - - private static final long FORM_OFFSET; - static { - try { - FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form")); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - } } diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleImpl.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleImpl.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleImpl.java Sun Aug 10 06:13:36 2014 +0200 @@ -34,8 +34,6 @@ import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; @@ -842,6 +840,8 @@ } private static MethodHandle makeInjectedInvoker(Class hostClass) { + throw new IllegalStateException("Implement me too!"); + /* Class bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); if (hostClass.getClassLoader() != bcc.getClassLoader()) throw new InternalError(hostClass.getName()+" (CL)"); @@ -873,6 +873,7 @@ throw new InternalError(ex); } return bccInvoker; + */ } private static ClassValue CV_makeInjectedInvoker = new ClassValue() { @Override protected MethodHandle computeValue(Class hostClass) { @@ -905,7 +906,7 @@ private static final MethodHandle MH_checkCallerClass; static { final Class THIS_CLASS = BindCaller.class; - assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); +// assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); try { MH_checkCallerClass = IMPL_LOOKUP .findStatic(THIS_CLASS, "checkCallerClass", @@ -916,16 +917,16 @@ } } - @CallerSensitive - private static boolean checkCallerClass(Class expected, Class expected2) { - // This method is called via MH_checkCallerClass and so it's - // correct to ask for the immediate caller here. - Class actual = Reflection.getCallerClass(); - if (actual != expected && actual != expected2) - throw new InternalError("found "+actual.getName()+", expected "+expected.getName() - +(expected == expected2 ? "" : ", or else "+expected2.getName())); - return true; - } +// @CallerSensitive +// private static boolean checkCallerClass(Class expected, Class expected2) { +// // This method is called via MH_checkCallerClass and so it's +// // correct to ask for the immediate caller here. +// Class actual = Reflection.getCallerClass(); +// if (actual != expected && actual != expected2) +// throw new InternalError("found "+actual.getName()+", expected "+expected.getName() +// +(expected == expected2 ? "" : ", or else "+expected2.getName())); +// return true; +// } private static final byte[] T_BYTES; static { diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleNatives.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleNatives.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleNatives.java Sun Aug 10 06:13:36 2014 +0200 @@ -265,7 +265,7 @@ continue; } throw new InternalError(err); - } catch (NoSuchFieldException | IllegalAccessException ex) { + } catch (IllegalAccessException ex) { String err = (name+": JVM has "+vmval+" which Java does not define"); // ignore exotic ops the JVM cares about; we just wont issue them //System.err.println("warning: "+err); @@ -488,7 +488,7 @@ Class defc = mem.getDeclaringClass(); switch (mem.getName()) { case "checkMemberAccess": - return canBeCalledVirtual(mem, java.lang.SecurityManager.class); + return true; //canBeCalledVirtual(mem, java.lang.SecurityManager.class); case "getContextClassLoader": return canBeCalledVirtual(mem, java.lang.Thread.class); } diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java Sun Aug 10 06:13:36 2014 +0200 @@ -30,9 +30,9 @@ import java.security.PrivilegedAction; import sun.invoke.WrapperInstance; import java.util.ArrayList; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.misc.ReflectUtil; +//import sun.reflect.CallerSensitive; +//import sun.reflect.Reflection; +//import sun.reflect.misc.ReflectUtil; /** * This class consists exclusively of static methods that help adapt @@ -144,17 +144,17 @@ // entry points, must be covered by hand-written or automatically // generated adapter classes. // - @CallerSensitive +// @CallerSensitive public static T asInterfaceInstance(final Class intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) throw new IllegalArgumentException("not a public interface: "+intfc.getName()); final MethodHandle mh; - if (System.getSecurityManager() != null) { - final Class caller = Reflection.getCallerClass(); - final ClassLoader ccl = caller != null ? caller.getClassLoader() : null; - ReflectUtil.checkProxyPackageAccess(ccl, intfc); - mh = ccl != null ? bindCaller(target, caller) : target; + if (false) {//System.getSecurityManager() != null) { +// final Class caller = Reflection.getCallerClass(); +// final ClassLoader ccl = caller != null ? caller.getClassLoader() : null; +// ReflectUtil.checkProxyPackageAccess(ccl, intfc); +// mh = ccl != null ? bindCaller(target, caller) : target; } else { mh = target; } @@ -194,7 +194,7 @@ }; final Object proxy; - if (System.getSecurityManager() != null) { + if (false) { // System.getSecurityManager() != null) { // sun.invoke.WrapperInstance is a restricted interface not accessible // by any non-null class loader. final ClassLoader loader = proxyLoader; diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleStatics.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleStatics.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleStatics.java Sun Aug 10 06:13:36 2014 +0200 @@ -27,7 +27,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.Unsafe; +//import sun.misc.Unsafe; /** * This class consists exclusively of static names internal to the @@ -39,7 +39,7 @@ private MethodHandleStatics() { } // do not instantiate - static final Unsafe UNSAFE = Unsafe.getUnsafe(); +// static final Unsafe UNSAFE = Unsafe.getUnsafe(); static final boolean DEBUG_METHOD_HANDLE_NAMES; static final boolean DUMP_CLASS_FILES; diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandles.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandles.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandles.java Sun Aug 10 06:13:36 2014 +0200 @@ -33,14 +33,9 @@ import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyAccess; import sun.invoke.util.Wrapper; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.misc.ReflectUtil; -import sun.security.util.SecurityConstants; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; import java.util.concurrent.ConcurrentHashMap; -import sun.security.util.SecurityConstants; /** * This class consists exclusively of static methods that operate on or return @@ -85,9 +80,10 @@ * executing in the same caller class {@code C}. * @return a lookup object for the caller of this method, with private access */ - @CallerSensitive +// @CallerSensitive public static Lookup lookup() { - return new Lookup(Reflection.getCallerClass()); + throw new IllegalStateException("Implement me!"); +// return new Lookup(Reflection.getCallerClass()); } /** @@ -138,14 +134,14 @@ */ public static T reflectAs(Class expected, MethodHandle target) { - SecurityManager smgr = System.getSecurityManager(); - if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION); +// SecurityManager smgr = System.getSecurityManager(); +// if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION); Lookup lookup = Lookup.IMPL_LOOKUP; // use maximally privileged lookup return lookup.revealDirect(target).reflectAs(expected, lookup); } // Copied from AccessibleObject, as used by Method.setAccessible, etc.: - static final private java.security.Permission ACCESS_PERMISSION = - new ReflectPermission("suppressAccessChecks"); +// static final private java.security.Permission ACCESS_PERMISSION = +// new ReflectPermission("suppressAccessChecks"); /** * A lookup object is a factory for creating method handles, @@ -1428,28 +1424,28 @@ * If this lookup object has private access, then the caller class is the lookupClass. */ void checkSecurityManager(Class refc, MemberName m) { - SecurityManager smgr = System.getSecurityManager(); - if (smgr == null) return; - if (allowedModes == TRUSTED) return; - - // Step 1: - boolean fullPowerLookup = hasPrivateAccess(); - if (!fullPowerLookup || - !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) { - ReflectUtil.checkPackageAccess(refc); - } - - // Step 2: - if (m.isPublic()) return; - if (!fullPowerLookup) { - smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); - } - - // Step 3: - Class defc = m.getDeclaringClass(); - if (!fullPowerLookup && defc != refc) { - ReflectUtil.checkPackageAccess(defc); - } +// SecurityManager smgr = System.getSecurityManager(); +// if (smgr == null) return; +// if (allowedModes == TRUSTED) return; +// +// // Step 1: +// boolean fullPowerLookup = hasPrivateAccess(); +// if (!fullPowerLookup || +// !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) { +// ReflectUtil.checkPackageAccess(refc); +// } +// +// // Step 2: +// if (m.isPublic()) return; +// if (!fullPowerLookup) { +// smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); +// } +// +// // Step 3: +// Class defc = m.getDeclaringClass(); +// if (!fullPowerLookup && defc != refc) { +// ReflectUtil.checkPackageAccess(defc); +// } } void checkMethod(byte refKind, Class refc, MemberName m) throws IllegalAccessException { @@ -1749,17 +1745,17 @@ return false; } ClassLoader loader = defc.getClassLoader(); - if (!sun.misc.VM.isSystemDomainLoader(loader)) { - ClassLoader sysl = ClassLoader.getSystemClassLoader(); - boolean found = false; - while (sysl != null) { - if (loader == sysl) { found = true; break; } - sysl = sysl.getParent(); - } - if (!found) { - return false; - } - } +// if (!sun.misc.VM.isSystemDomainLoader(loader)) { +// ClassLoader sysl = ClassLoader.getSystemClassLoader(); +// boolean found = false; +// while (sysl != null) { +// if (loader == sysl) { found = true; break; } +// sysl = sysl.getParent(); +// } +// if (!found) { +// return false; +// } +// } try { MemberName resolved2 = publicLookup().resolveOrFail(refKind, new MemberName(refKind, defc, member.getName(), member.getType())); diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java Sun Aug 10 06:13:36 2014 +0200 @@ -948,60 +948,60 @@ */ private static final java.io.ObjectStreamField[] serialPersistentFields = { }; - /** - * Save the {@code MethodType} instance to a stream. - * - * @serialData - * For portability, the serialized format does not refer to named fields. - * Instead, the return type and parameter type arrays are written directly - * from the {@code writeObject} method, using two calls to {@code s.writeObject} - * as follows: - *
{@code
-s.writeObject(this.returnType());
-s.writeObject(this.parameterArray());
-     * }
- *

- * The deserialized field values are checked as if they were - * provided to the factory method {@link #methodType(Class,Class[]) methodType}. - * For example, null values, or {@code void} parameter types, - * will lead to exceptions during deserialization. - * @param s the stream to write the object to - * @throws java.io.IOException if there is a problem writing the object - */ - private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - s.defaultWriteObject(); // requires serialPersistentFields to be an empty array - s.writeObject(returnType()); - s.writeObject(parameterArray()); - } - - /** - * Reconstitute the {@code MethodType} instance from a stream (that is, - * deserialize it). - * This instance is a scratch object with bogus final fields. - * It provides the parameters to the factory method called by - * {@link #readResolve readResolve}. - * After that call it is discarded. - * @param s the stream to read the object from - * @throws java.io.IOException if there is a problem reading the object - * @throws ClassNotFoundException if one of the component classes cannot be resolved - * @see #MethodType() - * @see #readResolve - * @see #writeObject - */ - private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - s.defaultReadObject(); // requires serialPersistentFields to be an empty array - - Class returnType = (Class) s.readObject(); - Class[] parameterArray = (Class[]) s.readObject(); - - // Probably this object will never escape, but let's check - // the field values now, just to be sure. - checkRtype(returnType); - checkPtypes(parameterArray); - - parameterArray = parameterArray.clone(); // make sure it is unshared - MethodType_init(returnType, parameterArray); - } +// /** +// * Save the {@code MethodType} instance to a stream. +// * +// * @serialData +// * For portability, the serialized format does not refer to named fields. +// * Instead, the return type and parameter type arrays are written directly +// * from the {@code writeObject} method, using two calls to {@code s.writeObject} +// * as follows: +// *

{@code
+//s.writeObject(this.returnType());
+//s.writeObject(this.parameterArray());
+//     * }
+// *

+// * The deserialized field values are checked as if they were +// * provided to the factory method {@link #methodType(Class,Class[]) methodType}. +// * For example, null values, or {@code void} parameter types, +// * will lead to exceptions during deserialization. +// * @param s the stream to write the object to +// * @throws java.io.IOException if there is a problem writing the object +// */ +// private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { +// s.defaultWriteObject(); // requires serialPersistentFields to be an empty array +// s.writeObject(returnType()); +// s.writeObject(parameterArray()); +// } +// +// /** +// * Reconstitute the {@code MethodType} instance from a stream (that is, +// * deserialize it). +// * This instance is a scratch object with bogus final fields. +// * It provides the parameters to the factory method called by +// * {@link #readResolve readResolve}. +// * After that call it is discarded. +// * @param s the stream to read the object from +// * @throws java.io.IOException if there is a problem reading the object +// * @throws ClassNotFoundException if one of the component classes cannot be resolved +// * @see #MethodType() +// * @see #readResolve +// * @see #writeObject +// */ +// private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { +// s.defaultReadObject(); // requires serialPersistentFields to be an empty array +// +// Class returnType = (Class) s.readObject(); +// Class[] parameterArray = (Class[]) s.readObject(); +// +// // Probably this object will never escape, but let's check +// // the field values now, just to be sure. +// checkRtype(returnType); +// checkPtypes(parameterArray); +// +// parameterArray = parameterArray.clone(); // make sure it is unshared +// MethodType_init(returnType, parameterArray); +// } /** * For serialization only. @@ -1011,27 +1011,27 @@ this.rtype = null; this.ptypes = null; } - private void MethodType_init(Class rtype, Class[] ptypes) { - // In order to communicate these values to readResolve, we must - // store them into the implementation-specific final fields. - checkRtype(rtype); - checkPtypes(ptypes); - UNSAFE.putObject(this, rtypeOffset, rtype); - UNSAFE.putObject(this, ptypesOffset, ptypes); - } +// private void MethodType_init(Class rtype, Class[] ptypes) { +// // In order to communicate these values to readResolve, we must +// // store them into the implementation-specific final fields. +// checkRtype(rtype); +// checkPtypes(ptypes); +// UNSAFE.putObject(this, rtypeOffset, rtype); +// UNSAFE.putObject(this, ptypesOffset, ptypes); +// } // Support for resetting final fields while deserializing - private static final long rtypeOffset, ptypesOffset; - static { - try { - rtypeOffset = UNSAFE.objectFieldOffset - (MethodType.class.getDeclaredField("rtype")); - ptypesOffset = UNSAFE.objectFieldOffset - (MethodType.class.getDeclaredField("ptypes")); - } catch (Exception ex) { - throw new Error(ex); - } - } +// private static final long rtypeOffset, ptypesOffset; +// static { +// try { +// rtypeOffset = UNSAFE.objectFieldOffset +// (MethodType.class.getDeclaredField("rtype")); +// ptypesOffset = UNSAFE.objectFieldOffset +// (MethodType.class.getDeclaredField("ptypes")); +// } catch (Exception ex) { +// throw new Error(ex); +// } +// } /** * Resolves and initializes a {@code MethodType} object diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/java/lang/invoke/ProxyClassesDumper.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/ProxyClassesDumper.java Sun Aug 10 05:56:32 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.lang.invoke; - -import sun.util.logging.PlatformLogger; - -import java.io.FilePermission; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Helper class used by InnerClassLambdaMetafactory to log generated classes - * - * @implNote - *

Because this class is called by LambdaMetafactory, make use - * of lambda lead to recursive calls cause stack overflow. - */ -final class ProxyClassesDumper { - private static final char[] HEX = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - private static final char[] BAD_CHARS = { - '\\', ':', '*', '?', '"', '<', '>', '|' - }; - private static final String[] REPLACEMENT = { - "%5C", "%3A", "%2A", "%3F", "%22", "%3C", "%3E", "%7C" - }; - - private final Path dumpDir; - - public static ProxyClassesDumper getInstance(String path) { - if (null == path) { - return null; - } - try { - path = path.trim(); - final Path dir = Paths.get(path.length() == 0 ? "." : path); - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - validateDumpDir(dir); - return null; - } - }, null, new FilePermission("<>", "read, write")); - return new ProxyClassesDumper(dir); - } catch (InvalidPathException ex) { - PlatformLogger.getLogger(ProxyClassesDumper.class.getName()) - .warning("Path " + path + " is not valid - dumping disabled", ex); - } catch (IllegalArgumentException iae) { - PlatformLogger.getLogger(ProxyClassesDumper.class.getName()) - .warning(iae.getMessage() + " - dumping disabled"); - } - return null; - } - - private ProxyClassesDumper(Path path) { - dumpDir = Objects.requireNonNull(path); - } - - private static void validateDumpDir(Path path) { - if (!Files.exists(path)) { - throw new IllegalArgumentException("Directory " + path + " does not exist"); - } else if (!Files.isDirectory(path)) { - throw new IllegalArgumentException("Path " + path + " is not a directory"); - } else if (!Files.isWritable(path)) { - throw new IllegalArgumentException("Directory " + path + " is not writable"); - } - } - - public static String encodeForFilename(String className) { - final int len = className.length(); - StringBuilder sb = new StringBuilder(len); - - for (int i = 0; i < len; i++) { - char c = className.charAt(i); - // control characters - if (c <= 31) { - sb.append('%'); - sb.append(HEX[c >> 4 & 0x0F]); - sb.append(HEX[c & 0x0F]); - } else { - int j = 0; - for (; j < BAD_CHARS.length; j++) { - if (c == BAD_CHARS[j]) { - sb.append(REPLACEMENT[j]); - break; - } - } - if (j >= BAD_CHARS.length) { - sb.append(c); - } - } - } - - return sb.toString(); - } - - public void dumpClass(String className, final byte[] classBytes) { - Path file; - try { - file = dumpDir.resolve(encodeForFilename(className) + ".class"); - } catch (InvalidPathException ex) { - PlatformLogger.getLogger(ProxyClassesDumper.class.getName()) - .warning("Invalid path for class " + className); - return; - } - - try { - Path dir = file.getParent(); - Files.createDirectories(dir); - Files.write(file, classBytes); - } catch (Exception ignore) { - PlatformLogger.getLogger(ProxyClassesDumper.class.getName()) - .warning("Exception writing to path at " + file.toString()); - // simply don't care if this operation failed - } - } -} diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/sun/invoke/anon/AnonymousClassLoader.java --- a/rt/emul/compact/src/main/java/sun/invoke/anon/AnonymousClassLoader.java Sun Aug 10 05:56:32 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import sun.misc.IOUtils; - -/** - * Anonymous class loader. Will load any valid classfile, producing - * a {@link Class} metaobject, without installing that class in the - * system dictionary. Therefore, {@link Class#forName(String)} will never - * produce a reference to an anonymous class. - *

- * The access permissions of the anonymous class are borrowed from - * a host class. The new class behaves as if it were an - * inner class of the host class. It can access the host's private - * members, if the creator of the class loader has permission to - * do so (or to create accessible reflective objects). - *

- * When the anonymous class is loaded, elements of its constant pool - * can be patched to new values. This provides a hook to pre-resolve - * named classes in the constant pool to other classes, including - * anonymous ones. Also, string constants can be pre-resolved to - * any reference. (The verifier treats non-string, non-class reference - * constants as plain objects.) - *

- * Why include the patching function? It makes some use cases much easier. - * Second, the constant pool needed some internal patching anyway, - * to anonymize the loaded class itself. Finally, if you are going - * to use this seriously, you'll want to build anonymous classes - * on top of pre-existing anonymous classes, and that requires patching. - * - *

%%% TO-DO: - *

    - *
  • needs better documentation
  • - *
  • needs more security work (for safe delegation)
  • - *
  • needs a clearer story about error processing
  • - *
  • patch member references also (use ';' as delimiter char)
  • - *
  • patch method references to (conforming) method handles
  • - *
- * - * @author jrose - * @author Remi Forax - * @see - * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm - */ - -public class AnonymousClassLoader { - final Class hostClass; - - // Privileged constructor. - private AnonymousClassLoader(Class hostClass) { - this.hostClass = hostClass; - } - - public static AnonymousClassLoader make(sun.misc.Unsafe unsafe, Class hostClass) { - if (unsafe == null) throw new NullPointerException(); - return new AnonymousClassLoader(hostClass); - } - - public Class loadClass(byte[] classFile) { - if (defineAnonymousClass == null) { - // no JVM support; try to fake an approximation - try { - return fakeLoadClass(new ConstantPoolParser(classFile).createPatch()); - } catch (InvalidConstantPoolFormatException ee) { - throw new IllegalArgumentException(ee); - } - } - return loadClass(classFile, null); - } - - public Class loadClass(ConstantPoolPatch classPatch) { - if (defineAnonymousClass == null) { - // no JVM support; try to fake an approximation - return fakeLoadClass(classPatch); - } - Object[] patches = classPatch.patchArray; - // Convert class names (this late in the game) - // to use slash '/' instead of dot '.'. - // Java likes dots, but the JVM likes slashes. - for (int i = 0; i < patches.length; i++) { - Object value = patches[i]; - if (value != null) { - byte tag = classPatch.getTag(i); - switch (tag) { - case ConstantPoolVisitor.CONSTANT_Class: - if (value instanceof String) { - if (patches == classPatch.patchArray) - patches = patches.clone(); - patches[i] = ((String)value).replace('.', '/'); - } - break; - case ConstantPoolVisitor.CONSTANT_Fieldref: - case ConstantPoolVisitor.CONSTANT_Methodref: - case ConstantPoolVisitor.CONSTANT_InterfaceMethodref: - case ConstantPoolVisitor.CONSTANT_NameAndType: - // When/if the JVM supports these patches, - // we'll probably need to reformat them also. - // Meanwhile, let the class loader create the error. - break; - } - } - } - return loadClass(classPatch.outer.classFile, classPatch.patchArray); - } - - private Class loadClass(byte[] classFile, Object[] patchArray) { - try { - return (Class) - defineAnonymousClass.invoke(unsafe, - hostClass, classFile, patchArray); - } catch (Exception ex) { - throwReflectedException(ex); - throw new RuntimeException("error loading into "+hostClass, ex); - } - } - - private static void throwReflectedException(Exception ex) { - if (ex instanceof InvocationTargetException) { - Throwable tex = ((InvocationTargetException)ex).getTargetException(); - if (tex instanceof Error) - throw (Error) tex; - ex = (Exception) tex; - } - if (ex instanceof RuntimeException) { - throw (RuntimeException) ex; - } - } - - private Class fakeLoadClass(ConstantPoolPatch classPatch) { - // Implementation: - // 1. Make up a new name nobody has used yet. - // 2. Inspect the tail-header of the class to find the this_class index. - // 3. Patch the CONSTANT_Class for this_class to the new name. - // 4. Add other CP entries required by (e.g.) string patches. - // 5. Flatten Class constants down to their names, making sure that - // the host class loader can pick them up again accurately. - // 6. Generate the edited class file bytes. - // - // Potential limitations: - // * The class won't be truly anonymous, and may interfere with others. - // * Flattened class constants might not work, because of loader issues. - // * Pseudo-string constants will not flatten down to real strings. - // * Method handles will (of course) fail to flatten to linkage strings. - if (true) throw new UnsupportedOperationException("NYI"); - Object[] cpArray; - try { - cpArray = classPatch.getOriginalCP(); - } catch (InvalidConstantPoolFormatException ex) { - throw new RuntimeException(ex); - } - int thisClassIndex = classPatch.getParser().getThisClassIndex(); - String thisClassName = (String) cpArray[thisClassIndex]; - synchronized (AnonymousClassLoader.class) { - thisClassName = thisClassName+"\\|"+(++fakeNameCounter); - } - classPatch.putUTF8(thisClassIndex, thisClassName); - byte[] classFile = null; - return unsafe.defineClass(null, classFile, 0, classFile.length, - hostClass.getClassLoader(), - hostClass.getProtectionDomain()); - } - private static int fakeNameCounter = 99999; - - // ignore two warnings on this line: - private static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); - // preceding line requires that this class be on the boot class path - - static private final Method defineAnonymousClass; - static { - Method dac = null; - Class unsafeClass = unsafe.getClass(); - try { - dac = unsafeClass.getMethod("defineAnonymousClass", - Class.class, - byte[].class, - Object[].class); - } catch (Exception ee) { - dac = null; - } - defineAnonymousClass = dac; - } - - private static void noJVMSupport() { - throw new UnsupportedOperationException("no JVM support for anonymous classes"); - } - - - private static native Class loadClassInternal(Class hostClass, - byte[] classFile, - Object[] patchArray); - - public static byte[] readClassFile(Class templateClass) throws IOException { - String templateName = templateClass.getName(); - int lastDot = templateName.lastIndexOf('.'); - java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class"); - java.net.URLConnection connection = url.openConnection(); - int contentLength = connection.getContentLength(); - if (contentLength < 0) - throw new IOException("invalid content length "+contentLength); - - return IOUtils.readFully(connection.getInputStream(), contentLength, true); - } -} diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolParser.java --- a/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolParser.java Sun Aug 10 05:56:32 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; - -import static sun.invoke.anon.ConstantPoolVisitor.*; - -/** A constant pool parser. - */ -public class ConstantPoolParser { - final byte[] classFile; - final byte[] tags; - final char[] firstHeader; // maghi, maglo, minor, major, cplen - - // these are filled in on first parse: - int endOffset; - char[] secondHeader; // flags, this_class, super_class, intlen - - // used to decode UTF8 array - private char[] charArray = new char[80]; - - /** Creates a constant pool parser. - * @param classFile an array of bytes containing a class. - * @throws InvalidConstantPoolFormatException if the header of the class has errors. - */ - public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException { - this.classFile = classFile; - this.firstHeader = parseHeader(classFile); - this.tags = new byte[firstHeader[4]]; - } - - /** Create a constant pool parser by loading the bytecodes of the - * class taken as argument. - * - * @param templateClass the class to parse. - * - * @throws IOException raised if an I/O occurs when loading - * the bytecode of the template class. - * @throws InvalidConstantPoolFormatException if the header of the class has errors. - * - * @see #ConstantPoolParser(byte[]) - * @see AnonymousClassLoader#readClassFile(Class) - */ - public ConstantPoolParser(Class templateClass) throws IOException, InvalidConstantPoolFormatException { - this(AnonymousClassLoader.readClassFile(templateClass)); - } - - /** Creates an empty patch to patch the class file - * used by the current parser. - * @return a new class patch. - */ - public ConstantPoolPatch createPatch() { - return new ConstantPoolPatch(this); - } - - /** Report the tag of the indicated CP entry. - * @param index - * @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc. - */ - public byte getTag(int index) { - getEndOffset(); // trigger an exception if we haven't parsed yet - return tags[index]; - } - - /** Report the length of the constant pool. */ - public int getLength() { - return firstHeader[4]; - } - - /** Report the offset, within the class file, of the start of the constant pool. */ - public int getStartOffset() { - return firstHeader.length * 2; - } - - /** Report the offset, within the class file, of the end of the constant pool. */ - public int getEndOffset() { - if (endOffset == 0) - throw new IllegalStateException("class file has not yet been parsed"); - return endOffset; - } - - /** Report the CP index of this class's own name. */ - public int getThisClassIndex() { - getEndOffset(); // provoke exception if not yet parsed - return secondHeader[1]; - } - - /** Report the total size of the class file. */ - public int getTailLength() { - return classFile.length - getEndOffset(); - } - - /** Write the head (header plus constant pool) - * of the class file to the indicated stream. - */ - public void writeHead(OutputStream out) throws IOException { - out.write(classFile, 0, getEndOffset()); - } - - /** Write the head (header plus constant pool) - * of the class file to the indicated stream, - * incorporating the non-null entries of the given array - * as patches. - */ - void writePatchedHead(OutputStream out, Object[] patchArray) { - // this will be useful to partially emulate the class loader on old JVMs - throw new UnsupportedOperationException("Not yet implemented"); - } - - /** Write the tail (everything after the constant pool) - * of the class file to the indicated stream. - */ - public void writeTail(OutputStream out) throws IOException { - out.write(classFile, getEndOffset(), getTailLength()); - } - - private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException { - char[] result = new char[5]; - ByteBuffer buffer = ByteBuffer.wrap(classFile); - for (int i = 0; i < result.length; i++) - result[i] = (char) getUnsignedShort(buffer); - int magic = result[0] << 16 | result[1] << 0; - if (magic != 0xCAFEBABE) - throw new InvalidConstantPoolFormatException("invalid magic number "+magic); - // skip major, minor version - int len = result[4]; - if (len < 1) - throw new InvalidConstantPoolFormatException("constant pool length < 1"); - return result; - } - - /** Parse the constant pool of the class - * calling a method visit* each time a constant pool entry is parsed. - * - * The order of the calls to visit* is not guaranteed to be the same - * than the order of the constant pool entry in the bytecode array. - * - * @param visitor - * @throws InvalidConstantPoolFormatException - */ - public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException { - ByteBuffer buffer = ByteBuffer.wrap(classFile); - buffer.position(getStartOffset()); //skip header - - Object[] values = new Object[getLength()]; - try { - parseConstantPool(buffer, values, visitor); - } catch(BufferUnderflowException e) { - throw new InvalidConstantPoolFormatException(e); - } - if (endOffset == 0) { - endOffset = buffer.position(); - secondHeader = new char[4]; - for (int i = 0; i < secondHeader.length; i++) { - secondHeader[i] = (char) getUnsignedShort(buffer); - } - } - resolveConstantPool(values, visitor); - } - - private char[] getCharArray(int utfLength) { - if (utfLength <= charArray.length) - return charArray; - return charArray = new char[utfLength]; - } - - private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException { - for (int i = 1; i < tags.length; ) { - byte tag = (byte) getUnsignedByte(buffer); - assert(tags[i] == 0 || tags[i] == tag); - tags[i] = tag; - switch (tag) { - case CONSTANT_Utf8: - int utfLen = getUnsignedShort(buffer); - String value = getUTF8(buffer, utfLen, getCharArray(utfLen)); - visitor.visitUTF8(i, CONSTANT_Utf8, value); - tags[i] = tag; - values[i++] = value; - break; - case CONSTANT_Integer: - visitor.visitConstantValue(i, tag, buffer.getInt()); - i++; - break; - case CONSTANT_Float: - visitor.visitConstantValue(i, tag, buffer.getFloat()); - i++; - break; - case CONSTANT_Long: - visitor.visitConstantValue(i, tag, buffer.getLong()); - i+=2; - break; - case CONSTANT_Double: - visitor.visitConstantValue(i, tag, buffer.getDouble()); - i+=2; - break; - - case CONSTANT_Class: // fall through: - case CONSTANT_String: - tags[i] = tag; - values[i++] = new int[] { getUnsignedShort(buffer) }; - break; - - case CONSTANT_Fieldref: // fall through: - case CONSTANT_Methodref: // fall through: - case CONSTANT_InterfaceMethodref: // fall through: - case CONSTANT_NameAndType: - tags[i] = tag; - values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) }; - break; - default: - throw new AssertionError("invalid constant "+tag); - } - } - } - - private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) { - // clean out the int[] values, which are temporary - for (int beg = 1, end = values.length-1, beg2, end2; - beg <= end; - beg = beg2, end = end2) { - beg2 = end; end2 = beg-1; - //System.out.println("CP resolve pass: "+beg+".."+end); - for (int i = beg; i <= end; i++) { - Object value = values[i]; - if (!(value instanceof int[])) - continue; - int[] array = (int[]) value; - byte tag = tags[i]; - switch (tag) { - case CONSTANT_String: - String stringBody = (String) values[array[0]]; - visitor.visitConstantString(i, tag, stringBody, array[0]); - values[i] = null; - break; - case CONSTANT_Class: { - String className = (String) values[array[0]]; - // use the external form favored by Class.forName: - className = className.replace('/', '.'); - visitor.visitConstantString(i, tag, className, array[0]); - values[i] = className; - break; - } - case CONSTANT_NameAndType: { - String memberName = (String) values[array[0]]; - String signature = (String) values[array[1]]; - visitor.visitDescriptor(i, tag, memberName, signature, - array[0], array[1]); - values[i] = new String[] {memberName, signature}; - break; - } - case CONSTANT_Fieldref: // fall through: - case CONSTANT_Methodref: // fall through: - case CONSTANT_InterfaceMethodref: { - Object className = values[array[0]]; - Object nameAndType = values[array[1]]; - if (!(className instanceof String) || - !(nameAndType instanceof String[])) { - // one more pass is needed - if (beg2 > i) beg2 = i; - if (end2 < i) end2 = i; - continue; - } - String[] nameAndTypeArray = (String[]) nameAndType; - visitor.visitMemberRef(i, tag, - (String)className, - nameAndTypeArray[0], - nameAndTypeArray[1], - array[0], array[1]); - values[i] = null; - } - break; - default: - continue; - } - } - } - } - - private static int getUnsignedByte(ByteBuffer buffer) { - return buffer.get() & 0xFF; - } - - private static int getUnsignedShort(ByteBuffer buffer) { - int b1 = getUnsignedByte(buffer); - int b2 = getUnsignedByte(buffer); - return (b1 << 8) + (b2 << 0); - } - - private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException { - int utfLimit = buffer.position() + utfLen; - int index = 0; - while (buffer.position() < utfLimit) { - int c = buffer.get() & 0xff; - if (c > 127) { - buffer.position(buffer.position() - 1); - return getUTF8Extended(buffer, utfLimit, charArray, index); - } - charArray[index++] = (char)c; - } - return new String(charArray, 0, index); - } - - private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException { - int c, c2, c3; - while (buffer.position() < utfLimit) { - c = buffer.get() & 0xff; - switch (c >> 4) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - /* 0xxxxxxx*/ - charArray[index++] = (char)c; - break; - case 12: case 13: - /* 110x xxxx 10xx xxxx*/ - c2 = buffer.get(); - if ((c2 & 0xC0) != 0x80) - throw new InvalidConstantPoolFormatException( - "malformed input around byte " + buffer.position()); - charArray[index++] = (char)(((c & 0x1F) << 6) | - (c2 & 0x3F)); - break; - case 14: - /* 1110 xxxx 10xx xxxx 10xx xxxx */ - c2 = buffer.get(); - c3 = buffer.get(); - if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) - throw new InvalidConstantPoolFormatException( - "malformed input around byte " + (buffer.position())); - charArray[index++] = (char)(((c & 0x0F) << 12) | - ((c2 & 0x3F) << 6) | - ((c3 & 0x3F) << 0)); - break; - default: - /* 10xx xxxx, 1111 xxxx */ - throw new InvalidConstantPoolFormatException( - "malformed input around byte " + buffer.position()); - } - } - // The number of chars produced may be less than utflen - return new String(charArray, 0, index); - } -} diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolPatch.java --- a/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolPatch.java Sun Aug 10 05:56:32 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,503 +0,0 @@ -/* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Map; - -import static sun.invoke.anon.ConstantPoolVisitor.*; - -/** A class and its patched constant pool. - * - * This class allow to modify (patch) a constant pool - * by changing the value of its entry. - * Entry are referenced using index that can be get - * by parsing the constant pool using - * {@link ConstantPoolParser#parse(ConstantPoolVisitor)}. - * - * @see ConstantPoolVisitor - * @see ConstantPoolParser#createPatch() - */ -public class ConstantPoolPatch { - final ConstantPoolParser outer; - final Object[] patchArray; - - ConstantPoolPatch(ConstantPoolParser outer) { - this.outer = outer; - this.patchArray = new Object[outer.getLength()]; - } - - /** Create a {@link ConstantPoolParser} and - * a {@link ConstantPoolPatch} in one step. - * Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}. - * - * @param classFile an array of bytes containing a class. - * @see #ConstantPoolParser(Class) - */ - public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException { - this(new ConstantPoolParser(classFile)); - } - - /** Create a {@link ConstantPoolParser} and - * a {@link ConstantPoolPatch} in one step. - * Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}. - * - * @param templateClass the class to parse. - * @see #ConstantPoolParser(Class) - */ - public ConstantPoolPatch(Class templateClass) throws IOException, InvalidConstantPoolFormatException { - this(new ConstantPoolParser(templateClass)); - } - - - /** Creates a patch from an existing patch. - * All changes are copied from that patch. - * @param patch a patch - * - * @see ConstantPoolParser#createPatch() - */ - public ConstantPoolPatch(ConstantPoolPatch patch) { - outer = patch.outer; - patchArray = patch.patchArray.clone(); - } - - /** Which parser built this patch? */ - public ConstantPoolParser getParser() { - return outer; - } - - /** Report the tag at the given index in the constant pool. */ - public byte getTag(int index) { - return outer.getTag(index); - } - - /** Report the current patch at the given index of the constant pool. - * Null means no patch will be made. - * To observe the unpatched entry at the given index, use - * {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)} - */ - public Object getPatch(int index) { - Object value = patchArray[index]; - if (value == null) return null; - switch (getTag(index)) { - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - if (value instanceof String) - value = stripSemis(2, (String) value); - break; - case CONSTANT_NameAndType: - if (value instanceof String) - value = stripSemis(1, (String) value); - break; - } - return value; - } - - /** Clear all patches. */ - public void clear() { - Arrays.fill(patchArray, null); - } - - /** Clear one patch. */ - public void clear(int index) { - patchArray[index] = null; - } - - /** Produce the patches as an array. */ - public Object[] getPatches() { - return patchArray.clone(); - } - - /** Produce the original constant pool as an array. */ - public Object[] getOriginalCP() throws InvalidConstantPoolFormatException { - return getOriginalCP(0, patchArray.length, -1); - } - - /** Walk the constant pool, applying patches using the given map. - * - * @param utf8Map Utf8 strings to modify, if encountered - * @param classMap Classes (or their names) to modify, if encountered - * @param valueMap Constant values to modify, if encountered - * @param deleteUsedEntries if true, delete map entries that are used - */ - public void putPatches(final Map utf8Map, - final Map classMap, - final Map valueMap, - boolean deleteUsedEntries) throws InvalidConstantPoolFormatException { - final HashSet usedUtf8Keys; - final HashSet usedClassKeys; - final HashSet usedValueKeys; - if (deleteUsedEntries) { - usedUtf8Keys = (utf8Map == null) ? null : new HashSet(); - usedClassKeys = (classMap == null) ? null : new HashSet(); - usedValueKeys = (valueMap == null) ? null : new HashSet(); - } else { - usedUtf8Keys = null; - usedClassKeys = null; - usedValueKeys = null; - } - - outer.parse(new ConstantPoolVisitor() { - - @Override - public void visitUTF8(int index, byte tag, String utf8) { - putUTF8(index, utf8Map.get(utf8)); - if (usedUtf8Keys != null) usedUtf8Keys.add(utf8); - } - - @Override - public void visitConstantValue(int index, byte tag, Object value) { - putConstantValue(index, tag, valueMap.get(value)); - if (usedValueKeys != null) usedValueKeys.add(value); - } - - @Override - public void visitConstantString(int index, byte tag, String name, int nameIndex) { - if (tag == CONSTANT_Class) { - putConstantValue(index, tag, classMap.get(name)); - if (usedClassKeys != null) usedClassKeys.add(name); - } else { - assert(tag == CONSTANT_String); - visitConstantValue(index, tag, name); - } - } - }); - if (usedUtf8Keys != null) utf8Map.keySet().removeAll(usedUtf8Keys); - if (usedClassKeys != null) classMap.keySet().removeAll(usedClassKeys); - if (usedValueKeys != null) valueMap.keySet().removeAll(usedValueKeys); - } - - Object[] getOriginalCP(final int startIndex, - final int endIndex, - final int tagMask) throws InvalidConstantPoolFormatException { - final Object[] cpArray = new Object[endIndex - startIndex]; - outer.parse(new ConstantPoolVisitor() { - - void show(int index, byte tag, Object value) { - if (index < startIndex || index >= endIndex) return; - if (((1 << tag) & tagMask) == 0) return; - cpArray[index - startIndex] = value; - } - - @Override - public void visitUTF8(int index, byte tag, String utf8) { - show(index, tag, utf8); - } - - @Override - public void visitConstantValue(int index, byte tag, Object value) { - assert(tag != CONSTANT_String); - show(index, tag, value); - } - - @Override - public void visitConstantString(int index, byte tag, - String value, int j) { - show(index, tag, value); - } - - @Override - public void visitMemberRef(int index, byte tag, - String className, String memberName, - String signature, - int j, int k) { - show(index, tag, new String[]{ className, memberName, signature }); - } - - @Override - public void visitDescriptor(int index, byte tag, - String memberName, String signature, - int j, int k) { - show(index, tag, new String[]{ memberName, signature }); - } - }); - return cpArray; - } - - /** Write the head (header plus constant pool) - * of the patched class file to the indicated stream. - */ - void writeHead(OutputStream out) throws IOException { - outer.writePatchedHead(out, patchArray); - } - - /** Write the tail (everything after the constant pool) - * of the patched class file to the indicated stream. - */ - void writeTail(OutputStream out) throws IOException { - outer.writeTail(out); - } - - private void checkConstantTag(byte tag, Object value) { - if (value == null) - throw new IllegalArgumentException( - "invalid null constant value"); - if (classForTag(tag) != value.getClass()) - throw new IllegalArgumentException( - "invalid constant value" - + (tag == CONSTANT_None ? "" - : " for tag "+tagName(tag)) - + " of class "+value.getClass()); - } - - private void checkTag(int index, byte putTag) { - byte tag = outer.tags[index]; - if (tag != putTag) - throw new IllegalArgumentException( - "invalid put operation" - + " for " + tagName(putTag) - + " at index " + index + " found " + tagName(tag)); - } - - private void checkTagMask(int index, int tagBitMask) { - byte tag = outer.tags[index]; - int tagBit = ((tag & 0x1F) == tag) ? (1 << tag) : 0; - if ((tagBit & tagBitMask) == 0) - throw new IllegalArgumentException( - "invalid put operation" - + " at index " + index + " found " + tagName(tag)); - } - - private static void checkMemberName(String memberName) { - if (memberName.indexOf(';') >= 0) - throw new IllegalArgumentException("memberName " + memberName + " contains a ';'"); - } - - /** Set the entry of the constant pool indexed by index to - * a new string. - * - * @param index an index to a constant pool entry containing a - * {@link ConstantPoolVisitor#CONSTANT_Utf8} value. - * @param utf8 a string - * - * @see ConstantPoolVisitor#visitUTF8(int, byte, String) - */ - public void putUTF8(int index, String utf8) { - if (utf8 == null) { clear(index); return; } - checkTag(index, CONSTANT_Utf8); - patchArray[index] = utf8; - } - - /** Set the entry of the constant pool indexed by index to - * a new value, depending on its dynamic type. - * - * @param index an index to a constant pool entry containing a - * one of the following structures: - * {@link ConstantPoolVisitor#CONSTANT_Integer}, - * {@link ConstantPoolVisitor#CONSTANT_Float}, - * {@link ConstantPoolVisitor#CONSTANT_Long}, - * {@link ConstantPoolVisitor#CONSTANT_Double}, - * {@link ConstantPoolVisitor#CONSTANT_String}, or - * {@link ConstantPoolVisitor#CONSTANT_Class} - * @param value a boxed int, float, long or double; or a string or class object - * @throws IllegalArgumentException if the type of the constant does not - * match the constant pool entry type, - * as reported by {@link #getTag(int)} - * - * @see #putConstantValue(int, byte, Object) - * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object) - * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int) - */ - public void putConstantValue(int index, Object value) { - if (value == null) { clear(index); return; } - byte tag = tagForConstant(value.getClass()); - checkConstantTag(tag, value); - checkTag(index, tag); - patchArray[index] = value; - } - - /** Set the entry of the constant pool indexed by index to - * a new value. - * - * @param index an index to a constant pool entry matching the given tag - * @param tag one of the following values: - * {@link ConstantPoolVisitor#CONSTANT_Integer}, - * {@link ConstantPoolVisitor#CONSTANT_Float}, - * {@link ConstantPoolVisitor#CONSTANT_Long}, - * {@link ConstantPoolVisitor#CONSTANT_Double}, - * {@link ConstantPoolVisitor#CONSTANT_String}, or - * {@link ConstantPoolVisitor#CONSTANT_Class} - * @param value a boxed number, string, or class object - * @throws IllegalArgumentException if the type of the constant does not - * match the constant pool entry type, or if a class name contains - * '/' or ';' - * - * @see #putConstantValue(int, Object) - * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object) - * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int) - */ - public void putConstantValue(int index, byte tag, Object value) { - if (value == null) { clear(index); return; } - checkTag(index, tag); - if (tag == CONSTANT_Class && value instanceof String) { - checkClassName((String) value); - } else if (tag == CONSTANT_String) { - // the JVM accepts any object as a patch for a string - } else { - // make sure the incoming value is the right type - checkConstantTag(tag, value); - } - checkTag(index, tag); - patchArray[index] = value; - } - - /** Set the entry of the constant pool indexed by index to - * a new {@link ConstantPoolVisitor#CONSTANT_NameAndType} value. - * - * @param index an index to a constant pool entry containing a - * {@link ConstantPoolVisitor#CONSTANT_NameAndType} value. - * @param memberName a memberName - * @param signature a signature - * @throws IllegalArgumentException if memberName contains the character ';' - * - * @see ConstantPoolVisitor#visitDescriptor(int, byte, String, String, int, int) - */ - public void putDescriptor(int index, String memberName, String signature) { - checkTag(index, CONSTANT_NameAndType); - checkMemberName(memberName); - patchArray[index] = addSemis(memberName, signature); - } - - /** Set the entry of the constant pool indexed by index to - * a new {@link ConstantPoolVisitor#CONSTANT_Fieldref}, - * {@link ConstantPoolVisitor#CONSTANT_Methodref}, or - * {@link ConstantPoolVisitor#CONSTANT_InterfaceMethodref} value. - * - * @param index an index to a constant pool entry containing a member reference - * @param className a class name - * @param memberName a field or method name - * @param signature a field or method signature - * @throws IllegalArgumentException if memberName contains the character ';' - * or signature is not a correct signature - * - * @see ConstantPoolVisitor#visitMemberRef(int, byte, String, String, String, int, int) - */ - public void putMemberRef(int index, byte tag, - String className, String memberName, String signature) { - checkTagMask(tag, CONSTANT_MemberRef_MASK); - checkTag(index, tag); - checkClassName(className); - checkMemberName(memberName); - if (signature.startsWith("(") == (tag == CONSTANT_Fieldref)) - throw new IllegalArgumentException("bad signature: "+signature); - patchArray[index] = addSemis(className, memberName, signature); - } - - static private final int CONSTANT_MemberRef_MASK = - CONSTANT_Fieldref - | CONSTANT_Methodref - | CONSTANT_InterfaceMethodref; - - private static final Map, Byte> CONSTANT_VALUE_CLASS_TAG - = new IdentityHashMap, Byte>(); - private static final Class[] CONSTANT_VALUE_CLASS = new Class[16]; - static { - Object[][] values = { - {Integer.class, CONSTANT_Integer}, - {Long.class, CONSTANT_Long}, - {Float.class, CONSTANT_Float}, - {Double.class, CONSTANT_Double}, - {String.class, CONSTANT_String}, - {Class.class, CONSTANT_Class} - }; - for (Object[] value : values) { - Class cls = (Class)value[0]; - Byte tag = (Byte) value[1]; - CONSTANT_VALUE_CLASS_TAG.put(cls, tag); - CONSTANT_VALUE_CLASS[(byte)tag] = cls; - } - } - - static Class classForTag(byte tag) { - if ((tag & 0xFF) >= CONSTANT_VALUE_CLASS.length) - return null; - return CONSTANT_VALUE_CLASS[tag]; - } - - static byte tagForConstant(Class cls) { - Byte tag = CONSTANT_VALUE_CLASS_TAG.get(cls); - return (tag == null) ? CONSTANT_None : (byte)tag; - } - - private static void checkClassName(String className) { - if (className.indexOf('/') >= 0 || className.indexOf(';') >= 0) - throw new IllegalArgumentException("invalid class name " + className); - } - - static String addSemis(String name, String... names) { - StringBuilder buf = new StringBuilder(name.length() * 5); - buf.append(name); - for (String name2 : names) { - buf.append(';').append(name2); - } - String res = buf.toString(); - assert(stripSemis(names.length, res)[0].equals(name)); - assert(stripSemis(names.length, res)[1].equals(names[0])); - assert(names.length == 1 || - stripSemis(names.length, res)[2].equals(names[1])); - return res; - } - - static String[] stripSemis(int count, String string) { - String[] res = new String[count+1]; - int pos = 0; - for (int i = 0; i < count; i++) { - int pos2 = string.indexOf(';', pos); - if (pos2 < 0) pos2 = string.length(); // yuck - res[i] = string.substring(pos, pos2); - pos = pos2; - } - res[count] = string.substring(pos); - return res; - } - - public String toString() { - StringBuilder buf = new StringBuilder(this.getClass().getName()); - buf.append("{"); - Object[] origCP = null; - for (int i = 0; i < patchArray.length; i++) { - if (patchArray[i] == null) continue; - if (origCP != null) { - buf.append(", "); - } else { - try { - origCP = getOriginalCP(); - } catch (InvalidConstantPoolFormatException ee) { - origCP = new Object[0]; - } - } - Object orig = (i < origCP.length) ? origCP[i] : "?"; - buf.append(orig).append("=").append(patchArray[i]); - } - buf.append("}"); - return buf.toString(); - } -} diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolVisitor.java --- a/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolVisitor.java Sun Aug 10 05:56:32 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -/** - * A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)} - * when a constant pool entry is parsed. - *

- * A visit* method is called when a constant pool entry is parsed. - * The first argument is always the constant pool index. - * The second argument is always the constant pool tag, - * even for methods like {@link #visitUTF8(int, byte, String)} which only apply to one tag. - * String arguments refer to Utf8 or NameAndType entries declared elsewhere, - * and are always accompanied by the indexes of those entries. - *

- * The order of the calls to the visit* methods is not necessarily related - * to the order of the entries in the constant pool. - * If one entry has a reference to another entry, the latter (lower-level) - * entry will be visited first. - *

- * The following table shows the relation between constant pool entry - * types and the corresponding visit* methods: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Tag(s)Method
{@link #CONSTANT_Utf8}{@link #visitUTF8(int, byte, String)}
{@link #CONSTANT_Integer}, {@link #CONSTANT_Float}, - * {@link #CONSTANT_Long}, {@link #CONSTANT_Double}{@link #visitConstantValue(int, byte, Object)}
{@link #CONSTANT_String}, {@link #CONSTANT_Class}{@link #visitConstantString(int, byte, String, int)}
{@link #CONSTANT_NameAndType}{@link #visitDescriptor(int, byte, String, String, int, int)}
{@link #CONSTANT_Fieldref}, - * {@link #CONSTANT_Methodref}, - * {@link #CONSTANT_InterfaceMethodref}{@link #visitMemberRef(int, byte, String, String, String, int, int)}
- * - * @see ConstantPoolPatch - * @author Remi Forax - * @author jrose - */ -public class ConstantPoolVisitor { - /** Called each time an UTF8 constant pool entry is found. - * @param index the constant pool index - * @param tag always {@link #CONSTANT_Utf8} - * @param utf8 string encoded in modified UTF-8 format passed as a {@code String} - * - * @see ConstantPoolPatch#putUTF8(int, String) - */ - public void visitUTF8(int index, byte tag, String utf8) { - // do nothing - } - - /** Called for each constant pool entry that encodes an integer, - * a float, a long, or a double. - * Constant strings and classes are not managed by this method but - * by {@link #visitConstantString(int, byte, String, int)}. - * - * @param index the constant pool index - * @param tag one of {@link #CONSTANT_Integer}, - * {@link #CONSTANT_Float}, - * {@link #CONSTANT_Long}, - * or {@link #CONSTANT_Double} - * @param value encoded value - * - * @see ConstantPoolPatch#putConstantValue(int, Object) - */ - public void visitConstantValue(int index, byte tag, Object value) { - // do nothing - } - - /** Called for each constant pool entry that encodes a string or a class. - * @param index the constant pool index - * @param tag one of {@link #CONSTANT_String}, - * {@link #CONSTANT_Class}, - * @param name string body or class name (using dot separator) - * @param nameIndex the index of the Utf8 string for the name - * - * @see ConstantPoolPatch#putConstantValue(int, byte, Object) - */ - public void visitConstantString(int index, byte tag, - String name, int nameIndex) { - // do nothing - } - - /** Called for each constant pool entry that encodes a name and type. - * @param index the constant pool index - * @param tag always {@link #CONSTANT_NameAndType} - * @param memberName a field or method name - * @param signature the member signature - * @param memberNameIndex index of the Utf8 string for the member name - * @param signatureIndex index of the Utf8 string for the signature - * - * @see ConstantPoolPatch#putDescriptor(int, String, String) - */ - public void visitDescriptor(int index, byte tag, - String memberName, String signature, - int memberNameIndex, int signatureIndex) { - // do nothing - } - - /** Called for each constant pool entry that encodes a field or method. - * @param index the constant pool index - * @param tag one of {@link #CONSTANT_Fieldref}, - * or {@link #CONSTANT_Methodref}, - * or {@link #CONSTANT_InterfaceMethodref} - * @param className the class name (using dot separator) - * @param memberName name of the field or method - * @param signature the field or method signature - * @param classNameIndex index of the Utf8 string for the class name - * @param descriptorIndex index of the NameAndType descriptor constant - * - * @see ConstantPoolPatch#putMemberRef(int, byte, String, String, String) - */ - public void visitMemberRef(int index, byte tag, - String className, String memberName, String signature, - int classNameIndex, int descriptorIndex) { - // do nothing - } - - public static final byte - CONSTANT_None = 0, - CONSTANT_Utf8 = 1, - //CONSTANT_Unicode = 2, /* unused */ - CONSTANT_Integer = 3, - CONSTANT_Float = 4, - CONSTANT_Long = 5, - CONSTANT_Double = 6, - CONSTANT_Class = 7, - CONSTANT_String = 8, - CONSTANT_Fieldref = 9, - CONSTANT_Methodref = 10, - CONSTANT_InterfaceMethodref = 11, - CONSTANT_NameAndType = 12; - - private static String[] TAG_NAMES = { - "Empty", - "Utf8", - null, //"Unicode", - "Integer", - "Float", - "Long", - "Double", - "Class", - "String", - "Fieldref", - "Methodref", - "InterfaceMethodref", - "NameAndType" - }; - - public static String tagName(byte tag) { - String name = null; - if ((tag & 0xFF) < TAG_NAMES.length) - name = TAG_NAMES[tag]; - if (name == null) - name = "Unknown#"+(tag&0xFF); - return name; - } -} diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/sun/invoke/anon/InvalidConstantPoolFormatException.java --- a/rt/emul/compact/src/main/java/sun/invoke/anon/InvalidConstantPoolFormatException.java Sun Aug 10 05:56:32 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -/** Exception used when there is an error in the constant pool - * format. - */ -public class InvalidConstantPoolFormatException extends Exception { - private static final long serialVersionUID=-6103888330523770949L; - - public InvalidConstantPoolFormatException(String message,Throwable cause) { - super(message,cause); - } - - public InvalidConstantPoolFormatException(String message) { - super(message); - } - - public InvalidConstantPoolFormatException(Throwable cause) { - super(cause); - } -} diff -r 6799184bf769 -r 5c990ed353e9 rt/emul/compact/src/main/java/sun/invoke/util/VerifyAccess.java --- a/rt/emul/compact/src/main/java/sun/invoke/util/VerifyAccess.java Sun Aug 10 05:56:32 2014 +0200 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/VerifyAccess.java Sun Aug 10 06:13:36 2014 +0200 @@ -27,7 +27,6 @@ import java.lang.reflect.Modifier; import static java.lang.reflect.Modifier.*; -import sun.reflect.Reflection; /** * This class centralizes information about the JVM's linkage access control. @@ -144,7 +143,8 @@ // ...But arrays and primitives are synthesized with their own odd flags: if (c.isArray() || c.isPrimitive()) return c.getModifiers(); - return Reflection.getClassAccessFlags(c); + return c.getModifiers(); +// return Reflection.getClassAccessFlags(c); } /** @@ -263,10 +263,11 @@ } private static Class getOutermostEnclosingClass(Class c) { - Class pkgmem = c; - for (Class enc = c; (enc = enc.getEnclosingClass()) != null; ) - pkgmem = enc; - return pkgmem; + throw new IllegalStateException("Needed?"); +// Class pkgmem = c; +// for (Class enc = c; (enc = enc.getEnclosingClass()) != null; ) +// pkgmem = enc; +// return pkgmem; } private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,