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 |
654 // these names require special lookups because of the implicit MethodType argument |
685 // these names require special lookups because of the implicit MethodType argument |
655 if ("invoke".equals(name)) |
686 if ("invoke".equals(name)) |
656 return invoker(type); |
687 return invoker(type); |
657 if ("invokeExact".equals(name)) |
688 if ("invokeExact".equals(name)) |
658 return exactInvoker(type); |
689 return exactInvoker(type); |
|
690 assert(!MemberName.isMethodHandleInvokeName(name)); |
659 return null; |
691 return null; |
660 } |
692 } |
661 |
693 |
662 /** |
694 /** |
663 * Produces a method handle which creates an object and initializes it, using |
695 * Produces a method handle which creates an object and initializes it, using |
899 * or if the method's variable arity modifier bit |
931 * or if the method's variable arity modifier bit |
900 * is set and {@code asVarargsCollector} fails |
932 * is set and {@code asVarargsCollector} fails |
901 * @throws NullPointerException if the argument is null |
933 * @throws NullPointerException if the argument is null |
902 */ |
934 */ |
903 public MethodHandle unreflect(Method m) throws IllegalAccessException { |
935 public MethodHandle unreflect(Method m) throws IllegalAccessException { |
|
936 if (m.getDeclaringClass() == MethodHandle.class) { |
|
937 MethodHandle mh = unreflectForMH(m); |
|
938 if (mh != null) return mh; |
|
939 } |
904 MemberName method = new MemberName(m); |
940 MemberName method = new MemberName(m); |
905 byte refKind = method.getReferenceKind(); |
941 byte refKind = method.getReferenceKind(); |
906 if (refKind == REF_invokeSpecial) |
942 if (refKind == REF_invokeSpecial) |
907 refKind = REF_invokeVirtual; |
943 refKind = REF_invokeVirtual; |
908 assert(method.isMethod()); |
944 assert(method.isMethod()); |
909 Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; |
945 Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; |
910 return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); |
946 return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); |
|
947 } |
|
948 private MethodHandle unreflectForMH(Method m) { |
|
949 // these names require special lookups because they throw UnsupportedOperationException |
|
950 if (MemberName.isMethodHandleInvokeName(m.getName())) |
|
951 return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m)); |
|
952 return null; |
911 } |
953 } |
912 |
954 |
913 /** |
955 /** |
914 * Produces a method handle for a reflected method. |
956 * Produces a method handle for a reflected method. |
915 * It will bypass checks for overriding methods on the receiver, |
957 * It will bypass checks for overriding methods on the receiver, |
1009 * @throws IllegalAccessException if access checking fails |
1051 * @throws IllegalAccessException if access checking fails |
1010 * @throws NullPointerException if the argument is null |
1052 * @throws NullPointerException if the argument is null |
1011 */ |
1053 */ |
1012 public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { |
1054 public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { |
1013 return unreflectField(f, true); |
1055 return unreflectField(f, true); |
|
1056 } |
|
1057 |
|
1058 /** |
|
1059 * Cracks a direct method handle created by this lookup object or a similar one. |
|
1060 * Security and access checks are performed to ensure that this lookup object |
|
1061 * is capable of reproducing the target method handle. |
|
1062 * This means that the cracking may fail if target is a direct method handle |
|
1063 * but was created by an unrelated lookup object. |
|
1064 * @param target a direct method handle to crack into symbolic reference components |
|
1065 * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object |
|
1066 * @exception SecurityException if a security manager is present and it |
|
1067 * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> |
|
1068 * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails |
|
1069 * @exception NullPointerException if the target is {@code null} |
|
1070 * @since 1.8 |
|
1071 */ |
|
1072 public MethodHandleInfo revealDirect(MethodHandle target) { |
|
1073 MemberName member = target.internalMemberName(); |
|
1074 if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke())) |
|
1075 throw newIllegalArgumentException("not a direct method handle"); |
|
1076 Class<?> defc = member.getDeclaringClass(); |
|
1077 byte refKind = member.getReferenceKind(); |
|
1078 assert(MethodHandleNatives.refKindIsValid(refKind)); |
|
1079 if (refKind == REF_invokeSpecial && !target.isInvokeSpecial()) |
|
1080 // Devirtualized method invocation is usually formally virtual. |
|
1081 // To avoid creating extra MemberName objects for this common case, |
|
1082 // we encode this extra degree of freedom using MH.isInvokeSpecial. |
|
1083 refKind = REF_invokeVirtual; |
|
1084 if (refKind == REF_invokeVirtual && defc.isInterface()) |
|
1085 // Symbolic reference is through interface but resolves to Object method (toString, etc.) |
|
1086 refKind = REF_invokeInterface; |
|
1087 // Check SM permissions and member access before cracking. |
|
1088 try { |
|
1089 checkSecurityManager(defc, member); |
|
1090 checkAccess(refKind, defc, member); |
|
1091 } catch (IllegalAccessException ex) { |
|
1092 throw new IllegalArgumentException(ex); |
|
1093 } |
|
1094 // Produce the handle to the results. |
|
1095 return new InfoFromMemberName(this, member, refKind); |
1014 } |
1096 } |
1015 |
1097 |
1016 /// Helper methods, all package-private. |
1098 /// Helper methods, all package-private. |
1017 |
1099 |
1018 MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
1100 MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
1208 return getDirectMethodCommon(refKind, refc, method, false, callerClass); |
1290 return getDirectMethodCommon(refKind, refc, method, false, callerClass); |
1209 } |
1291 } |
1210 private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, |
1292 private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, |
1211 boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { |
1293 boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { |
1212 checkMethod(refKind, refc, method); |
1294 checkMethod(refKind, refc, method); |
1213 if (method.isMethodHandleInvoke()) |
1295 assert(!method.isMethodHandleInvoke()); |
1214 return fakeMethodHandleInvoke(method); |
|
1215 |
1296 |
1216 Class<?> refcAsSuper; |
1297 Class<?> refcAsSuper; |
1217 if (refKind == REF_invokeSpecial && |
1298 if (refKind == REF_invokeSpecial && |
1218 refc != lookupClass() && |
1299 refc != lookupClass() && |
|
1300 !refc.isInterface() && |
1219 refc != (refcAsSuper = lookupClass().getSuperclass()) && |
1301 refc != (refcAsSuper = lookupClass().getSuperclass()) && |
1220 refc.isAssignableFrom(lookupClass())) { |
1302 refc.isAssignableFrom(lookupClass())) { |
1221 assert(!method.getName().equals("<init>")); // not this code path |
1303 assert(!method.getName().equals("<init>")); // not this code path |
1222 // Per JVMS 6.5, desc. of invokespecial instruction: |
1304 // Per JVMS 6.5, desc. of invokespecial instruction: |
1223 // If the method is in a superclass of the LC, |
1305 // If the method is in a superclass of the LC, |
1240 mh = maybeBindCaller(method, mh, callerClass); |
1322 mh = maybeBindCaller(method, mh, callerClass); |
1241 mh = mh.setVarargs(method); |
1323 mh = mh.setVarargs(method); |
1242 if (doRestrict) |
1324 if (doRestrict) |
1243 mh = restrictReceiver(method, mh, lookupClass()); |
1325 mh = restrictReceiver(method, mh, lookupClass()); |
1244 return mh; |
1326 return mh; |
1245 } |
|
1246 private MethodHandle fakeMethodHandleInvoke(MemberName method) { |
|
1247 return throwException(method.getReturnType(), UnsupportedOperationException.class); |
|
1248 } |
1327 } |
1249 private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, |
1328 private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, |
1250 Class<?> callerClass) |
1329 Class<?> callerClass) |
1251 throws IllegalAccessException { |
1330 throws IllegalAccessException { |
1252 if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) |
1331 if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) |