64 static { MethodHandleImpl.initStatics(); } |
64 static { MethodHandleImpl.initStatics(); } |
65 // See IMPL_LOOKUP below. |
65 // See IMPL_LOOKUP below. |
66 |
66 |
67 //// Method handle creation from ordinary methods. |
67 //// Method handle creation from ordinary methods. |
68 |
68 |
69 /** Create a {@link Lookup} lookup object on the caller. |
69 /** |
70 * |
70 * Return a {@link Lookup lookup object} on the caller, |
|
71 * which has the capability to access any method handle that the caller has access to, |
|
72 * including direct method handles to private fields and methods. |
|
73 * This lookup object is a <em>capability</em> which may be delegated to trusted agents. |
|
74 * Do not store it in place where untrusted code can access it. |
71 */ |
75 */ |
72 public static Lookup lookup() { |
76 public static Lookup lookup() { |
73 return new Lookup(); |
77 return new Lookup(); |
74 } |
78 } |
75 |
79 |
76 /** Version of lookup which is trusted minimally. |
80 /** |
77 * It can only be used to create method handles to |
81 * Return a {@link Lookup lookup object} which is trusted minimally. |
78 * publicly accessible members. |
82 * It can only be used to create method handles to |
|
83 * publicly accessible fields and methods. |
79 */ |
84 */ |
80 public static Lookup publicLookup() { |
85 public static Lookup publicLookup() { |
81 return Lookup.PUBLIC_LOOKUP; |
86 return Lookup.PUBLIC_LOOKUP; |
82 } |
87 } |
83 |
88 |
84 /** |
89 /** |
85 * A factory object for creating method handles, when the creation |
90 * A <em>lookup object</em> is a factory for creating method handles, |
86 * requires access checking. Method handles do not perform |
91 * when the creation requires access checking. |
|
92 * Method handles do not perform |
87 * access checks when they are called; this is a major difference |
93 * access checks when they are called; this is a major difference |
88 * from reflective {@link Method}, which performs access checking |
94 * from reflective {@link Method}, which performs access checking |
89 * against every caller, on every call. Method handle access |
95 * against every caller, on every call. |
90 * restrictions are enforced when a method handle is created. |
96 * Therefore, method handle access |
|
97 * restrictions must be enforced when a method handle is created. |
91 * The caller class against which those restrictions are enforced |
98 * The caller class against which those restrictions are enforced |
92 * is known as the "lookup class". {@link Lookup} embodies an |
99 * is known as the {@linkplain #lookupClass lookup class}. |
|
100 * A lookup object embodies an |
93 * authenticated lookup class, and can be used to create any number |
101 * authenticated lookup class, and can be used to create any number |
94 * of access-checked method handles, all checked against a single |
102 * of access-checked method handles, all checked against a single |
95 * lookup class. |
103 * lookup class. |
96 * <p> |
104 * <p> |
97 * A class which needs to create method handles will call |
105 * A class which needs to create method handles will call |
98 * {@code MethodHandles.lookup()} to create a factory for itself. |
106 * {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself. |
99 * It may then use this factory to create method handles on |
107 * It may then use this factory to create method handles on |
100 * all of its methods, including private ones. |
108 * all of its methods, including private ones. |
101 * It may also delegate the lookup (e.g., to a metaobject protocol) |
109 * It may also delegate the lookup (e.g., to a metaobject protocol) |
102 * by passing the {@code Lookup} object to other code. |
110 * by passing the {@code Lookup} object to other code. |
103 * If this other code creates method handles, they will be access |
111 * If this other code creates method handles, they will be access |
104 * checked against the original lookup class, and not with any higher |
112 * checked against the original lookup class, and not with any higher |
105 * privileges. |
113 * privileges. |
106 * <p> |
114 * <p> |
107 * Note that access checks only apply to named and reflected methods. |
115 * Access checks only apply to named and reflected methods. |
108 * Other method handle creation methods, such as {@link #convertArguments}, |
116 * Other method handle creation methods, such as |
|
117 * {@link #convertArguments MethodHandles.convertArguments}, |
109 * do not require any access checks, and can be done independently |
118 * do not require any access checks, and can be done independently |
110 * of any lookup class. |
119 * of any lookup class. |
111 * <p> |
120 * <h3>How access errors are handled</h3> |
112 * <em>A note about error conditions:<em> A lookup can fail, because |
121 * A lookup can fail, because |
113 * the containing class is not accessible to the lookup class, or |
122 * the containing class is not accessible to the lookup class, or |
114 * because the desired class member is missing, or because the |
123 * because the desired class member is missing, or because the |
115 * desired class member is not accessible to the lookup class. |
124 * desired class member is not accessible to the lookup class. |
116 * It can also fail if a security manager is installed and refuses |
125 * It can also fail if a security manager is installed and refuses |
117 * access. In any of these cases, an exception will be |
126 * access. In any of these cases, an exception will be |
134 */ |
160 */ |
135 public Class<?> lookupClass() { |
161 public Class<?> lookupClass() { |
136 return lookupClass; |
162 return lookupClass; |
137 } |
163 } |
138 |
164 |
|
165 // This is just for calling out to MethodHandleImpl. |
|
166 private Class<?> lookupClassOrNull() { |
|
167 return (allowedModes == TRUSTED) ? null : lookupClass; |
|
168 } |
|
169 |
|
170 /** Which types of members can this lookup object produce? |
|
171 * The result is a bit-mask of the modifier bits PUBLIC, PROTECTED, PRIVATE, and STRICT. |
|
172 * The modifier bit STRICT stands in for the (non-existent) package protection mode. |
|
173 */ |
|
174 int lookupModes() { |
|
175 return allowedModes & ALL_MODES; |
|
176 } |
|
177 |
139 /** Embody the current class (the lookupClass) as a lookup class |
178 /** Embody the current class (the lookupClass) as a lookup class |
140 * for method handle creation. |
179 * for method handle creation. |
141 * Must be called by from a method in this package, |
180 * Must be called by from a method in this package, |
142 * which in turn is called by a method not in this package. |
181 * which in turn is called by a method not in this package. |
|
182 * <p> |
143 * Also, don't make it private, lest javac interpose |
183 * Also, don't make it private, lest javac interpose |
144 * an access$N method. |
184 * an access$N method. |
145 */ |
185 */ |
146 Lookup() { |
186 Lookup() { |
147 this(IMPL_TOKEN, getCallerClassAtEntryPoint()); |
187 this(getCallerClassAtEntryPoint(), ALL_MODES); |
148 } |
|
149 |
|
150 Lookup(Access token, Class<?> lookupClass) { |
|
151 // make sure we haven't accidentally picked up a privileged class: |
188 // make sure we haven't accidentally picked up a privileged class: |
152 checkUnprivilegedlookupClass(lookupClass); |
189 checkUnprivilegedlookupClass(lookupClass); |
|
190 } |
|
191 |
|
192 Lookup(Access token, Class<?> lookupClass) { |
|
193 this(lookupClass, ALL_MODES); |
|
194 Access.check(token); |
|
195 } |
|
196 |
|
197 private Lookup(Class<?> lookupClass, int allowedModes) { |
153 this.lookupClass = lookupClass; |
198 this.lookupClass = lookupClass; |
|
199 this.allowedModes = allowedModes; |
154 } |
200 } |
155 |
201 |
156 /** |
202 /** |
157 * Create a lookup on the specified class. |
203 * Create a lookup on the specified new lookup class. |
158 * The result is guaranteed to have no more access privileges |
204 * The resulting object will report the specified |
159 * than the original. |
205 * class as its own {@link #lookupClass}. |
160 */ |
206 * <p> |
161 public Lookup in(Class<?> newLookupClass) { |
207 * However, the resulting {@code Lookup} object is guaranteed |
162 if (this == PUBLIC_LOOKUP) return PUBLIC_LOOKUP; |
208 * to have no more access capabilities than the original. |
163 if (newLookupClass == null) return PUBLIC_LOOKUP; |
209 * In particular:<ul> |
164 if (newLookupClass == lookupClass) return this; |
210 * <li>If the new lookup class differs from the old one, |
165 if (this != IMPL_LOOKUP) { |
211 * protected members will not be accessible by virtue of inheritance. |
166 if (!VerifyAccess.isSamePackage(lookupClass, newLookupClass)) |
212 * <li>If the new lookup class is in a different package |
167 throw newNoAccessException(new MemberName(newLookupClass), this); |
213 * than the old one, protected and default (package) members will not be accessible. |
168 checkUnprivilegedlookupClass(newLookupClass); |
214 * <li>If the new lookup class is not within the same package member |
|
215 * as the old one, private members will not be accessible. |
|
216 * <li>In all cases, public members will continue to be accessible. |
|
217 * </ul> |
|
218 */ |
|
219 public Lookup in(Class<?> requestedLookupClass) { |
|
220 requestedLookupClass.getClass(); // null check |
|
221 if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all |
|
222 return new Lookup(requestedLookupClass, ALL_MODES); |
|
223 if (requestedLookupClass == this.lookupClass) |
|
224 return this; // keep same capabilities |
|
225 int newModes = (allowedModes & (ALL_MODES & ~PROTECTED)); |
|
226 if ((newModes & PACKAGE) != 0 |
|
227 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) { |
|
228 newModes &= ~(PACKAGE|PRIVATE); |
169 } |
229 } |
170 return new Lookup(newLookupClass); |
230 if ((newModes & PRIVATE) != 0 |
171 } |
231 && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) { |
172 |
232 newModes &= ~PRIVATE; |
173 private Lookup(Class<?> lookupClass) { |
233 } |
174 this.lookupClass = lookupClass; |
234 checkUnprivilegedlookupClass(requestedLookupClass); |
|
235 return new Lookup(requestedLookupClass, newModes); |
175 } |
236 } |
176 |
237 |
177 // Make sure outer class is initialized first. |
238 // Make sure outer class is initialized first. |
178 static { IMPL_TOKEN.getClass(); } |
239 static { IMPL_TOKEN.getClass(); } |
179 |
|
180 private static final Class<?> PUBLIC_ONLY = sun.dyn.empty.Empty.class; |
|
181 |
240 |
182 /** Version of lookup which is trusted minimally. |
241 /** Version of lookup which is trusted minimally. |
183 * It can only be used to create method handles to |
242 * It can only be used to create method handles to |
184 * publicly accessible members. |
243 * publicly accessible members. |
185 */ |
244 */ |
186 static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY); |
245 static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC); |
187 |
246 |
188 /** Package-private version of lookup which is trusted. */ |
247 /** Package-private version of lookup which is trusted. */ |
189 static final Lookup IMPL_LOOKUP = new Lookup(null); |
248 static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); |
190 static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); } |
249 static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); } |
191 |
250 |
192 private static void checkUnprivilegedlookupClass(Class<?> lookupClass) { |
251 private static void checkUnprivilegedlookupClass(Class<?> lookupClass) { |
193 String name = lookupClass.getName(); |
252 String name = lookupClass.getName(); |
194 if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn.")) |
253 if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn.")) |
195 throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); |
254 throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); |
196 } |
255 } |
197 |
256 |
|
257 /** Display the name of the class. |
|
258 * If there are restrictions on the access permitted to this lookup, |
|
259 * display those also. |
|
260 */ |
198 @Override |
261 @Override |
199 public String toString() { |
262 public String toString() { |
200 if (lookupClass == PUBLIC_ONLY) |
263 String modestr; |
201 return "public"; |
264 String cname = lookupClass.getName(); |
202 if (lookupClass == null) |
265 switch (allowedModes) { |
203 return "privileged"; |
266 case TRUSTED: |
204 return lookupClass.getName(); |
267 return "/trusted"; |
|
268 case PUBLIC: |
|
269 modestr = "/public"; |
|
270 if (lookupClass == Object.class) |
|
271 return modestr; |
|
272 break; |
|
273 case PUBLIC|PACKAGE: |
|
274 return cname + "/package"; |
|
275 case 0: // should not happen |
|
276 return cname + "/empty"; |
|
277 case ALL_MODES: |
|
278 return cname; |
|
279 } |
|
280 StringBuilder buf = new StringBuilder(cname); |
|
281 if ((allowedModes & PUBLIC) != 0) buf.append("/public"); |
|
282 if ((allowedModes & PACKAGE) != 0) buf.append("/package"); |
|
283 if ((allowedModes & PROTECTED) != 0) buf.append("/protected"); |
|
284 if ((allowedModes & PRIVATE) != 0) buf.append("/private"); |
|
285 return buf.toString(); |
205 } |
286 } |
206 |
287 |
207 // call this from an entry point method in Lookup with extraFrames=0. |
288 // call this from an entry point method in Lookup with extraFrames=0. |
208 private static Class<?> getCallerClassAtEntryPoint() { |
289 private static Class<?> getCallerClassAtEntryPoint() { |
209 final int CALLER_DEPTH = 4; |
290 final int CALLER_DEPTH = 4; |
217 /** |
298 /** |
218 * Produce a method handle for a static method. |
299 * Produce a method handle for a static method. |
219 * The type of the method handle will be that of the method. |
300 * The type of the method handle will be that of the method. |
220 * (Since static methods do not take receivers, there is no |
301 * (Since static methods do not take receivers, there is no |
221 * additional receiver argument inserted into the method handle type, |
302 * additional receiver argument inserted into the method handle type, |
222 * as there would be with {@linkplain #findVirtual} or {@linkplain #findSpecial}.) |
303 * as there would be with {@link #findVirtual} or {@link #findSpecial}.) |
223 * The method and all its argument types must be accessible to the lookup class. |
304 * The method and all its argument types must be accessible to the lookup class. |
224 * If the method's class has not yet been initialized, that is done |
305 * If the method's class has not yet been initialized, that is done |
225 * immediately, before the method handle is returned. |
306 * immediately, before the method handle is returned. |
226 * @param defc the class from which the method is accessed |
307 * @param refc the class from which the method is accessed |
227 * @param name the name of the method |
308 * @param name the name of the method |
228 * @param type the type of the method |
309 * @param type the type of the method |
229 * @return the desired method handle |
310 * @return the desired method handle |
230 * @exception SecurityException <em>TBD</em> |
311 * @exception SecurityException <em>TBD</em> |
231 * @exception NoAccessException if the method does not exist or access checking fails |
312 * @exception NoAccessException if the method does not exist or access checking fails |
232 */ |
313 */ |
233 public |
314 public |
234 MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException { |
315 MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoAccessException { |
235 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass()); |
316 MemberName method = resolveOrFail(refc, name, type, true); |
236 VerifyAccess.checkName(method, this); |
317 checkMethod(refc, method, true); |
237 checkStatic(true, method, this); |
318 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); |
238 //throw NoSuchMethodException |
|
239 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass()); |
|
240 } |
319 } |
241 |
320 |
242 /** |
321 /** |
243 * Produce a method handle for a virtual method. |
322 * Produce a method handle for a virtual method. |
244 * The type of the method handle will be that of the method, |
323 * The type of the method handle will be that of the method, |
245 * with the receiver type ({@code defc}) prepended. |
324 * with the receiver type (usually {@code refc}) prepended. |
246 * The method and all its argument types must be accessible to the lookup class. |
325 * The method and all its argument types must be accessible to the lookup class. |
247 * <p> |
326 * <p> |
248 * (<em>BUG NOTE:</em> The type {@code Object} may be prepended instead |
327 * (<em>BUG NOTE:</em> The type {@code Object} may be prepended instead |
249 * of the receiver type, if the receiver type is not on the boot class path. |
328 * of the receiver type, if the receiver type is not on the boot class path. |
250 * This is due to a temporary JVM limitation, in which MethodHandle |
329 * This is due to a temporary JVM limitation, in which MethodHandle |
255 * When called, the handle will treat the first argument as a receiver |
334 * When called, the handle will treat the first argument as a receiver |
256 * and dispatch on the receiver's type to determine which method |
335 * and dispatch on the receiver's type to determine which method |
257 * implementation to enter. |
336 * implementation to enter. |
258 * (The dispatching action is identical with that performed by an |
337 * (The dispatching action is identical with that performed by an |
259 * {@code invokevirtual} or {@code invokeinterface} instruction.) |
338 * {@code invokevirtual} or {@code invokeinterface} instruction.) |
260 * @param defc the class or interface from which the method is accessed |
339 * @param refc the class or interface from which the method is accessed |
261 * @param name the name of the method |
340 * @param name the name of the method |
262 * @param type the type of the method, with the receiver argument omitted |
341 * @param type the type of the method, with the receiver argument omitted |
263 * @return the desired method handle |
342 * @return the desired method handle |
264 * @exception SecurityException <em>TBD</em> |
343 * @exception SecurityException <em>TBD</em> |
265 * @exception NoAccessException if the method does not exist or access checking fails |
344 * @exception NoAccessException if the method does not exist or access checking fails |
266 */ |
345 */ |
267 public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException { |
346 public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoAccessException { |
268 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass()); |
347 MemberName method = resolveOrFail(refc, name, type, false); |
269 VerifyAccess.checkName(method, this); |
348 checkMethod(refc, method, false); |
270 checkStatic(false, method, this); |
349 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
271 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass()); |
350 return restrictProtectedReceiver(method, mh); |
|
351 } |
|
352 |
|
353 /** |
|
354 * Produce a method handle which creates an object and initializes it, using |
|
355 * the constructor of the specified type. |
|
356 * The parameter types of the method handle will be those of the constructor, |
|
357 * while the return type will be a reference to the constructor's class. |
|
358 * The constructor and all its argument types must be accessible to the lookup class. |
|
359 * If the constructor's class has not yet been initialized, that is done |
|
360 * immediately, before the method handle is returned. |
|
361 * <p> |
|
362 * Note: The requested type must have a return type of {@code void}. |
|
363 * This is consistent with the JVM's treatment of constructor signatures. |
|
364 * @param refc the class or interface from which the method is accessed |
|
365 * @param type the type of the method, with the receiver argument omitted, and a void return type |
|
366 * @return the desired method handle |
|
367 * @exception SecurityException <em>TBD</em> |
|
368 * @exception NoAccessException if the method does not exist or access checking fails |
|
369 */ |
|
370 public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoAccessException { |
|
371 String name = "<init>"; |
|
372 MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); |
|
373 assert(ctor.isConstructor()); |
|
374 checkAccess(refc, ctor); |
|
375 MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); |
|
376 return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH); |
272 } |
377 } |
273 |
378 |
274 /** |
379 /** |
275 * Produce an early-bound method handle for a virtual method, |
380 * Produce an early-bound method handle for a virtual method, |
276 * as if called from an {@code invokespecial} |
381 * as if called from an {@code invokespecial} |
285 * (This direct invocation action is identical with that performed by an |
390 * (This direct invocation action is identical with that performed by an |
286 * {@code invokespecial} instruction.) |
391 * {@code invokespecial} instruction.) |
287 * <p> |
392 * <p> |
288 * If the explicitly specified caller class is not identical with the |
393 * If the explicitly specified caller class is not identical with the |
289 * lookup class, a security check TBD is performed. |
394 * lookup class, a security check TBD is performed. |
290 * @param defc the class or interface from which the method is accessed |
395 * @param refc the class or interface from which the method is accessed |
291 * @param name the name of the method, or "<init>" for a constructor |
396 * @param name the name of the method (which must not be "<init>") |
292 * @param type the type of the method, with the receiver argument omitted |
397 * @param type the type of the method, with the receiver argument omitted |
293 * @param specialCaller the proposed calling class to perform the {@code invokespecial} |
398 * @param specialCaller the proposed calling class to perform the {@code invokespecial} |
294 * @return the desired method handle |
399 * @return the desired method handle |
295 * @exception SecurityException <em>TBD</em> |
400 * @exception SecurityException <em>TBD</em> |
296 * @exception NoAccessException if the method does not exist or access checking fails |
401 * @exception NoAccessException if the method does not exist or access checking fails |
297 */ |
402 */ |
298 public MethodHandle findSpecial(Class<?> defc, String name, MethodType type, |
403 public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, |
299 Class<?> specialCaller) throws NoAccessException { |
404 Class<?> specialCaller) throws NoAccessException { |
300 checkSpecialCaller(specialCaller, this); |
405 checkSpecialCaller(specialCaller); |
301 Lookup slookup = this.in(specialCaller); |
406 MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); |
302 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, slookup.lookupClass()); |
407 checkMethod(refc, method, false); |
303 VerifyAccess.checkName(method, this); |
408 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); |
304 checkStatic(false, method, this); |
409 return restrictReceiver(method, mh, specialCaller); |
305 if (name.equals("<init>")) { |
410 } |
306 throw newNoAccessException("cannot directly invoke a constructor", method, null); |
411 |
307 } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) { |
412 /** |
308 throw newNoAccessException("method must be in a superclass of lookup class", method, slookup.lookupClass()); |
413 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
309 } |
414 * Produce a method handle giving read access to a field. |
310 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, slookup.lookupClass()); |
415 * The type of the method handle will have a return type of the field's |
|
416 * value type. |
|
417 * If the field is static, the method handle will take no arguments. |
|
418 * Otherwise, its single argument will be the instance containing |
|
419 * the field. |
|
420 * Access checking is performed immediately on behalf of the lookup class. |
|
421 * @param name the field's name |
|
422 * @param type the field's type |
|
423 * @param isStatic true if and only if the field is static |
|
424 * @return a method handle which can load values from the field |
|
425 * @exception NoAccessException if access checking fails |
|
426 */ |
|
427 public MethodHandle findGetter(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoAccessException { |
|
428 return makeAccessor(refc, name, type, isStatic, false); |
|
429 } |
|
430 |
|
431 /** |
|
432 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
433 * Produce a method handle giving write access to a reflected field. |
|
434 * The type of the method handle will have a void return type. |
|
435 * If the field is static, the method handle will take a single |
|
436 * argument, of the field's value type, the value to be stored. |
|
437 * Otherwise, the two arguments will be the instance containing |
|
438 * the field, and the value to be stored. |
|
439 * Access checking is performed immediately on behalf of the lookup class. |
|
440 * @param name the field's name |
|
441 * @param type the field's type |
|
442 * @param isStatic true if and only if the field is static |
|
443 * @return a method handle which can store values into the reflected field |
|
444 * @exception NoAccessException if access checking fails |
|
445 */ |
|
446 public MethodHandle findSetter(Class<?> refc, String name, Class<?> type, |
|
447 boolean isStatic) throws NoAccessException { |
|
448 return makeAccessor(refc, name, type, isStatic, true); |
311 } |
449 } |
312 |
450 |
313 /** |
451 /** |
314 * Produce an early-bound method handle for a non-static method. |
452 * Produce an early-bound method handle for a non-static method. |
315 * The receiver must have a supertype {@code defc} in which a method |
453 * The receiver must have a supertype {@code defc} in which a method |
362 * @param m the reflected method |
498 * @param m the reflected method |
363 * @return a method handle which can invoke the reflected method |
499 * @return a method handle which can invoke the reflected method |
364 * @exception NoAccessException if access checking fails |
500 * @exception NoAccessException if access checking fails |
365 */ |
501 */ |
366 public MethodHandle unreflect(Method m) throws NoAccessException { |
502 public MethodHandle unreflect(Method m) throws NoAccessException { |
367 return unreflectImpl(new MemberName(m), m.isAccessible(), true, false, this); |
503 MemberName method = new MemberName(m); |
|
504 assert(method.isMethod()); |
|
505 if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); |
|
506 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
|
507 if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh); |
|
508 return mh; |
368 } |
509 } |
369 |
510 |
370 /** |
511 /** |
371 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
512 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
372 * Produce a method handle for a reflected method. |
513 * Produce a method handle for a reflected method. |
373 * It will bypass checks for overriding methods on the receiver, |
514 * It will bypass checks for overriding methods on the receiver, |
374 * as if by the {@code invokespecial} instruction. |
515 * as if by a {@code invokespecial} instruction from within the {@code specialCaller}. |
375 * The type of the method handle will be that of the method, |
516 * The type of the method handle will be that of the method, |
376 * with the receiver type prepended. |
517 * with the special caller type prepended (and <em>not</em> the receiver of the method). |
377 * If the method's {@code accessible} flag is not set, |
518 * If the method's {@code accessible} flag is not set, |
378 * access checking is performed immediately on behalf of the lookup class, |
519 * access checking is performed immediately on behalf of the lookup class, |
379 * as if {@code invokespecial} instruction were being linked. |
520 * as if {@code invokespecial} instruction were being linked. |
380 * @param m the reflected method |
521 * @param m the reflected method |
|
522 * @param specialCaller the class nominally calling the method |
381 * @return a method handle which can invoke the reflected method |
523 * @return a method handle which can invoke the reflected method |
382 * @exception NoAccessException if access checking fails |
524 * @exception NoAccessException if access checking fails |
383 */ |
525 */ |
384 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException { |
526 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException { |
385 checkSpecialCaller(specialCaller, this); |
527 checkSpecialCaller(specialCaller); |
386 Lookup slookup = this.in(specialCaller); |
528 MemberName method = new MemberName(m); |
387 MemberName mname = new MemberName(m); |
529 assert(method.isMethod()); |
388 checkStatic(false, mname, this); |
530 // ignore m.isAccessible: this is a new kind of access |
389 return unreflectImpl(mname, m.isAccessible(), false, false, slookup); |
531 checkMethod(m.getDeclaringClass(), method, false); |
|
532 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); |
|
533 return restrictReceiver(method, mh, specialCaller); |
390 } |
534 } |
391 |
535 |
392 /** |
536 /** |
393 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
537 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
394 * Produce a method handle for a reflected constructor. |
538 * Produce a method handle for a reflected constructor. |
441 * @param f the reflected field |
587 * @param f the reflected field |
442 * @return a method handle which can store values into the reflected field |
588 * @return a method handle which can store values into the reflected field |
443 * @exception NoAccessException if access checking fails |
589 * @exception NoAccessException if access checking fails |
444 */ |
590 */ |
445 public MethodHandle unreflectSetter(Field f) throws NoAccessException { |
591 public MethodHandle unreflectSetter(Field f) throws NoAccessException { |
446 MemberName m = new MemberName(f); |
592 return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true); |
447 return unreflectImpl(m, f.isAccessible(), false, true, this); |
593 } |
448 } |
594 |
449 |
595 /// Helper methods, all package-private. |
450 } |
596 |
451 |
597 MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) { |
452 static /*must not be public*/ |
598 checkSymbolicClass(refc); // do this before attempting to resolve |
453 MethodHandle findStaticFrom(Lookup lookup, |
599 int mods = (isStatic ? Modifier.STATIC : 0); |
454 Class<?> defc, String name, MethodType type) throws NoAccessException { |
600 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull()); |
455 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookup.lookupClass()); |
601 } |
456 VerifyAccess.checkName(method, lookup); |
602 |
457 checkStatic(true, method, lookup); |
603 MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) { |
458 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookup.lookupClass()); |
604 checkSymbolicClass(refc); // do this before attempting to resolve |
459 } |
605 int mods = (isStatic ? Modifier.STATIC : 0); |
460 |
606 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull()); |
461 static void checkStatic(boolean wantStatic, MemberName m, Lookup lookup) { |
607 } |
462 if (wantStatic != m.isStatic()) { |
608 |
463 String message = wantStatic ? "expected a static method" : "expected a non-static method"; |
609 MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic, |
464 throw newNoAccessException(message, m, lookup.lookupClass()); |
610 boolean searchSupers, Class<?> specialCaller) { |
465 } |
611 checkSymbolicClass(refc); // do this before attempting to resolve |
466 } |
612 int mods = (isStatic ? Modifier.STATIC : 0); |
467 |
613 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller); |
468 static void checkSpecialCaller(Class<?> specialCaller, Lookup lookup) { |
614 } |
469 if (lookup == Lookup.IMPL_LOOKUP) |
615 |
470 return; // privileged action |
616 void checkSymbolicClass(Class<?> refc) { |
471 assert(lookup.lookupClass() != null); |
617 Class<?> caller = lookupClassOrNull(); |
472 if (!VerifyAccess.isSamePackageMember(specialCaller, lookup.lookupClass())) |
618 if (caller != null && !VerifyAccess.isClassAccessible(refc, caller)) |
473 throw newNoAccessException("no private access", new MemberName(specialCaller), lookup.lookupClass()); |
619 throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), caller); |
474 } |
620 } |
475 |
621 |
476 // Helper for creating handles on reflected methods and constructors. |
622 void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) { |
477 static MethodHandle unreflectImpl(MemberName m, boolean isAccessible, |
623 String message; |
478 boolean doDispatch, boolean isSetter, Lookup lookup) { |
624 if (m.isConstructor()) |
479 MethodType narrowMethodType = null; |
625 message = "expected a method, not a constructor"; |
480 Class<?> defc = m.getDeclaringClass(); |
626 else if (!m.isMethod()) |
481 boolean isSpecialInvoke = m.isInvocable() && !doDispatch; |
627 message = "expected a method"; |
482 int mods = m.getModifiers(); |
628 else if (wantStatic != m.isStatic()) |
483 if (m.isStatic()) { |
629 message = wantStatic ? "expected a static method" : "expected a non-static method"; |
484 if (!isAccessible && |
630 else |
485 VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), false) == null) |
631 { checkAccess(refc, m); return; } |
486 throw newNoAccessException(m, lookup); |
632 throw newNoAccessException(message, m, lookupClass()); |
487 } else { |
633 } |
488 Class<?> constraint; |
634 |
489 if (isAccessible) { |
635 void checkAccess(Class<?> refc, MemberName m) { |
490 // abbreviated access check for "unlocked" method |
636 int allowedModes = this.allowedModes; |
491 constraint = doDispatch ? defc : lookup.lookupClass(); |
637 if (allowedModes == TRUSTED) return; |
492 } else { |
638 int mods = m.getModifiers(); |
493 constraint = VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), isSpecialInvoke); |
639 if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers())) |
|
640 return; // common case |
|
641 int requestedModes = fixmods(mods); // adjust 0 => PACKAGE |
|
642 if ((requestedModes & allowedModes) != 0 |
|
643 && VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(), |
|
644 mods, lookupClass())) |
|
645 return; |
|
646 if (((requestedModes & ~allowedModes) & PROTECTED) != 0 |
|
647 && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass())) |
|
648 // Protected members can also be checked as if they were package-private. |
|
649 return; |
|
650 throw newNoAccessException(accessFailedMessage(refc, m), m, lookupClass()); |
|
651 } |
|
652 |
|
653 String accessFailedMessage(Class<?> refc, MemberName m) { |
|
654 Class<?> defc = m.getDeclaringClass(); |
|
655 int mods = m.getModifiers(); |
|
656 if (!VerifyAccess.isClassAccessible(defc, lookupClass())) |
|
657 return "class is not public"; |
|
658 if (refc != defc && !VerifyAccess.isClassAccessible(refc, lookupClass())) |
|
659 return "symbolic reference "+refc.getName()+" is not public"; |
|
660 if (Modifier.isPublic(mods)) |
|
661 return "access to public member failed"; // (how?) |
|
662 else if (allowedModes == PUBLIC) |
|
663 return "member is not public"; |
|
664 if (Modifier.isPrivate(mods)) |
|
665 return "member is private"; |
|
666 if (Modifier.isProtected(mods)) |
|
667 return "member is protected"; |
|
668 return "member is private to package"; |
|
669 } |
|
670 |
|
671 void checkSpecialCaller(Class<?> specialCaller) { |
|
672 if (allowedModes == TRUSTED) return; |
|
673 if (!VerifyAccess.isSamePackageMember(specialCaller, lookupClass())) |
|
674 throw newNoAccessException("no private access for invokespecial", |
|
675 new MemberName(specialCaller), lookupClass()); |
|
676 } |
|
677 |
|
678 MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) { |
|
679 // The accessing class only has the right to use a protected member |
|
680 // on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc. |
|
681 if (!method.isProtected() || method.isStatic() |
|
682 || allowedModes == TRUSTED |
|
683 || VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())) |
|
684 return mh; |
|
685 else |
|
686 return restrictReceiver(method, mh, lookupClass()); |
|
687 } |
|
688 MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) { |
|
689 assert(!method.isStatic()); |
|
690 Class<?> defc = method.getDeclaringClass(); // receiver type of mh is too wide |
|
691 if (defc.isInterface() || !defc.isAssignableFrom(caller)) { |
|
692 throw newNoAccessException("caller class must be a subclass below the method", method, caller); |
494 } |
693 } |
495 if (constraint == null) { |
694 MethodType rawType = mh.type(); |
496 throw newNoAccessException(m, lookup); |
695 if (rawType.parameterType(0) == caller) return mh; |
497 } |
696 MethodType narrowType = rawType.changeParameterType(0, caller); |
498 if (constraint != defc && !constraint.isAssignableFrom(defc)) { |
697 return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null); |
499 if (!defc.isAssignableFrom(constraint)) |
698 } |
500 throw newNoAccessException("receiver must be in caller class", m, lookup.lookupClass()); |
699 |
501 if (m.isInvocable()) |
700 MethodHandle makeAccessor(Class<?> refc, String name, Class<?> type, |
502 narrowMethodType = m.getInvocationType().changeParameterType(0, constraint); |
701 boolean isStatic, boolean isSetter) throws NoAccessException { |
503 else if (m.isField()) |
702 MemberName field = resolveOrFail(refc, name, type, isStatic); |
504 narrowMethodType = (!isSetter |
703 if (isStatic != field.isStatic()) |
505 ? MethodType.methodType(m.getFieldType(), constraint) |
704 throw newNoAccessException(isStatic |
506 : MethodType.methodType(void.class, constraint, m.getFieldType())); |
705 ? "expected a static field" |
507 } |
706 : "expected a non-static field", |
508 } |
707 field, lookupClass()); |
509 if (m.isInvocable()) |
708 return makeAccessor(refc, field, false, isSetter); |
510 return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookup.lookupClass()); |
709 } |
511 else if (m.isField()) |
710 |
512 return MethodHandleImpl.accessField(IMPL_TOKEN, m, isSetter, lookup.lookupClass()); |
711 MethodHandle makeAccessor(Class<?> refc, MemberName field, |
513 else |
712 boolean trusted, boolean isSetter) throws NoAccessException { |
514 throw new InternalError(); |
713 assert(field.isField()); |
|
714 if (trusted) |
|
715 return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); |
|
716 checkAccess(refc, field); |
|
717 MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); |
|
718 return restrictProtectedReceiver(field, mh); |
|
719 } |
515 } |
720 } |
516 |
721 |
517 /** |
722 /** |
518 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
723 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
519 * Produce a method handle giving read access to elements of an array. |
724 * Produce a method handle giving read access to elements of an array. |
1023 * <p> |
1233 * <p> |
1024 * <b>Example:</b> |
1234 * <b>Example:</b> |
1025 * <p><blockquote><pre> |
1235 * <p><blockquote><pre> |
1026 * MethodHandle cat = MethodHandles.lookup(). |
1236 * MethodHandle cat = MethodHandles.lookup(). |
1027 * findVirtual(String.class, "concat", String.class, String.class); |
1237 * findVirtual(String.class, "concat", String.class, String.class); |
1028 * System.out.println(cat.<String>invoke("x", "y")); // xy |
1238 * System.out.println(cat.<String>invokeExact("x", "y")); // xy |
1029 * MethodHandle d0 = dropArguments(cat, 0, String.class); |
1239 * MethodHandle d0 = dropArguments(cat, 0, String.class); |
1030 * System.out.println(d0.<String>invoke("x", "y", "z")); // xy |
1240 * System.out.println(d0.<String>invokeExact("x", "y", "z")); // xy |
1031 * MethodHandle d1 = dropArguments(cat, 1, String.class); |
1241 * MethodHandle d1 = dropArguments(cat, 1, String.class); |
1032 * System.out.println(d1.<String>invoke("x", "y", "z")); // xz |
1242 * System.out.println(d1.<String>invokeExact("x", "y", "z")); // xz |
1033 * MethodHandle d2 = dropArguments(cat, 2, String.class); |
1243 * MethodHandle d2 = dropArguments(cat, 2, String.class); |
1034 * System.out.println(d2.<String>invoke("x", "y", "z")); // yz |
1244 * System.out.println(d2.<String>invokeExact("x", "y", "z")); // yz |
1035 * MethodHandle d12 = dropArguments(cat, 1, String.class, String.class); |
1245 * MethodHandle d12 = dropArguments(cat, 1, String.class, String.class); |
1036 * System.out.println(d12.<String>invoke("w", "x", "y", "z")); // wz |
1246 * System.out.println(d12.<String>invokeExact("w", "x", "y", "z")); // wz |
1037 * </pre></blockquote> |
1247 * </pre></blockquote> |
1038 * @param target the method handle to invoke after the argument is dropped |
1248 * @param target the method handle to invoke after the argument is dropped |
1039 * @param valueTypes the type(s) of the argument to drop |
1249 * @param valueTypes the type(s) of the argument to drop |
1040 * @param pos which argument to drop (zero for the first) |
1250 * @param pos which argument to drop (zero for the first) |
1041 * @return a new method handle which drops an argument of the given type, |
1251 * @return a new method handle which drops an argument of the given type, |