changeset 428:a65758cae648

meth: small bug fixes; MR1 comments; copyright headers
author jrose
date Wed, 22 Aug 2012 16:37:49 -0700
parents 6fb74815fa12
children a8e6272996ec
files meth.patch
diffstat 1 files changed, 621 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/meth.patch	Tue Aug 21 16:35:24 2012 -0700
+++ b/meth.patch	Wed Aug 22 16:37:49 2012 -0700
@@ -1,8 +1,70 @@
 # Unsorted changes to method handles are entrained here.
+0000000: an attempt to use "<init>" as a method name should elicit NoSuchMethodException
+0000000: arity mismatch on a call to spreader method handle should elicit WrongMethodTypeException
+add comments where MR1 changes are likely
+update copyright headers
 
+diff --git a/src/share/classes/java/lang/invoke/CallSite.java b/src/share/classes/java/lang/invoke/CallSite.java
+--- a/src/share/classes/java/lang/invoke/CallSite.java
++++ b/src/share/classes/java/lang/invoke/CallSite.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+@@ -289,7 +289,7 @@
+                 throw new ClassCastException("bootstrap method failed to produce a CallSite");
+             }
+             if (!site.getTarget().type().equals(type))
+-                throw new WrongMethodTypeException("wrong type: "+site.getTarget());
++                throw wrongTargetType(site.getTarget(), type);
+         } catch (Throwable ex) {
+             BootstrapMethodError bex;
+             if (ex instanceof BootstrapMethodError)
+diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+--- 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, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
+--- a/src/share/classes/java/lang/invoke/Invokers.java
++++ b/src/share/classes/java/lang/invoke/Invokers.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
+--- a/src/share/classes/java/lang/invoke/LambdaForm.java
++++ b/src/share/classes/java/lang/invoke/LambdaForm.java
+@@ -180,7 +180,7 @@
+         assert(isValidSignature(basicTypeSignature));
+         int resultPos = arity + 1;  // skip '_'
+         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
+-            throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
++            throw newIllegalArgumentException("bad arity", basicTypeSignature);
+         int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
+         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
+         for (int i = 0; i < numRes; i++) {
 diff --git a/src/share/classes/java/lang/invoke/MemberName.java b/src/share/classes/java/lang/invoke/MemberName.java
 --- a/src/share/classes/java/lang/invoke/MemberName.java
 +++ b/src/share/classes/java/lang/invoke/MemberName.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
 @@ -299,19 +299,9 @@
          assert(getReferenceKind() == oldKind);
          assert(MethodHandleNatives.refKindIsValid(refKind));
@@ -23,15 +85,571 @@
      private boolean testFlags(int mask, int value) {
          return (flags & mask) == value;
      }
-@@ -452,8 +442,10 @@
+@@ -452,7 +442,9 @@
          this.clazz = defClass;
          this.name = name;
          this.type = type;
 -        setFlags(flags);
 +        this.flags = flags;
 +        assert(testAnyFlags(ALL_KINDS));
++        assert(referenceKindIsConsistent());  // do this after resolution also
          assert(this.resolution == null);  // nobody should have touched this yet
-+        //assert(referenceKindIsConsistent());  // do this after resolution
      }
  
-     private void expandFromVM() {
+@@ -494,14 +486,14 @@
+         case REF_invokeVirtual:     return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
+         case REF_newInvokeSpecial:  return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
+         }
+-        throw new IllegalArgumentException(this.toString());
++        throw newIllegalArgumentException("cannot be made special", this);
+     }
+     public MemberName asConstructor() {
+         switch (getReferenceKind()) {
+         case REF_invokeSpecial:     return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
+         case REF_newInvokeSpecial:  return this;
+         }
+-        throw new IllegalArgumentException(this.toString());
++        throw newIllegalArgumentException("cannot be made constructor", this);
+     }
+     /** Create a name for the given reflected constructor.  The resulting name will be in a resolved state. */
+     @SuppressWarnings("LeakingThisInConstructor")
+@@ -570,7 +562,7 @@
+      *  This may be in a super-class of the declaring class of this member.
+      */
+     public MemberName getDefinition() {
+-        if (!isResolved())  throw new IllegalStateException("must be resolved: "+this);
++        if (!isResolved())  throw newIllegalStateException("must be resolved", this);
+         if (isType())  return this;
+         MemberName res = this.clone();
+         res.clazz = null;
+@@ -614,15 +606,6 @@
+         init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
+         initResolved(false);
+     }
+-    /** Create a field or type name from the given components:  Declaring class, name, type.
+-     *  The declaring class may be supplied as null if this is to be a bare name and type.
+-     *  The modifier flags default to zero.
+-     *  The resulting name will in an unresolved state.
+-     */
+-    public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
+-        this(defClass, name, type, REF_NONE);
+-        initResolved(false);
+-    }
+     /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
+      *  It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
+      *  The declaring class may be supplied as null if this is to be a bare name and type.
+@@ -635,15 +618,6 @@
+         init(defClass, name, type, flagsMods(flags, 0, refKind));
+         initResolved(false);
+     }
+-//    /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
+-//     *  It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
+-//     *  The declaring class may be supplied as null if this is to be a bare name and type.
+-//     *  The modifier flags default to zero.
+-//     *  The resulting name will in an unresolved state.
+-//     */
+-//    public MemberName(Class<?> defClass, String name, MethodType type, Void unused) {
+-//        this(defClass, name, type, REF_NONE);
+-//    }
+ 
+     /** Query whether this member name is resolved to a non-static, non-final method.
+      */
+diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
+--- 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, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+@@ -31,8 +31,6 @@
+ import sun.misc.Unsafe;
+ 
+ import static java.lang.invoke.MethodHandleStatics.*;
+-import java.util.logging.Level;
+-import java.util.logging.Logger;
+ 
+ /**
+  * A method handle is a typed, directly executable reference to an underlying method,
+@@ -803,6 +801,7 @@
+      * @throws WrongMethodTypeException if the implied {@code asType} call fails
+      * @see #asCollector
+      */
++    //FIXME in MR1: clarify that after spreading, if there is an arity mismatch, WMTE is raised
+     public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
+         asSpreaderChecks(arrayType, arrayLength);
+         int spreadArgPos = type.parameterCount() - arrayLength;
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+--- 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, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+@@ -107,7 +107,7 @@
+         }
+         static String name(Class<?> arrayClass, boolean isSetter) {
+             Class<?> elemClass = arrayClass.getComponentType();
+-            if (elemClass == null)  throw new IllegalArgumentException();
++            if (elemClass == null)  throw newIllegalArgumentException("not an array", arrayClass);
+             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
+         }
+         static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false;  // FIXME: decide
+@@ -452,7 +452,7 @@
+     static void checkSpreadArgument(Object av, int n) {
+         // FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE
+         // but the actual exception raised by an arity mismatch should be WMTE
+-        final boolean RAISE_RANDOM_EXCEPTIONS = true;  // FIXME: delete in JSR 292 M1
++        final boolean RAISE_RANDOM_EXCEPTIONS = false;  // FIXME in MR1: set this to false and remove
+         if (av == null) {
+             if (n == 0)  return;
+             int len;
+@@ -468,7 +468,7 @@
+         // fall through to error:
+         if (RAISE_RANDOM_EXCEPTIONS)
+             throw newIllegalArgumentException("Array is not of length "+n);
+-        throw new WrongMethodTypeException("Array is not of length "+n);
++        throw new WrongMethodTypeException("array is not of length "+n);
+     }
+ 
+     private static final NamedFunction NF_checkSpreadArgument;
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+@@ -26,7 +26,8 @@
+ package java.lang.invoke;
+ import java.lang.invoke.MethodHandleNatives.Constants;
+ 
+-//Not yet public: public
++/*not public*/
++// FIXME in MR1: Make this a public API
+ class MethodHandleInfo {
+    public static final int
+        REF_NONE                    = Constants.REF_NONE,
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+@@ -28,6 +28,7 @@
+ import java.lang.reflect.*;
+ import sun.invoke.WrapperInstance;
+ import java.util.ArrayList;
++import static java.lang.invoke.MethodHandleStatics.*;
+ 
+ /**
+  * This class consists exclusively of static methods that help adapt
+@@ -136,10 +137,10 @@
+     public static
+     <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
+         if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
+-            throw new IllegalArgumentException("not a public interface: "+intfc.getName());
++            throw newIllegalArgumentException("not a public interface", intfc.getName());
+         final Method[] methods = getSingleNameMethods(intfc);
+         if (methods == null)
+-            throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
++            throw newIllegalArgumentException("not a single-method interface", intfc.getName());
+         final MethodHandle[] vaTargets = new MethodHandle[methods.length];
+         for (int i = 0; i < methods.length; i++) {
+             Method sm = methods[i];
+@@ -187,7 +188,7 @@
+                 return (WrapperInstance) x;
+         } catch (ClassCastException ex) {
+         }
+-        throw new IllegalArgumentException("not a wrapper instance");
++        throw newIllegalArgumentException("not a wrapper instance");
+     }
+ 
+     /**
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2011, 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
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- 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, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+@@ -329,6 +329,7 @@
+      *     where {@code defcPkg} is the package of {@code defc}.
+      * </ul>
+      */
++    // FIXME in MR1: clarify that the name "<init>" never works as a method name, even if the corresponding constructor happens to exist
+     public static final
+     class Lookup {
+         /** The class on behalf of whom the lookup is being performed. */
+@@ -643,6 +644,7 @@
+          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+          * @throws NullPointerException if any argument is null
+          */
++        // FIXME in MR1: clarify that name="<init>" elicits a NoSuchMethodException always (ctor != method)
+         public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+             if (refc == MethodHandle.class) {
+                 MethodHandle mh = findVirtualForMH(name, type);
+@@ -729,6 +731,8 @@
+          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+          * @throws NullPointerException if any argument is null
+          */
++        // FIXME in MR1: clarify that specialCaller access check happens first
++        // FIXME in MR1: clarify that name="<init>" elicits a NoSuchMethodException always (ctor != method)
+         public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
+                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
+             checkSpecialCaller(specialCaller);
+@@ -964,7 +968,7 @@
+          *                                is set and {@code asVarargsCollector} fails
+          * @throws NullPointerException if the argument is null
+          */
+-        @SuppressWarnings("rawtypes")  // Will be Constructor<?> after JSR 292 MR
++        @SuppressWarnings("rawtypes")  // FIXME in MR1: add wildcard to be Constructor<?>
+         public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
+             MemberName ctor = new MemberName(c);
+             assert(ctor.isConstructor());
+@@ -1019,15 +1023,16 @@
+         /// Helper methods, all package-private.
+ 
+         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
++            name.getClass(); type.getClass();  // NPE
+             checkSymbolicClass(refc);  // do this before attempting to resolve
+-            name.getClass(); type.getClass();  // NPE
+             return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
+                                             NoSuchFieldException.class);
+         }
+ 
+         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
++            type.getClass();  // NPE
+             checkSymbolicClass(refc);  // do this before attempting to resolve
+-            name.getClass(); type.getClass();  // NPE
++            checkMethodName(refKind, name);
+             return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
+                                             NoSuchMethodException.class);
+         }
+@@ -1038,6 +1043,12 @@
+                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
+         }
+ 
++        void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
++            if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
++                throw new NoSuchMethodException("illegal method name: "+name);
++        }
++
++
+         /**
+          * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
+          * This function performs stack walk magic: do not refactor it.
+@@ -1337,7 +1348,7 @@
+     static public
+     MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
+         if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
+-            throw new IllegalArgumentException("bad argument count "+leadingArgCount);
++            throw newIllegalArgumentException("bad argument count", leadingArgCount);
+         return type.invokers().spreadInvoker(leadingArgCount);
+     }
+ 
+@@ -1876,7 +1887,7 @@
+         return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+     }
+ 
+-    // FIXME: Make this public in M1.
++    // FIXME in MR1: Make this a public API
+     /*non-public*/ static
+     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle collector) {
+         MethodType targetType = target.type();
+diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
+--- a/src/share/classes/java/lang/invoke/MethodType.java
++++ b/src/share/classes/java/lang/invoke/MethodType.java
+@@ -882,7 +882,7 @@
+         if (!descriptor.startsWith("(") ||  // also generates NPE if needed
+             descriptor.indexOf(')') < 0 ||
+             descriptor.indexOf('.') >= 0)
+-            throw new IllegalArgumentException("not a method descriptor: "+descriptor);
++            throw newIllegalArgumentException("not a method descriptor", descriptor);
+         List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
+         Class<?> rtype = types.remove(types.size() - 1);
+         checkSlotCount(types.size());
+diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+--- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
++++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+@@ -27,8 +27,6 @@
+ 
+ import static java.lang.invoke.LambdaForm.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
+-import java.util.logging.Level;
+-import java.util.logging.Logger;
+ 
+ /**
+  * A method handle whose behavior is determined only by its LambdaForm.
+diff --git a/src/share/classes/java/lang/invoke/WrongMethodTypeException.java b/src/share/classes/java/lang/invoke/WrongMethodTypeException.java
+--- a/src/share/classes/java/lang/invoke/WrongMethodTypeException.java
++++ b/src/share/classes/java/lang/invoke/WrongMethodTypeException.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+diff --git a/src/share/classes/java/lang/invoke/package-info.java b/src/share/classes/java/lang/invoke/package-info.java
+--- a/src/share/classes/java/lang/invoke/package-info.java
++++ b/src/share/classes/java/lang/invoke/package-info.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * 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
+diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
+--- a/test/java/lang/invoke/MethodHandlesTest.java
++++ b/test/java/lang/invoke/MethodHandlesTest.java
+@@ -363,6 +363,7 @@
+         protected Example(String name) { this.name = name; }
+         @SuppressWarnings("LeakingThisInConstructor")
+         protected Example(int x) { this(); called("protected <init>", this, x); }
++        //Example(Void x) { does not exist; lookup elicts NoSuchMethodException }
+         @Override public String toString() { return name; }
+ 
+         public void            v0()     { called("v0", this); }
+@@ -463,6 +464,9 @@
+         return lookup.in(defc);
+     }
+ 
++    /** Is findVirtual (etc.) of "<init>" supposed to elicit a NoSuchMethodException? */
++    final static boolean INIT_REF_CAUSES_NSME = true;
++
+     @Test
+     public void testFindStatic() throws Throwable {
+         if (CAN_SKIP_WORKING)  return;
+@@ -483,6 +487,8 @@
+         testFindStatic(Example.class, Object.class, "s7", float.class, double.class);
+ 
+         testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");
++        testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class);
++        testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
+         testFindStatic(false, PRIVATE, Example.class, void.class, "v0");
+     }
+ 
+@@ -505,11 +511,12 @@
+             target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
+@@ -527,6 +534,13 @@
+             System.out.print(':');
+     }
+ 
++    static void assertExceptionClass(Class<? extends Throwable> expected,
++                                     Throwable actual) {
++        if (expected.isInstance(actual))  return;
++        actual.printStackTrace();
++        assertEquals(expected, actual.getClass());
++    }
++
+     static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+ 
+     // rough check of name string
+@@ -556,6 +570,8 @@
+         testFindVirtual(PubExample.class, void.class, "Pub/pro_v0");
+ 
+         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");
++        testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class);
++        testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class);
+         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");
+ 
+         // test dispatch
+@@ -591,11 +607,12 @@
+             target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
+@@ -632,11 +649,11 @@
+         testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
+         testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
+         // Do some negative testing:
+-        testFindSpecial(false, EXAMPLE, SubExample.class, Example.class, void.class, "bogus");
+-        testFindSpecial(false, PRIVATE, SubExample.class, Example.class, void.class, "bogus");
+         for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
+             testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
++            testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
+             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
++            testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
+             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
+         }
+     }
+@@ -662,19 +679,25 @@
+         countTest(positive);
+         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
+         MethodType type = MethodType.methodType(ret, params);
++        Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
++        boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
++                                   (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
+         MethodHandle target = null;
+         Exception noAccess = null;
+         try {
+             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
+-            if (verbosity >= 5)  System.out.println("  lookup => "+maybeMoveIn(lookup, specialCaller));
+-            target = maybeMoveIn(lookup, specialCaller).findSpecial(defc, methodName, type, specialCaller);
++            if (verbosity >= 5)  System.out.println("  lookup => "+specialLookup);
++            target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (!specialAccessOK)  // this check should happen first
++                ?   IllegalAccessException.class
++                : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                : IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
+@@ -719,7 +742,7 @@
+             target = lookup.findConstructor(defc, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
+-            assertTrue(noAccess instanceof IllegalAccessException);
++            assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
+@@ -750,6 +773,8 @@
+         testBind(Example.class, Object.class, "v2", int.class, Object.class);
+         testBind(Example.class, Object.class, "v2", int.class, int.class);
+         testBind(false, PRIVATE, Example.class, void.class, "bogus");
++        testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class);
++        testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
+         testBind(SubExample.class, void.class, "Sub/v0");
+         testBind(SubExample.class, void.class, "Sub/pkg_v0");
+         testBind(IntExample.Impl.class, void.class, "Int/v0");
+@@ -773,11 +798,12 @@
+             target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
+@@ -840,6 +866,10 @@
+         countTest(positive);
+         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
+         MethodType type = MethodType.methodType(ret, params);
++        Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null);
++        boolean specialAccessOK = (specialCaller != null &&
++                                   specialLookup.lookupClass() == specialCaller &&
++                                   (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
+         Method rmethod = defc.getDeclaredMethod(methodName, params);
+         MethodHandle target = null;
+         Exception noAccess = null;
+@@ -848,16 +878,15 @@
+         try {
+             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
+             if (isSpecial)
+-                target = maybeMoveIn(lookup, specialCaller).unreflectSpecial(rmethod, specialCaller);
++                target = specialLookup.unreflectSpecial(rmethod, specialCaller);
+             else
+                 target = maybeMoveIn(lookup, defc).unreflect(rmethod);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                IllegalAccessException.class,  // NSME is impossible, since it was already reflected
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
+@@ -1091,11 +1120,12 @@
+         } catch (ReflectiveOperationException ex) {
+             mh = null;
+             noAccess = ex;
++            assertExceptionClass(
++                (fname.contains("bogus"))
++                ?   NoSuchFieldException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (fname.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchFieldException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype