jdk/src/share/classes/java/lang/invoke/MethodHandles.java
changeset 16118 9f3390f42157
parent 14222 58f55d4dde46
child 16123 82033940e774
equal deleted inserted replaced
16117:3c521ba54a81 16118:9f3390f42157
   596          */
   596          */
   597         public
   597         public
   598         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
   598         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
   599             MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
   599             MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
   600             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   600             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   601             return getDirectMethod(REF_invokeStatic, refc, method);
   601             Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
       
   602             return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
   602         }
   603         }
   603 
   604 
   604         /**
   605         /**
   605          * Produces a method handle for a virtual method.
   606          * Produces a method handle for a virtual method.
   606          * The type of the method handle will be that of the method,
   607          * The type of the method handle will be that of the method,
   650                 if (mh != null)  return mh;
   651                 if (mh != null)  return mh;
   651             }
   652             }
   652             byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
   653             byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
   653             MemberName method = resolveOrFail(refKind, refc, name, type);
   654             MemberName method = resolveOrFail(refKind, refc, name, type);
   654             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   655             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   655             return getDirectMethod(refKind, refc, method);
   656             Class<?> callerClass = findBoundCallerClass(method);
       
   657             return getDirectMethod(refKind, refc, method, callerClass);
   656         }
   658         }
   657         private MethodHandle findVirtualForMH(String name, MethodType type) {
   659         private MethodHandle findVirtualForMH(String name, MethodType type) {
   658             // these names require special lookups because of the implicit MethodType argument
   660             // these names require special lookups because of the implicit MethodType argument
   659             if ("invoke".equals(name))
   661             if ("invoke".equals(name))
   660                 return invoker(type);
   662                 return invoker(type);
   734                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
   736                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
   735             checkSpecialCaller(specialCaller);
   737             checkSpecialCaller(specialCaller);
   736             Lookup specialLookup = this.in(specialCaller);
   738             Lookup specialLookup = this.in(specialCaller);
   737             MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
   739             MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
   738             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   740             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   739             return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method);
   741             Class<?> callerClass = findBoundCallerClass(method);
       
   742             return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
   740         }
   743         }
   741 
   744 
   742         /**
   745         /**
   743          * Produces a method handle giving read access to a non-static field.
   746          * Produces a method handle giving read access to a non-static field.
   744          * The type of the method handle will have a return type of the field's
   747          * The type of the method handle will have a return type of the field's
   877          */
   880          */
   878         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
   881         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
   879             Class<? extends Object> refc = receiver.getClass(); // may get NPE
   882             Class<? extends Object> refc = receiver.getClass(); // may get NPE
   880             MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
   883             MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
   881             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   884             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
   882             MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method);
   885             Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
       
   886             MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
   883             return mh.bindReceiver(receiver).setVarargs(method);
   887             return mh.bindReceiver(receiver).setVarargs(method);
   884         }
   888         }
   885 
   889 
   886         /**
   890         /**
   887          * Makes a direct method handle to <i>m</i>, if the lookup class has permission.
   891          * Makes a direct method handle to <i>m</i>, if the lookup class has permission.
   908             MemberName method = new MemberName(m);
   912             MemberName method = new MemberName(m);
   909             byte refKind = method.getReferenceKind();
   913             byte refKind = method.getReferenceKind();
   910             if (refKind == REF_invokeSpecial)
   914             if (refKind == REF_invokeSpecial)
   911                 refKind = REF_invokeVirtual;
   915                 refKind = REF_invokeVirtual;
   912             assert(method.isMethod());
   916             assert(method.isMethod());
       
   917             Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
   913             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
   918             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
   914             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method);
   919             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
   915         }
   920         }
   916 
   921 
   917         /**
   922         /**
   918          * Produces a method handle for a reflected method.
   923          * Produces a method handle for a reflected method.
   919          * It will bypass checks for overriding methods on the receiver,
   924          * It will bypass checks for overriding methods on the receiver,
   938         public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
   943         public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
   939             checkSpecialCaller(specialCaller);
   944             checkSpecialCaller(specialCaller);
   940             Lookup specialLookup = this.in(specialCaller);
   945             Lookup specialLookup = this.in(specialCaller);
   941             MemberName method = new MemberName(m, true);
   946             MemberName method = new MemberName(m, true);
   942             assert(method.isMethod());
   947             assert(method.isMethod());
       
   948             Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
   943             // ignore m.isAccessible:  this is a new kind of access
   949             // ignore m.isAccessible:  this is a new kind of access
   944             return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method);
   950             return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
   945         }
   951         }
   946 
   952 
   947         /**
   953         /**
   948          * Produces a method handle for a reflected constructor.
   954          * Produces a method handle for a reflected constructor.
   949          * The type of the method handle will be that of the constructor,
   955          * The type of the method handle will be that of the constructor,
  1038             if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
  1044             if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
  1039                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
  1045                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
  1040         }
  1046         }
  1041 
  1047 
  1042         /**
  1048         /**
       
  1049          * Find my trustable caller class if m is a caller sensitive method.
       
  1050          * If this lookup object has private access, then the caller class is the lookupClass.
       
  1051          * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
       
  1052          * This is the same caller class as is used by checkSecurityManager.
       
  1053          * This function performs stack walk magic: do not refactor it.
       
  1054          */
       
  1055         Class<?> findBoundCallerClass(MemberName m) {
       
  1056             Class<?> callerClass = null;
       
  1057             if (MethodHandleNatives.isCallerSensitive(m)) {
       
  1058                 // Do not refactor this to a more "logical" place, since it is stack walk magic.
       
  1059                 // Note that this is the same expression as in Step 2 below in checkSecurityManager.
       
  1060                 callerClass = ((allowedModes & PRIVATE) != 0
       
  1061                                ? lookupClass  // for strong access modes, no extra check
       
  1062                                // next line does stack walk magic; do not refactor:
       
  1063                                : getCallerClassAtEntryPoint(true));
       
  1064             }
       
  1065             return callerClass;
       
  1066         }
       
  1067         /**
  1043          * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
  1068          * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
       
  1069          * Determines a trustable caller class to compare with refc, the symbolic reference class.
       
  1070          * If this lookup object has private access, then the caller class is the lookupClass.
       
  1071          * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
  1044          * This function performs stack walk magic: do not refactor it.
  1072          * This function performs stack walk magic: do not refactor it.
  1045          */
  1073          */
  1046         void checkSecurityManager(Class<?> refc, MemberName m) {
  1074         void checkSecurityManager(Class<?> refc, MemberName m) {
  1047             SecurityManager smgr = System.getSecurityManager();
  1075             SecurityManager smgr = System.getSecurityManager();
  1048             if (smgr == null)  return;
  1076             if (smgr == null)  return;
  1193             if (rawType.parameterType(0) == caller)  return mh;
  1221             if (rawType.parameterType(0) == caller)  return mh;
  1194             MethodType narrowType = rawType.changeParameterType(0, caller);
  1222             MethodType narrowType = rawType.changeParameterType(0, caller);
  1195             return mh.viewAsType(narrowType);
  1223             return mh.viewAsType(narrowType);
  1196         }
  1224         }
  1197 
  1225 
  1198         private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException {
  1226         private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
  1199             return getDirectMethodCommon(refKind, refc, method,
  1227             return getDirectMethodCommon(refKind, refc, method,
  1200                     (refKind == REF_invokeSpecial ||
  1228                     (refKind == REF_invokeSpecial ||
  1201                         (MethodHandleNatives.refKindHasReceiver(refKind) &&
  1229                         (MethodHandleNatives.refKindHasReceiver(refKind) &&
  1202                             restrictProtectedReceiver(method))));
  1230                             restrictProtectedReceiver(method))), callerClass);
  1203         }
  1231         }
  1204         private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException {
  1232         private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
  1205             return getDirectMethodCommon(refKind, refc, method, false);
  1233             return getDirectMethodCommon(refKind, refc, method, false, callerClass);
  1206         }
  1234         }
  1207         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
  1235         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
  1208                                                    boolean doRestrict) throws IllegalAccessException {
  1236                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
  1209             checkMethod(refKind, refc, method);
  1237             checkMethod(refKind, refc, method);
  1210             if (method.isMethodHandleInvoke())
  1238             if (method.isMethodHandleInvoke())
  1211                 return fakeMethodHandleInvoke(method);
  1239                 return fakeMethodHandleInvoke(method);
  1212             MethodHandle mh = DirectMethodHandle.make(refc, method);
  1240             MethodHandle mh = DirectMethodHandle.make(refc, method);
  1213             mh = maybeBindCaller(method, mh);
  1241             mh = maybeBindCaller(method, mh, callerClass);
  1214             mh = mh.setVarargs(method);
  1242             mh = mh.setVarargs(method);
  1215             if (doRestrict)
  1243             if (doRestrict)
  1216                 mh = restrictReceiver(method, mh, lookupClass());
  1244                 mh = restrictReceiver(method, mh, lookupClass());
  1217             return mh;
  1245             return mh;
  1218         }
  1246         }
  1219         private MethodHandle fakeMethodHandleInvoke(MemberName method) {
  1247         private MethodHandle fakeMethodHandleInvoke(MemberName method) {
  1220             return throwException(method.getReturnType(), UnsupportedOperationException.class);
  1248             return throwException(method.getReturnType(), UnsupportedOperationException.class);
  1221         }
  1249         }
  1222         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh) throws IllegalAccessException {
  1250         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
       
  1251                                              Class<?> callerClass)
       
  1252                                              throws IllegalAccessException {
  1223             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
  1253             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
  1224                 return mh;
  1254                 return mh;
  1225             Class<?> hostClass = lookupClass;
  1255             Class<?> hostClass = lookupClass;
  1226             if ((allowedModes & PRIVATE) == 0)  // caller must use full-power lookup
  1256             if ((allowedModes & PRIVATE) == 0)  // caller must use full-power lookup
  1227                 hostClass = null;
  1257                 hostClass = callerClass;  // callerClass came from a security manager style stack walk
  1228             MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
  1258             MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
  1229             // Note: caller will apply varargs after this step happens.
  1259             // Note: caller will apply varargs after this step happens.
  1230             return cbmh;
  1260             return cbmh;
  1231         }
  1261         }
  1232         private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
  1262         private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
  1260                         : resolveOrFail(refKind, defc, name, (Class<?>) type);
  1290                         : resolveOrFail(refKind, defc, name, (Class<?>) type);
  1261                 return getDirectField(refKind, defc, field);
  1291                 return getDirectField(refKind, defc, field);
  1262             } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
  1292             } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
  1263                 MemberName method = (resolved != null) ? resolved
  1293                 MemberName method = (resolved != null) ? resolved
  1264                         : resolveOrFail(refKind, defc, name, (MethodType) type);
  1294                         : resolveOrFail(refKind, defc, name, (MethodType) type);
  1265                 return getDirectMethod(refKind, defc, method);
  1295                 return getDirectMethod(refKind, defc, method, lookupClass);
  1266             } else if (refKind == REF_newInvokeSpecial) {
  1296             } else if (refKind == REF_newInvokeSpecial) {
  1267                 assert(name == null || name.equals("<init>"));
  1297                 assert(name == null || name.equals("<init>"));
  1268                 MemberName ctor = (resolved != null) ? resolved
  1298                 MemberName ctor = (resolved != null) ? resolved
  1269                         : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type);
  1299                         : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type);
  1270                 return getDirectConstructor(defc, ctor);
  1300                 return getDirectConstructor(defc, ctor);