提交 b22436cb 编写于 作者: J jrose

8001108: an attempt to use "<init>" as a method name should elicit NoSuchMethodException

Summary: add an explicit check for leading "<", upgrade the unit tests
Reviewed-by: twisti, darcy
上级 34d1db74
...@@ -289,6 +289,9 @@ public class MethodHandles { ...@@ -289,6 +289,9 @@ public class MethodHandles {
* In general, the conditions under which a method handle may be * In general, the conditions under which a method handle may be
* looked up for a method {@code M} are exactly equivalent to the conditions * looked up for a method {@code M} are exactly equivalent to the conditions
* under which the lookup class could have compiled and resolved a call to {@code M}. * under which the lookup class could have compiled and resolved a call to {@code M}.
* Where the JVM would raise exceptions like {@code NoSuchMethodError},
* a method handle lookup will generally raise a corresponding
* checked exception, such as {@code NoSuchMethodException}.
* And the effect of invoking the method handle resulting from the lookup * And the effect of invoking the method handle resulting from the lookup
* is exactly equivalent to executing the compiled and resolved call to {@code M}. * is exactly equivalent to executing the compiled and resolved call to {@code M}.
* The same point is true of fields and constructors. * The same point is true of fields and constructors.
...@@ -305,6 +308,12 @@ public class MethodHandles { ...@@ -305,6 +308,12 @@ public class MethodHandles {
* (which will necessarily be a superclass of the lookup class) * (which will necessarily be a superclass of the lookup class)
* to the lookup class itself. * to the lookup class itself.
* <p> * <p>
* The JVM represents constructors and static initializer blocks as internal methods
* with special names ({@code "<init>"} and {@code "<clinit>"}).
* The internal syntax of invocation instructions allows them to refer to such internal
* methods as if they were normal methods, but the JVM bytecode verifier rejects them.
* A lookup of such an internal method will produce a {@code NoSuchMethodException}.
* <p>
* In some cases, access between nested classes is obtained by the Java compiler by creating * In some cases, access between nested classes is obtained by the Java compiler by creating
* an wrapper method to access a private method of another class * an wrapper method to access a private method of another class
* in the same top-level declaration. * in the same top-level declaration.
...@@ -604,6 +613,15 @@ public class MethodHandles { ...@@ -604,6 +613,15 @@ public class MethodHandles {
* The returned method handle will have * The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set. * the method's variable arity modifier bit ({@code 0x0080}) is set.
* <b>Example:</b>
* <p><blockquote><pre>{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
"asList", methodType(List.class, Object[].class));
assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
* }</pre></blockquote>
* @param refc the class from which the method is accessed * @param refc the class from which the method is accessed
* @param name the name of the method * @param name the name of the method
* @param type the type of the method * @param type the type of the method
...@@ -654,6 +672,34 @@ public class MethodHandles { ...@@ -654,6 +672,34 @@ public class MethodHandles {
* {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker} * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
* with the same {@code type} argument. * with the same {@code type} argument.
* *
* <b>Example:</b>
* <p><blockquote><pre>{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_concat = publicLookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
"hashCode", methodType(int.class));
MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
"hashCode", methodType(int.class));
assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
// interface method:
MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
"subSequence", methodType(CharSequence.class, int.class, int.class));
assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
// constructor "internal method" must be accessed differently:
MethodType MT_newString = methodType(void.class); //()V for new String()
try { assertEquals("impossible", lookup()
.findVirtual(String.class, "<init>", MT_newString));
} catch (NoSuchMethodException ex) { } // OK
MethodHandle MH_newString = publicLookup()
.findConstructor(String.class, MT_newString);
assertEquals("", (String) MH_newString.invokeExact());
* }</pre></blockquote>
*
* @param refc the class or interface from which the method is accessed * @param refc the class or interface from which the method is accessed
* @param name the name of the method * @param name the name of the method
* @param type the type of the method, with the receiver argument omitted * @param type the type of the method, with the receiver argument omitted
...@@ -696,12 +742,30 @@ public class MethodHandles { ...@@ -696,12 +742,30 @@ public class MethodHandles {
* If the constructor's class has not yet been initialized, that is done * If the constructor's class has not yet been initialized, that is done
* immediately, before the method handle is returned. * immediately, before the method handle is returned.
* <p> * <p>
* Note: The requested type must have a return type of {@code void}. * <em>(Note: The requested type must have a return type of {@code void}.
* This is consistent with the JVM's treatment of constructor type descriptors. * This is consistent with the JVM's treatment of constructor type descriptors.)</em>
* <p> * <p>
* The returned method handle will have * The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the constructor's variable arity modifier bit ({@code 0x0080}) is set. * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
* <p><b>Example:</b>
* <p><blockquote><pre>{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_newArrayList = publicLookup().findConstructor(
ArrayList.class, methodType(void.class, Collection.class));
Collection orig = Arrays.asList("x", "y");
Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
assert(orig != copy);
assertEquals(orig, copy);
// a variable-arity constructor:
MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
ProcessBuilder.class, methodType(void.class, String[].class));
ProcessBuilder pb = (ProcessBuilder)
MH_newProcessBuilder.invoke("x", "y", "z");
assertEquals("[x, y, z]", pb.command().toString());
* }</pre></blockquote>
* @param refc the class or interface from which the method is accessed * @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type * @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle * @return the desired method handle
...@@ -741,6 +805,45 @@ public class MethodHandles { ...@@ -741,6 +805,45 @@ public class MethodHandles {
* The returned method handle will have * The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set. * the method's variable arity modifier bit ({@code 0x0080}) is set.
* <p>
* <em>(Note: JVM internal methods named {@code "<init>"} are not visible to this API,
* even though the {@code invokespecial} instruction can refer to them
* in special circumstances. Use {@link #findConstructor findConstructor}
* to access instance initialization methods in a safe manner.)</em>
* <p><b>Example:</b>
* <p><blockquote><pre>{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
static class Listie extends ArrayList {
public String toString() { return "[wee Listie]"; }
static Lookup lookup() { return MethodHandles.lookup(); }
}
...
// no access to constructor via invokeSpecial:
MethodHandle MH_newListie = Listie.lookup()
.findConstructor(Listie.class, methodType(void.class));
Listie l = (Listie) MH_newListie.invokeExact();
try { assertEquals("impossible", Listie.lookup().findSpecial(
Listie.class, "<init>", methodType(void.class), Listie.class));
} catch (NoSuchMethodException ex) { } // OK
// access to super and self methods via invokeSpecial:
MethodHandle MH_super = Listie.lookup().findSpecial(
ArrayList.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_this = Listie.lookup().findSpecial(
Listie.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_duper = Listie.lookup().findSpecial(
Object.class, "toString" , methodType(String.class), Listie.class);
assertEquals("[]", (String) MH_super.invokeExact(l));
assertEquals(""+l, (String) MH_this.invokeExact(l));
assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
try { assertEquals("inaccessible", Listie.lookup().findSpecial(
String.class, "toString", methodType(String.class), Listie.class));
} catch (IllegalAccessException ex) { } // OK
Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
* }</pre></blockquote>
*
* @param refc the class or interface from which the method is accessed * @param refc the class or interface from which the method is accessed
* @param name the name of the method (which must not be "&lt;init&gt;") * @param name the name of the method (which must not be "&lt;init&gt;")
* @param type the type of the method, with the receiver argument omitted * @param type the type of the method, with the receiver argument omitted
...@@ -1105,6 +1208,7 @@ return mh1; ...@@ -1105,6 +1208,7 @@ return mh1;
checkSymbolicClass(refc); // do this before attempting to resolve checkSymbolicClass(refc); // do this before attempting to resolve
name.getClass(); // NPE name.getClass(); // NPE
type.getClass(); // NPE type.getClass(); // NPE
checkMethodName(refKind, name); // NPE check on name
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
NoSuchMethodException.class); NoSuchMethodException.class);
} }
...@@ -1124,6 +1228,13 @@ return mh1; ...@@ -1124,6 +1228,13 @@ return mh1;
throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this); throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
} }
/** Check name for an illegal leading "<" character. */
void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
throw new NoSuchMethodException("illegal method name: "+name);
}
/** /**
* Find my trustable caller class if m is a caller sensitive method. * Find my trustable caller class if m is a caller sensitive method.
* If this lookup object has private access, then the caller class is the lookupClass. * If this lookup object has private access, then the caller class is the lookupClass.
......
...@@ -53,7 +53,11 @@ public class JavaDocExamplesTest { ...@@ -53,7 +53,11 @@ public class JavaDocExamplesTest {
} }
public void run() throws Throwable { public void run() throws Throwable {
testMisc();
testFindStatic();
testFindConstructor();
testFindVirtual(); testFindVirtual();
testFindSpecial();
testPermuteArguments(); testPermuteArguments();
testDropArguments(); testDropArguments();
testFilterArguments(); testFilterArguments();
...@@ -99,7 +103,8 @@ static { ...@@ -99,7 +103,8 @@ static {
{} {}
@Test public void testFindVirtual() throws Throwable { @Test public void testMisc() throws Throwable {
// Extra tests, not from javadoc:
{} {}
MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class, MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class,
"concat", methodType(String.class, String.class)); "concat", methodType(String.class, String.class));
...@@ -114,6 +119,92 @@ assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy")); ...@@ -114,6 +119,92 @@ assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
{} {}
} }
@Test public void testFindStatic() throws Throwable {
{}
MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
"asList", methodType(List.class, Object[].class));
assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
{}
}
@Test public void testFindVirtual() throws Throwable {
{}
MethodHandle MH_concat = publicLookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
"hashCode", methodType(int.class));
MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
"hashCode", methodType(int.class));
assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
// interface method:
MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
"subSequence", methodType(CharSequence.class, int.class, int.class));
assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
// constructor "internal method" must be accessed differently:
MethodType MT_newString = methodType(void.class); //()V for new String()
try { assertEquals("impossible", lookup()
.findVirtual(String.class, "<init>", MT_newString));
} catch (NoSuchMethodException ex) { } // OK
MethodHandle MH_newString = publicLookup()
.findConstructor(String.class, MT_newString);
assertEquals("", (String) MH_newString.invokeExact());
{}
}
@Test public void testFindConstructor() throws Throwable {
{}
MethodHandle MH_newArrayList = publicLookup().findConstructor(
ArrayList.class, methodType(void.class, Collection.class));
Collection orig = Arrays.asList("x", "y");
Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
assert(orig != copy);
assertEquals(orig, copy);
// a variable-arity constructor:
MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
ProcessBuilder.class, methodType(void.class, String[].class));
ProcessBuilder pb = (ProcessBuilder)
MH_newProcessBuilder.invoke("x", "y", "z");
assertEquals("[x, y, z]", pb.command().toString());
{}
}
// for testFindSpecial
{}
static class Listie extends ArrayList {
public String toString() { return "[wee Listie]"; }
static Lookup lookup() { return MethodHandles.lookup(); }
}
{}
@Test public void testFindSpecial() throws Throwable {
{}
// no access to constructor via invokeSpecial:
MethodHandle MH_newListie = Listie.lookup()
.findConstructor(Listie.class, methodType(void.class));
Listie l = (Listie) MH_newListie.invokeExact();
try { assertEquals("impossible", Listie.lookup().findSpecial(
Listie.class, "<init>", methodType(void.class), Listie.class));
} catch (NoSuchMethodException ex) { } // OK
// access to super and self methods via invokeSpecial:
MethodHandle MH_super = Listie.lookup().findSpecial(
ArrayList.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_this = Listie.lookup().findSpecial(
Listie.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_duper = Listie.lookup().findSpecial(
Object.class, "toString" , methodType(String.class), Listie.class);
assertEquals("[]", (String) MH_super.invokeExact(l));
assertEquals(""+l, (String) MH_this.invokeExact(l));
assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
try { assertEquals("inaccessible", Listie.lookup().findSpecial(
String.class, "toString", methodType(String.class), Listie.class));
} catch (IllegalAccessException ex) { } // OK
Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
{}
}
@Test public void testPermuteArguments() throws Throwable { @Test public void testPermuteArguments() throws Throwable {
{{ {{
{} /// JAVADOC {} /// JAVADOC
......
...@@ -387,6 +387,7 @@ public class MethodHandlesTest { ...@@ -387,6 +387,7 @@ public class MethodHandlesTest {
protected Example(String name) { this.name = name; } protected Example(String name) { this.name = name; }
@SuppressWarnings("LeakingThisInConstructor") @SuppressWarnings("LeakingThisInConstructor")
protected Example(int x) { this(); called("protected <init>", this, x); } 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; } @Override public String toString() { return name; }
public void v0() { called("v0", this); } public void v0() { called("v0", this); }
...@@ -487,6 +488,9 @@ public class MethodHandlesTest { ...@@ -487,6 +488,9 @@ public class MethodHandlesTest {
return lookup.in(defc); return lookup.in(defc);
} }
/** Is findVirtual (etc.) of "<init>" supposed to elicit a NoSuchMethodException? */
final static boolean INIT_REF_CAUSES_NSME = true;
@Test @Test
public void testFindStatic() throws Throwable { public void testFindStatic() throws Throwable {
if (CAN_SKIP_WORKING) return; if (CAN_SKIP_WORKING) return;
...@@ -507,6 +511,8 @@ public class MethodHandlesTest { ...@@ -507,6 +511,8 @@ public class MethodHandlesTest {
testFindStatic(Example.class, Object.class, "s7", float.class, double.class); 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, "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"); testFindStatic(false, PRIVATE, Example.class, void.class, "v0");
} }
...@@ -529,11 +535,12 @@ public class MethodHandlesTest { ...@@ -529,11 +535,12 @@ public class MethodHandlesTest {
target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
noAccess = 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 (verbosity >= 5) ex.printStackTrace(System.out);
if (name.contains("bogus"))
assertTrue(noAccess instanceof NoSuchMethodException);
else
assertTrue(noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
...@@ -551,6 +558,13 @@ public class MethodHandlesTest { ...@@ -551,6 +558,13 @@ public class MethodHandlesTest {
System.out.print(':'); 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"); static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
// rough check of name string // rough check of name string
...@@ -580,6 +594,8 @@ public class MethodHandlesTest { ...@@ -580,6 +594,8 @@ public class MethodHandlesTest {
testFindVirtual(PubExample.class, void.class, "Pub/pro_v0"); 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, "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"); testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");
// test dispatch // test dispatch
...@@ -628,11 +644,12 @@ public class MethodHandlesTest { ...@@ -628,11 +644,12 @@ public class MethodHandlesTest {
target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type); target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
noAccess = 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 (verbosity >= 5) ex.printStackTrace(System.out);
if (name.contains("bogus"))
assertTrue(noAccess instanceof NoSuchMethodException);
else
assertTrue(noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
...@@ -682,11 +699,11 @@ public class MethodHandlesTest { ...@@ -682,11 +699,11 @@ public class MethodHandlesTest {
testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0"); testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0"); testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
// Do some negative testing: // 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 }) { for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0"); 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>", int.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0"); testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
} }
} }
...@@ -712,19 +729,25 @@ public class MethodHandlesTest { ...@@ -712,19 +729,25 @@ public class MethodHandlesTest {
countTest(positive); countTest(positive);
String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
MethodType type = MethodType.methodType(ret, params); MethodType type = MethodType.methodType(ret, params);
Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
(specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
MethodHandle target = null; MethodHandle target = null;
Exception noAccess = null; Exception noAccess = null;
try { try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
if (verbosity >= 5) System.out.println(" lookup => "+maybeMoveIn(lookup, specialCaller)); if (verbosity >= 5) System.out.println(" lookup => "+specialLookup);
target = maybeMoveIn(lookup, specialCaller).findSpecial(defc, methodName, type, specialCaller); target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
noAccess = 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 (verbosity >= 5) ex.printStackTrace(System.out);
if (name.contains("bogus"))
assertTrue(noAccess instanceof NoSuchMethodException);
else
assertTrue(noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
...@@ -769,7 +792,7 @@ public class MethodHandlesTest { ...@@ -769,7 +792,7 @@ public class MethodHandlesTest {
target = lookup.findConstructor(defc, type); target = lookup.findConstructor(defc, type);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
noAccess = ex; noAccess = ex;
assertTrue(noAccess instanceof IllegalAccessException); assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
...@@ -800,6 +823,8 @@ public class MethodHandlesTest { ...@@ -800,6 +823,8 @@ public class MethodHandlesTest {
testBind(Example.class, Object.class, "v2", int.class, Object.class); testBind(Example.class, Object.class, "v2", int.class, Object.class);
testBind(Example.class, Object.class, "v2", int.class, int.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, "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/v0");
testBind(SubExample.class, void.class, "Sub/pkg_v0"); testBind(SubExample.class, void.class, "Sub/pkg_v0");
testBind(IntExample.Impl.class, void.class, "Int/v0"); testBind(IntExample.Impl.class, void.class, "Int/v0");
...@@ -823,11 +848,12 @@ public class MethodHandlesTest { ...@@ -823,11 +848,12 @@ public class MethodHandlesTest {
target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type); target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
noAccess = 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 (verbosity >= 5) ex.printStackTrace(System.out);
if (name.contains("bogus"))
assertTrue(noAccess instanceof NoSuchMethodException);
else
assertTrue(noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
...@@ -890,6 +916,10 @@ public class MethodHandlesTest { ...@@ -890,6 +916,10 @@ public class MethodHandlesTest {
countTest(positive); countTest(positive);
String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
MethodType type = MethodType.methodType(ret, params); 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); Method rmethod = defc.getDeclaredMethod(methodName, params);
MethodHandle target = null; MethodHandle target = null;
Exception noAccess = null; Exception noAccess = null;
...@@ -898,16 +928,15 @@ public class MethodHandlesTest { ...@@ -898,16 +928,15 @@ public class MethodHandlesTest {
try { try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
if (isSpecial) if (isSpecial)
target = maybeMoveIn(lookup, specialCaller).unreflectSpecial(rmethod, specialCaller); target = specialLookup.unreflectSpecial(rmethod, specialCaller);
else else
target = maybeMoveIn(lookup, defc).unreflect(rmethod); target = maybeMoveIn(lookup, defc).unreflect(rmethod);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
noAccess = ex; noAccess = ex;
assertExceptionClass(
IllegalAccessException.class, // NSME is impossible, since it was already reflected
noAccess);
if (verbosity >= 5) ex.printStackTrace(System.out); if (verbosity >= 5) ex.printStackTrace(System.out);
if (name.contains("bogus"))
assertTrue(noAccess instanceof NoSuchMethodException);
else
assertTrue(noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
...@@ -1141,11 +1170,12 @@ public class MethodHandlesTest { ...@@ -1141,11 +1170,12 @@ public class MethodHandlesTest {
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
mh = null; mh = null;
noAccess = ex; noAccess = ex;
assertExceptionClass(
(fname.contains("bogus"))
? NoSuchFieldException.class
: IllegalAccessException.class,
noAccess);
if (verbosity >= 5) ex.printStackTrace(System.out); if (verbosity >= 5) ex.printStackTrace(System.out);
if (fname.contains("bogus"))
assertTrue(noAccess instanceof NoSuchFieldException);
else
assertTrue(noAccess instanceof IllegalAccessException);
} }
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册