Merge
diff --git a/makefiles/profile-rtjar-includes.txt b/makefiles/profile-rtjar-includes.txt
index 4722727..4cc528e 100644
--- a/makefiles/profile-rtjar-includes.txt
+++ b/makefiles/profile-rtjar-includes.txt
@@ -349,6 +349,7 @@
     com/sun/rowset/providers \
     com/sun/script/javascript \
     com/sun/script/util \
+    com/sun/security/auth \
     com/sun/security/auth/callback \
     com/sun/security/auth/login \
     com/sun/security/auth/module \
@@ -448,8 +449,7 @@
     sun/tracing \
     sun/tracing/dtrace
 
-PROFILE_3_RTJAR_INCLUDE_TYPES := \
-    com/sun/security/auth/*.class
+PROFILE_3_RTJAR_INCLUDE_TYPES :=
 
 PROFILE_3_RTJAR_EXCLUDE_TYPES := \
     javax/management/remote/rmi/_RMIConnectionImpl_Tie.class \
@@ -457,10 +457,10 @@
     javax/management/remote/rmi/_RMIServerImpl_Tie.class \
     javax/management/remote/rmi/_RMIServer_Stub.class \
     com/sun/security/auth/callback/DialogCallbackHandler.class \
-    com/sun/security/auth/callback/DialogCallbackHandler\$$$$1.class \
-    com/sun/security/auth/callback/DialogCallbackHandler\$$$$2.class \
-    com/sun/security/auth/callback/DialogCallbackHandler\$$$$Action.class \
-    com/sun/security/auth/callback/DialogCallbackHandler\$$$$ConfirmationInfo.class
+    com/sun/security/auth/callback/DialogCallbackHandler\$$1.class \
+    com/sun/security/auth/callback/DialogCallbackHandler\$$2.class \
+    com/sun/security/auth/callback/DialogCallbackHandler\$$Action.class \
+    com/sun/security/auth/callback/DialogCallbackHandler\$$ConfirmationInfo.class
 
 PROFILE_3_INCLUDE_METAINF_SERVICES := \
     META-INF/services/javax.script.ScriptEngineFactory 
diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
index db8d35f..7793bc2 100644
--- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -65,8 +65,7 @@
     }
 
     // Factory methods:
-
-    static DirectMethodHandle make(Class<?> receiver, MemberName member) {
+    static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) {
         MethodType mtype = member.getMethodOrFieldType();
         if (!member.isStatic()) {
             if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
@@ -74,8 +73,14 @@
             mtype = mtype.insertParameterTypes(0, receiver);
         }
         if (!member.isField()) {
-            LambdaForm lform = preparedLambdaForm(member);
-            return new DirectMethodHandle(mtype, lform, member);
+            if (refKind == REF_invokeSpecial) {
+                member = member.asSpecial();
+                LambdaForm lform = preparedLambdaForm(member);
+                return new Special(mtype, lform, member);
+            } else {
+                LambdaForm lform = preparedLambdaForm(member);
+                return new DirectMethodHandle(mtype, lform, member);
+            }
         } else {
             LambdaForm lform = preparedFieldLambdaForm(member);
             if (member.isStatic()) {
@@ -89,6 +94,12 @@
             }
         }
     }
+    static DirectMethodHandle make(Class<?> receiver, MemberName member) {
+        byte refKind = member.getReferenceKind();
+        if (refKind == REF_invokeSpecial)
+            refKind =  REF_invokeVirtual;
+        return make(refKind, receiver, member);
+    }
     static DirectMethodHandle make(MemberName member) {
         if (member.isConstructor())
             return makeAllocator(member);
@@ -124,6 +135,10 @@
 
     //// Implementation methods.
     @Override
+    MethodHandle viewAsType(MethodType newType) {
+        return new DirectMethodHandle(newType, form, member);
+    }
+    @Override
     @ForceInline
     MemberName internalMemberName() {
         return member;
@@ -367,6 +382,21 @@
         ((DirectMethodHandle)mh).ensureInitialized();
     }
 
+    /** This subclass represents invokespecial instructions. */
+    static class Special extends DirectMethodHandle {
+        private Special(MethodType mtype, LambdaForm form, MemberName member) {
+            super(mtype, form, member);
+        }
+        @Override
+        boolean isInvokeSpecial() {
+            return true;
+        }
+        @Override
+        MethodHandle viewAsType(MethodType newType) {
+            return new Special(newType, form, member);
+        }
+    }
+
     /** This subclass handles constructor references. */
     static class Constructor extends DirectMethodHandle {
         final MemberName initMethod;
@@ -379,6 +409,10 @@
             this.instanceClass = instanceClass;
             assert(initMethod.isResolved());
         }
+        @Override
+        MethodHandle viewAsType(MethodType newType) {
+            return new Constructor(newType, form, member, initMethod, instanceClass);
+        }
     }
 
     /*non-public*/ static Object constructorMethod(Object mh) {
@@ -405,6 +439,10 @@
         @Override Object checkCast(Object obj) {
             return fieldType.cast(obj);
         }
+        @Override
+        MethodHandle viewAsType(MethodType newType) {
+            return new Accessor(newType, form, member, fieldOffset);
+        }
     }
 
     @ForceInline
@@ -444,6 +482,10 @@
         @Override Object checkCast(Object obj) {
             return fieldType.cast(obj);
         }
+        @Override
+        MethodHandle viewAsType(MethodType newType) {
+            return new StaticAccessor(newType, form, member, staticBase, staticOffset);
+        }
     }
 
     @ForceInline
diff --git a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
index f2bb8eb..f7191f7 100644
--- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
+++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
@@ -53,7 +53,7 @@
     private static final String NAME_OBJECT = "java/lang/Object";
     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
             = MethodType.methodType(void.class,
-                                    String.class,
+                                    Class.class,
                                     int.class, String.class, String.class, String.class,
                                     int.class, String.class, String.class, String.class,
                                     String.class,
@@ -284,7 +284,7 @@
         mv.visitCode();
         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
         mv.visitInsn(DUP);;
-        mv.visitLdcInsn(targetClass.getName().replace('.', '/'));
+        mv.visitLdcInsn(Type.getType(targetClass));
         mv.visitLdcInsn(samInfo.getReferenceKind());
         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
         mv.visitLdcInsn(samInfo.getName());
diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
index aa323eb..774faff 100644
--- a/src/share/classes/java/lang/invoke/MethodHandle.java
+++ b/src/share/classes/java/lang/invoke/MethodHandle.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -1250,8 +1250,6 @@
     /*non-public*/
     MethodHandle viewAsType(MethodType newType) {
         // No actual conversions, just a new view of the same method.
-        if (!type.isViewableAs(newType))
-            throw new InternalError();
         return MethodHandleImpl.makePairwiseConvert(this, newType, 0);
     }
 
@@ -1268,6 +1266,11 @@
     }
 
     /*non-public*/
+    boolean isInvokeSpecial() {
+        return false;  // DMH.Special returns true
+    }
+
+    /*non-public*/
     Object internalValues() {
         return null;
     }
diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
index 1b35e0f..a18a7a4 100644
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -367,11 +367,11 @@
 
         @Override
         MethodHandle viewAsType(MethodType newType) {
-            MethodHandle mh = super.viewAsType(newType);
+            if (newType.lastParameterType() != type().lastParameterType())
+                throw new InternalError();
+            MethodHandle newTarget = asFixedArity().viewAsType(newType);
             // put back the varargs bit:
-            MethodType type = mh.type();
-            int arity = type.parameterCount();
-            return mh.asVarargsCollector(type.parameterType(arity-1));
+            return new AsVarargsCollector(newTarget, newType, arrayType);
         }
 
         @Override
@@ -379,6 +379,12 @@
             return asFixedArity().internalMemberName();
         }
 
+        /*non-public*/
+        @Override
+        boolean isInvokeSpecial() {
+            return asFixedArity().isInvokeSpecial();
+        }
+
 
         @Override
         MethodHandle bindArgument(int pos, char basicType, Object value) {
diff --git a/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
index ae579ab..380ca59 100644
--- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -32,7 +32,6 @@
  */
 final class MethodHandleInfo {
    public static final int
-       REF_NONE                    = Constants.REF_NONE,
        REF_getField                = Constants.REF_getField,
        REF_getStatic               = Constants.REF_getStatic,
        REF_putField                = Constants.REF_putField,
@@ -48,12 +47,17 @@
    private final MethodType methodType;
    private final int referenceKind;
 
-   public MethodHandleInfo(MethodHandle mh) throws ReflectiveOperationException {
+   public MethodHandleInfo(MethodHandle mh) {
        MemberName mn = mh.internalMemberName();
+       if (mn == null)  throw new IllegalArgumentException("not a direct method handle");
        this.declaringClass = mn.getDeclaringClass();
        this.name = mn.getName();
-       this.methodType = mn.getMethodType();
-       this.referenceKind = mn.getReferenceKind();
+       this.methodType = mn.getMethodOrFieldType();
+       byte refKind = mn.getReferenceKind();
+       if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial())
+           // Devirtualized method invocation is usually formally virtual.
+           refKind = REF_invokeVirtual;
+       this.referenceKind = refKind;
    }
 
    public Class<?> getDeclaringClass() {
@@ -78,7 +82,6 @@
 
    static String getReferenceKindString(int referenceKind) {
         switch (referenceKind) {
-            case REF_NONE: return "REF_NONE";
             case REF_getField: return "getfield";
             case REF_getStatic: return "getstatic";
             case REF_putField: return "putfield";
diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
index d2a499e..f4cad4d 100644
--- a/src/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -1237,7 +1237,7 @@
             checkMethod(refKind, refc, method);
             if (method.isMethodHandleInvoke())
                 return fakeMethodHandleInvoke(method);
-            MethodHandle mh = DirectMethodHandle.make(refc, method);
+            MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
             mh = maybeBindCaller(method, mh, callerClass);
             mh = mh.setVarargs(method);
             if (doRestrict)
diff --git a/src/share/classes/java/lang/invoke/SerializedLambda.java b/src/share/classes/java/lang/invoke/SerializedLambda.java
index 1a2db3f..3679e3f 100644
--- a/src/share/classes/java/lang/invoke/SerializedLambda.java
+++ b/src/share/classes/java/lang/invoke/SerializedLambda.java
@@ -40,7 +40,7 @@
  */
 public final class SerializedLambda implements Serializable {
     private static final long serialVersionUID = 8025925345765570181L;
-    private final String capturingClass;
+    private final Class<?> capturingClass;
     private final String functionalInterfaceClass;
     private final String functionalInterfaceMethodName;
     private final String functionalInterfaceMethodSignature;
@@ -73,7 +73,7 @@
      * @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by
      *                     the lambda
      */
-    public SerializedLambda(String capturingClass,
+    public SerializedLambda(Class<?> capturingClass,
                             int functionalInterfaceMethodKind,
                             String functionalInterfaceClass,
                             String functionalInterfaceMethodName,
@@ -99,7 +99,7 @@
 
     /** Get the name of the class that captured this lambda */
     public String getCapturingClass() {
-        return capturingClass;
+        return capturingClass.getName().replace('.', '/');
     }
 
     /** Get the name of the functional interface class to which this lambda has been converted */
@@ -166,9 +166,7 @@
             Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
                 @Override
                 public Method run() throws Exception {
-                    Class<?> clazz = Class.forName(capturingClass.replace('/', '.'), true,
-                                                   Thread.currentThread().getContextClassLoader());
-                    Method m = clazz.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
+                    Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
                     m.setAccessible(true);
                     return m;
                 }
@@ -196,14 +194,4 @@
                              MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName,
                              implMethodSignature, instantiatedMethodType, capturedArgs.length);
     }
-
-    /*
-    // @@@ Review question: is it worthwhile implementing a versioned serialization protocol?
-
-    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
-    }
-
-    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
-    }
-*/
 }
diff --git a/test/java/lang/invoke/7087570/Test7087570.java b/test/java/lang/invoke/7087570/Test7087570.java
new file mode 100644
index 0000000..572facc
--- /dev/null
+++ b/test/java/lang/invoke/7087570/Test7087570.java
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+/* @test
+ * @bug 7087570
+ * @summary REF_invokeSpecial DMHs (which are unusual) get marked explicitly; tweak the MHI to use this bit
+ *
+ * @run main Test7087570
+ */
+
+import java.lang.invoke.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+
+public class Test7087570 {
+    // XXX may remove the following constant declarations when MethodHandleInfo is made public
+    private static final int
+            REF_getField                = 1,
+            REF_getStatic               = 2,
+            REF_putField                = 3,
+            REF_putStatic               = 4,
+            REF_invokeVirtual           = 5,
+            REF_invokeStatic            = 6,
+            REF_invokeSpecial           = 7,
+            REF_newInvokeSpecial        = 8,
+            REF_invokeInterface         = 9,
+            REF_LIMIT                  = 10;
+
+    private static final TestMethodData[] TESTS = new TestMethodData[] {
+        // field accessors
+        data(DummyFieldHolder.class, "instanceField", getterMethodType(String.class), DummyFieldHolder.class, REF_getField),
+        data(DummyFieldHolder.class, "instanceField", setterMethodType(String.class), DummyFieldHolder.class, REF_putField),
+        data(DummyFieldHolder.class, "staticField", getterMethodType(Integer.class), DummyFieldHolder.class, REF_getStatic),
+        data(DummyFieldHolder.class, "staticField", setterMethodType(Integer.class), DummyFieldHolder.class, REF_putStatic),
+        data(DummyFieldHolder.class, "instanceByteField", getterMethodType(byte.class), DummyFieldHolder.class, REF_getField),
+        data(DummyFieldHolder.class, "instanceByteField", setterMethodType(byte.class), DummyFieldHolder.class, REF_putField),
+
+        // REF_invokeVirtual
+        data(Object.class, "hashCode", methodType(int.class), Object.class, REF_invokeVirtual),
+
+        // REF_invokeVirtual strength-reduced to REF_invokeSpecial,
+        // test if it normalizes back to REF_invokeVirtual in MethodHandleInfo as expected
+        data(String.class, "hashCode", methodType(int.class), String.class, REF_invokeVirtual),
+
+        // REF_invokeStatic
+        data(Collections.class, "sort", methodType(void.class, List.class), Collections.class, REF_invokeStatic),
+        data(Arrays.class, "asList", methodType(List.class, Object[].class), Arrays.class, REF_invokeStatic), // varargs case
+
+        // REF_invokeSpecial
+        data(Object.class, "hashCode", methodType(int.class), Object.class, REF_invokeSpecial),
+
+        // REF_newInvokeSpecial
+        data(String.class, "<init>", methodType(void.class, char[].class), String.class, REF_newInvokeSpecial),
+        data(DummyFieldHolder.class, "<init>", methodType(void.class, byte.class, Long[].class), DummyFieldHolder.class, REF_newInvokeSpecial), // varargs case
+
+        // REF_invokeInterface
+        data(List.class, "size", methodType(int.class), List.class, REF_invokeInterface)
+    };
+
+    public static void main(String... args) throws Throwable {
+        testWithLookup();
+        testWithUnreflect();
+    }
+
+    private static void doTest(MethodHandle mh, TestMethodData testMethod) {
+        Object mhi = newMethodHandleInfo(mh);
+
+        System.out.printf("%s.%s: %s, nominal refKind: %s, actual refKind: %s\n",
+                          testMethod.clazz.getName(), testMethod.name, testMethod.methodType,
+                          REF_KIND_NAMES[testMethod.referenceKind],
+                          REF_KIND_NAMES[getReferenceKind(mhi)]);
+        assertEquals(testMethod.name,           getName(mhi));
+        assertEquals(testMethod.methodType,     getMethodType(mhi));
+        assertEquals(testMethod.declaringClass, getDeclaringClass(mhi));
+        assertEquals(testMethod.referenceKind == REF_invokeSpecial, isInvokeSpecial(mh));
+        assertRefKindEquals(testMethod.referenceKind,  getReferenceKind(mhi));
+    }
+
+    private static void testWithLookup() throws Throwable {
+        for (TestMethodData testMethod : TESTS) {
+            MethodHandle mh = lookupFrom(testMethod);
+            doTest(mh, testMethod);
+        }
+    }
+
+    private static void testWithUnreflect() throws Throwable {
+        for (TestMethodData testMethod : TESTS) {
+            MethodHandle mh = unreflectFrom(testMethod);
+            doTest(mh, testMethod);
+        }
+    }
+
+    private static MethodType getterMethodType(Class<?> clazz) {
+        return methodType(clazz);
+    }
+
+    private static MethodType setterMethodType(Class<?> clazz) {
+        return methodType(void.class, clazz);
+    }
+
+    private static final String[] REF_KIND_NAMES = {
+        "MH::invokeBasic",
+        "REF_getField", "REF_getStatic", "REF_putField", "REF_putStatic",
+        "REF_invokeVirtual", "REF_invokeStatic", "REF_invokeSpecial",
+        "REF_newInvokeSpecial", "REF_invokeInterface"
+    };
+
+    private static final Lookup LOOKUP = lookup();
+
+    // XXX may remove the following reflective logic when MethodHandleInfo is made public
+    private static final MethodHandle MH_IS_INVOKESPECIAL;
+    private static final MethodHandle MHI_CONSTRUCTOR;
+    private static final MethodHandle MHI_GET_NAME;
+    private static final MethodHandle MHI_GET_METHOD_TYPE;
+    private static final MethodHandle MHI_GET_DECLARING_CLASS;
+    private static final MethodHandle MHI_GET_REFERENCE_KIND;
+
+    static {
+        try {
+            // This is white box testing.  Use reflection to grab private implementation bits.
+            String magicName = "IMPL_LOOKUP";
+            Field magicLookup = MethodHandles.Lookup.class.getDeclaredField(magicName);
+            // This unit test will fail if a security manager is installed.
+            magicLookup.setAccessible(true);
+            // Forbidden fruit...
+            Lookup directInvokeLookup = (Lookup) magicLookup.get(null);
+            Class<?> mhiClass = Class.forName("java.lang.invoke.MethodHandleInfo", false, MethodHandle.class.getClassLoader());
+            MH_IS_INVOKESPECIAL = directInvokeLookup
+                    .findVirtual(MethodHandle.class, "isInvokeSpecial", methodType(boolean.class));
+            MHI_CONSTRUCTOR = directInvokeLookup
+                    .findConstructor(mhiClass, methodType(void.class, MethodHandle.class));
+            MHI_GET_NAME = directInvokeLookup
+                    .findVirtual(mhiClass, "getName", methodType(String.class));
+            MHI_GET_METHOD_TYPE = directInvokeLookup
+                    .findVirtual(mhiClass, "getMethodType", methodType(MethodType.class));
+            MHI_GET_DECLARING_CLASS = directInvokeLookup
+                    .findVirtual(mhiClass, "getDeclaringClass", methodType(Class.class));
+            MHI_GET_REFERENCE_KIND = directInvokeLookup
+                    .findVirtual(mhiClass, "getReferenceKind", methodType(int.class));
+        } catch (ReflectiveOperationException ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static class TestMethodData {
+        final Class<?> clazz;
+        final String name;
+        final MethodType methodType;
+        final Class<?> declaringClass;
+        final int referenceKind; // the nominal refKind
+
+        public TestMethodData(Class<?> clazz, String name,
+                        MethodType methodType, Class<?> declaringClass,
+                        int referenceKind) {
+            this.clazz = clazz;
+            this.name = name;
+            this.methodType = methodType;
+            this.declaringClass = declaringClass;
+            this.referenceKind = referenceKind;
+        }
+    }
+
+    private static TestMethodData data(Class<?> clazz, String name,
+                                       MethodType methodType, Class<?> declaringClass,
+                                       int referenceKind) {
+        return new TestMethodData(clazz, name, methodType, declaringClass, referenceKind);
+    }
+
+    private static MethodHandle lookupFrom(TestMethodData testMethod)
+            throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
+        switch (testMethod.referenceKind) {
+        case REF_getField:
+            return LOOKUP.findGetter(testMethod.clazz, testMethod.name, testMethod.methodType.returnType());
+        case REF_putField:
+            return LOOKUP.findSetter(testMethod.clazz, testMethod.name, testMethod.methodType.parameterType(0));
+        case REF_getStatic:
+            return LOOKUP.findStaticGetter(testMethod.clazz, testMethod.name, testMethod.methodType.returnType());
+        case REF_putStatic:
+            return LOOKUP.findStaticSetter(testMethod.clazz, testMethod.name, testMethod.methodType.parameterType(0));
+        case REF_invokeVirtual:
+        case REF_invokeInterface:
+            return LOOKUP.findVirtual(testMethod.clazz, testMethod.name, testMethod.methodType);
+        case REF_invokeStatic:
+            return LOOKUP.findStatic(testMethod.clazz, testMethod.name, testMethod.methodType);
+        case REF_invokeSpecial:
+            Class<?> thisClass = LOOKUP.lookupClass();
+            return LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass);
+        case REF_newInvokeSpecial:
+            return LOOKUP.findConstructor(testMethod.clazz, testMethod.methodType);
+        default:
+            throw new Error("ERROR: unexpected referenceKind in test data");
+        }
+    }
+
+    private static MethodHandle unreflectFrom(TestMethodData testMethod)
+            throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
+        switch (testMethod.referenceKind) {
+        case REF_getField:
+        case REF_getStatic: {
+                Field f = testMethod.clazz.getDeclaredField(testMethod.name);
+                return LOOKUP.unreflectGetter(f);
+            }
+        case REF_putField:
+        case REF_putStatic: {
+                Field f = testMethod.clazz.getDeclaredField(testMethod.name);
+                return LOOKUP.unreflectSetter(f);
+            }
+        case REF_invokeVirtual:
+        case REF_invokeStatic:
+        case REF_invokeInterface: {
+                Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray());
+                return LOOKUP.unreflect(m);
+            }
+        case REF_invokeSpecial: {
+                Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray());
+                Class<?> thisClass = LOOKUP.lookupClass();
+                return LOOKUP.unreflectSpecial(m, thisClass);
+            }
+        case REF_newInvokeSpecial: {
+                Constructor c = testMethod.clazz.getDeclaredConstructor(testMethod.methodType.parameterArray());
+                return LOOKUP.unreflectConstructor(c);
+            }
+        default:
+            throw new Error("ERROR: unexpected referenceKind in test data");
+        }
+    }
+
+    private static Object newMethodHandleInfo(MethodHandle mh) {
+        try {
+            return MHI_CONSTRUCTOR.invoke(mh);
+        } catch (Throwable ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static boolean isInvokeSpecial(MethodHandle mh) {
+        try {
+            return (boolean) MH_IS_INVOKESPECIAL.invokeExact(mh);
+        } catch (Throwable ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static String getName(Object mhi) {
+        try {
+            return (String) MHI_GET_NAME.invoke(mhi);
+        } catch (Throwable ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static MethodType getMethodType(Object mhi) {
+        try {
+            return (MethodType) MHI_GET_METHOD_TYPE.invoke(mhi);
+        } catch (Throwable ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static Class<?> getDeclaringClass(Object mhi) {
+        try {
+            return (Class<?>) MHI_GET_DECLARING_CLASS.invoke(mhi);
+        } catch (Throwable ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static int getReferenceKind(Object mhi) {
+        try {
+            return (int) MHI_GET_REFERENCE_KIND.invoke(mhi);
+        } catch (Throwable ex) {
+            throw new Error(ex);
+        }
+    }
+
+    private static void assertRefKindEquals(int expect, int observed) {
+        if (expect == observed) return;
+
+        String msg = "expected " + REF_KIND_NAMES[(int) expect] +
+                     " but observed " + REF_KIND_NAMES[(int) observed];
+        System.out.println("FAILED: " + msg);
+        throw new AssertionError(msg);
+    }
+
+    private static void assertEquals(Object expect, Object observed) {
+        if (java.util.Objects.equals(expect, observed)) return;
+
+        String msg = "expected " + expect + " but observed " + observed;
+        System.out.println("FAILED: " + msg);
+        throw new AssertionError(msg);
+    }
+}
+
+class DummyFieldHolder {
+    public static Integer staticField;
+    public String instanceField;
+    public byte instanceByteField;
+
+    public DummyFieldHolder(byte unused1, Long... unused2) {
+    }
+}
+
diff --git a/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java b/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java
new file mode 100644
index 0000000..9d38102
--- /dev/null
+++ b/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+@test
+@bug 8004970
+@summary Lambda serialization in the presence of class loaders
+@author Peter Levart
+*/
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Arrays;
+
+public class LambdaClassLoaderSerialization {
+
+    public interface SerializableRunnable extends Runnable, Serializable {}
+
+    public static class MyCode implements SerializableRunnable {
+
+        private byte[] serialize(Object o) {
+            ByteArrayOutputStream baos;
+            try (
+                ObjectOutputStream oos =
+                    new ObjectOutputStream(baos = new ByteArrayOutputStream())
+            ) {
+                oos.writeObject(o);
+            }
+            catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            return baos.toByteArray();
+        }
+
+        private <T> T deserialize(byte[] bytes) {
+            try (
+                ObjectInputStream ois =
+                    new ObjectInputStream(new ByteArrayInputStream(bytes))
+            ) {
+                return (T) ois.readObject();
+            }
+            catch (IOException | ClassNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public void run() {
+            System.out.println("                this: " + this);
+
+            SerializableRunnable deSerializedThis = deserialize(serialize(this));
+            System.out.println("    deSerializedThis: " + deSerializedThis);
+
+            SerializableRunnable runnable = () -> {System.out.println("HELLO");};
+            System.out.println("            runnable: " + runnable);
+
+            SerializableRunnable deSerializedRunnable = deserialize(serialize(runnable));
+            System.out.println("deSerializedRunnable: " + deSerializedRunnable);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        ClassLoader myCl = new MyClassLoader(
+            LambdaClassLoaderSerialization.class.getClassLoader()
+        );
+        Class<?> myCodeClass = Class.forName(
+            LambdaClassLoaderSerialization.class.getName() + "$MyCode",
+            true,
+            myCl
+        );
+        Runnable myCode = (Runnable) myCodeClass.newInstance();
+        myCode.run();
+    }
+
+    static class MyClassLoader extends ClassLoader {
+        MyClassLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        @Override
+        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+            if (name.indexOf('.') < 0) {
+                synchronized (getClassLoadingLock(name)) {
+                    Class<?> c = findLoadedClass(name);
+                    if (c == null) {
+                        c = findClass(name);
+                    }
+                    if (resolve) {
+                        resolveClass(c);
+                    }
+                    return c;
+                }
+            } else {
+                return super.loadClass(name, resolve);
+            }
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            String path = name.replace('.', '/').concat(".class");
+            try (InputStream is = getResourceAsStream(path)) {
+                if (is != null) {
+                    byte[] bytes = readFully(is);
+                    return defineClass(name, bytes, 0, bytes.length);
+                } else {
+                    throw new ClassNotFoundException(name);
+                }
+            }
+            catch (IOException e) {
+                throw new ClassNotFoundException(name, e);
+            }
+        }
+
+        static byte[] readFully(InputStream is) throws IOException {
+            byte[] output = {};
+            int pos = 0;
+            while (true) {
+                int bytesToRead;
+                if (pos >= output.length) { // Only expand when there's no room
+                    bytesToRead = output.length + 1024;
+                    if (output.length < pos + bytesToRead) {
+                        output = Arrays.copyOf(output, pos + bytesToRead);
+                    }
+                } else {
+                    bytesToRead = output.length - pos;
+                }
+                int cc = is.read(output, pos, bytesToRead);
+                if (cc < 0) {
+                    if (output.length != pos) {
+                        output = Arrays.copyOf(output, pos);
+                    }
+                    break;
+                }
+                pos += cc;
+            }
+            return output;
+        }
+    }
+}
diff --git a/test/java/lang/invoke/lambda/LambdaSerialization.java b/test/java/lang/invoke/lambda/LambdaSerialization.java
index ebe846b..6d681c3 100644
--- a/test/java/lang/invoke/lambda/LambdaSerialization.java
+++ b/test/java/lang/invoke/lambda/LambdaSerialization.java
@@ -25,7 +25,6 @@
 @test
 @bug 8004970
 @summary Lambda serialization
-@run main/othervm LambdaSerialization
 */
 
 import java.io.*;