24 */ |
24 */ |
25 |
25 |
26 package java.lang.invoke; |
26 package java.lang.invoke; |
27 |
27 |
28 import java.lang.reflect.*; |
28 import java.lang.reflect.*; |
29 import java.security.AccessController; |
|
30 import java.security.PrivilegedAction; |
|
31 import java.util.List; |
29 import java.util.List; |
32 import java.util.ArrayList; |
30 import java.util.ArrayList; |
33 import java.util.Arrays; |
31 import java.util.Arrays; |
34 |
32 |
35 import sun.invoke.util.ValueConversions; |
33 import sun.invoke.util.ValueConversions; |
52 * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns. |
50 * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns. |
53 * <li>Wrapper methods which can convert between method handles and interface types. |
51 * <li>Wrapper methods which can convert between method handles and interface types. |
54 * </ul> |
52 * </ul> |
55 * <p> |
53 * <p> |
56 * @author John Rose, JSR 292 EG |
54 * @author John Rose, JSR 292 EG |
|
55 * @since 1.7 |
57 */ |
56 */ |
58 public class MethodHandles { |
57 public class MethodHandles { |
59 |
58 |
60 private MethodHandles() { } // do not instantiate |
59 private MethodHandles() { } // do not instantiate |
61 |
60 |
93 * @return a lookup object which is trusted minimally |
92 * @return a lookup object which is trusted minimally |
94 */ |
93 */ |
95 public static Lookup publicLookup() { |
94 public static Lookup publicLookup() { |
96 return Lookup.PUBLIC_LOOKUP; |
95 return Lookup.PUBLIC_LOOKUP; |
97 } |
96 } |
|
97 |
|
98 /** |
|
99 * Performs an unchecked "crack" of a direct method handle. |
|
100 * The result is as if the user had obtained a lookup object capable enough |
|
101 * to crack the target method handle, called |
|
102 * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect} |
|
103 * on the target to obtain its symbolic reference, and then called |
|
104 * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs} |
|
105 * to resolve the symbolic reference to a member. |
|
106 * <p> |
|
107 * If there is a security manager, its {@code checkPermission} method |
|
108 * is called with a {@code ReflectPermission("suppressAccessChecks")} permission. |
|
109 * @param <T> the desired type of the result, either {@link Member} or a subtype |
|
110 * @param target a direct method handle to crack into symbolic reference components |
|
111 * @param expected a class object representing the desired result type {@code T} |
|
112 * @return a reference to the method, constructor, or field object |
|
113 * @exception SecurityException if the caller is not privileged to call {@code setAccessible} |
|
114 * @exception NullPointerException if either argument is {@code null} |
|
115 * @exception IllegalArgumentException if the target is not a direct method handle |
|
116 * @exception ClassCastException if the member is not of the expected type |
|
117 * @since 1.8 |
|
118 */ |
|
119 public static <T extends Member> T |
|
120 reflectAs(Class<T> expected, MethodHandle target) { |
|
121 SecurityManager smgr = System.getSecurityManager(); |
|
122 if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION); |
|
123 Lookup lookup = Lookup.IMPL_LOOKUP; // use maximally privileged lookup |
|
124 return lookup.revealDirect(target).reflectAs(expected, lookup); |
|
125 } |
|
126 // Copied from AccessibleObject, as used by Method.setAccessible, etc.: |
|
127 static final private java.security.Permission ACCESS_PERMISSION = |
|
128 new ReflectPermission("suppressAccessChecks"); |
98 |
129 |
99 /** |
130 /** |
100 * A <em>lookup object</em> is a factory for creating method handles, |
131 * A <em>lookup object</em> is a factory for creating method handles, |
101 * when the creation requires access checking. |
132 * when the creation requires access checking. |
102 * Method handles do not perform |
133 * Method handles do not perform |
645 // these names require special lookups because of the implicit MethodType argument |
676 // these names require special lookups because of the implicit MethodType argument |
646 if ("invoke".equals(name)) |
677 if ("invoke".equals(name)) |
647 return invoker(type); |
678 return invoker(type); |
648 if ("invokeExact".equals(name)) |
679 if ("invokeExact".equals(name)) |
649 return exactInvoker(type); |
680 return exactInvoker(type); |
|
681 assert(!MemberName.isMethodHandleInvokeName(name)); |
650 return null; |
682 return null; |
651 } |
683 } |
652 |
684 |
653 /** |
685 /** |
654 * Produces a method handle which creates an object and initializes it, using |
686 * Produces a method handle which creates an object and initializes it, using |
890 * or if the method's variable arity modifier bit |
922 * or if the method's variable arity modifier bit |
891 * is set and {@code asVarargsCollector} fails |
923 * is set and {@code asVarargsCollector} fails |
892 * @throws NullPointerException if the argument is null |
924 * @throws NullPointerException if the argument is null |
893 */ |
925 */ |
894 public MethodHandle unreflect(Method m) throws IllegalAccessException { |
926 public MethodHandle unreflect(Method m) throws IllegalAccessException { |
|
927 if (m.getDeclaringClass() == MethodHandle.class) { |
|
928 MethodHandle mh = unreflectForMH(m); |
|
929 if (mh != null) return mh; |
|
930 } |
895 MemberName method = new MemberName(m); |
931 MemberName method = new MemberName(m); |
896 byte refKind = method.getReferenceKind(); |
932 byte refKind = method.getReferenceKind(); |
897 if (refKind == REF_invokeSpecial) |
933 if (refKind == REF_invokeSpecial) |
898 refKind = REF_invokeVirtual; |
934 refKind = REF_invokeVirtual; |
899 assert(method.isMethod()); |
935 assert(method.isMethod()); |
900 Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; |
936 Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; |
901 return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); |
937 return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); |
|
938 } |
|
939 private MethodHandle unreflectForMH(Method m) { |
|
940 // these names require special lookups because they throw UnsupportedOperationException |
|
941 if (MemberName.isMethodHandleInvokeName(m.getName())) |
|
942 return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m)); |
|
943 return null; |
902 } |
944 } |
903 |
945 |
904 /** |
946 /** |
905 * Produces a method handle for a reflected method. |
947 * Produces a method handle for a reflected method. |
906 * It will bypass checks for overriding methods on the receiver, |
948 * It will bypass checks for overriding methods on the receiver, |
1000 * @throws IllegalAccessException if access checking fails |
1042 * @throws IllegalAccessException if access checking fails |
1001 * @throws NullPointerException if the argument is null |
1043 * @throws NullPointerException if the argument is null |
1002 */ |
1044 */ |
1003 public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { |
1045 public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { |
1004 return unreflectField(f, true); |
1046 return unreflectField(f, true); |
|
1047 } |
|
1048 |
|
1049 /** |
|
1050 * Cracks a direct method handle created by this lookup object or a similar one. |
|
1051 * Security and access checks are performed to ensure that this lookup object |
|
1052 * is capable of reproducing the target method handle. |
|
1053 * This means that the cracking may fail if target is a direct method handle |
|
1054 * but was created by an unrelated lookup object. |
|
1055 * @param target a direct method handle to crack into symbolic reference components |
|
1056 * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object |
|
1057 * @exception SecurityException if a security manager is present and it |
|
1058 * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> |
|
1059 * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails |
|
1060 * @exception NullPointerException if the target is {@code null} |
|
1061 * @since 1.8 |
|
1062 */ |
|
1063 public MethodHandleInfo revealDirect(MethodHandle target) { |
|
1064 MemberName member = target.internalMemberName(); |
|
1065 if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke())) |
|
1066 throw newIllegalArgumentException("not a direct method handle"); |
|
1067 Class<?> defc = member.getDeclaringClass(); |
|
1068 byte refKind = member.getReferenceKind(); |
|
1069 assert(MethodHandleNatives.refKindIsValid(refKind)); |
|
1070 if (refKind == REF_invokeSpecial && !target.isInvokeSpecial()) |
|
1071 // Devirtualized method invocation is usually formally virtual. |
|
1072 // To avoid creating extra MemberName objects for this common case, |
|
1073 // we encode this extra degree of freedom using MH.isInvokeSpecial. |
|
1074 refKind = REF_invokeVirtual; |
|
1075 if (refKind == REF_invokeVirtual && defc.isInterface()) |
|
1076 // Symbolic reference is through interface but resolves to Object method (toString, etc.) |
|
1077 refKind = REF_invokeInterface; |
|
1078 // Check SM permissions and member access before cracking. |
|
1079 try { |
|
1080 checkSecurityManager(defc, member); |
|
1081 checkAccess(refKind, defc, member); |
|
1082 } catch (IllegalAccessException ex) { |
|
1083 throw new IllegalArgumentException(ex); |
|
1084 } |
|
1085 // Produce the handle to the results. |
|
1086 return new InfoFromMemberName(this, member, refKind); |
1005 } |
1087 } |
1006 |
1088 |
1007 /// Helper methods, all package-private. |
1089 /// Helper methods, all package-private. |
1008 |
1090 |
1009 MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
1091 MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
1199 return getDirectMethodCommon(refKind, refc, method, false, callerClass); |
1281 return getDirectMethodCommon(refKind, refc, method, false, callerClass); |
1200 } |
1282 } |
1201 private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, |
1283 private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, |
1202 boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { |
1284 boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { |
1203 checkMethod(refKind, refc, method); |
1285 checkMethod(refKind, refc, method); |
1204 if (method.isMethodHandleInvoke()) |
1286 assert(!method.isMethodHandleInvoke()); |
1205 return fakeMethodHandleInvoke(method); |
|
1206 |
1287 |
1207 Class<?> refcAsSuper; |
1288 Class<?> refcAsSuper; |
1208 if (refKind == REF_invokeSpecial && |
1289 if (refKind == REF_invokeSpecial && |
1209 refc != lookupClass() && |
1290 refc != lookupClass() && |
|
1291 !refc.isInterface() && |
1210 refc != (refcAsSuper = lookupClass().getSuperclass()) && |
1292 refc != (refcAsSuper = lookupClass().getSuperclass()) && |
1211 refc.isAssignableFrom(lookupClass())) { |
1293 refc.isAssignableFrom(lookupClass())) { |
1212 assert(!method.getName().equals("<init>")); // not this code path |
1294 assert(!method.getName().equals("<init>")); // not this code path |
1213 // Per JVMS 6.5, desc. of invokespecial instruction: |
1295 // Per JVMS 6.5, desc. of invokespecial instruction: |
1214 // If the method is in a superclass of the LC, |
1296 // If the method is in a superclass of the LC, |
1231 mh = maybeBindCaller(method, mh, callerClass); |
1313 mh = maybeBindCaller(method, mh, callerClass); |
1232 mh = mh.setVarargs(method); |
1314 mh = mh.setVarargs(method); |
1233 if (doRestrict) |
1315 if (doRestrict) |
1234 mh = restrictReceiver(method, mh, lookupClass()); |
1316 mh = restrictReceiver(method, mh, lookupClass()); |
1235 return mh; |
1317 return mh; |
1236 } |
|
1237 private MethodHandle fakeMethodHandleInvoke(MemberName method) { |
|
1238 return throwException(method.getReturnType(), UnsupportedOperationException.class); |
|
1239 } |
1318 } |
1240 private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, |
1319 private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, |
1241 Class<?> callerClass) |
1320 Class<?> callerClass) |
1242 throws IllegalAccessException { |
1321 throws IllegalAccessException { |
1243 if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) |
1322 if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) |