1 /* |
|
2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package sun.dyn; |
|
27 |
|
28 import sun.dyn.util.BytecodeDescriptor; |
|
29 import java.dyn.*; |
|
30 import java.lang.reflect.Constructor; |
|
31 import java.lang.reflect.Field; |
|
32 import java.lang.reflect.Method; |
|
33 import java.lang.reflect.Member; |
|
34 import java.lang.reflect.Modifier; |
|
35 import java.util.ArrayList; |
|
36 import java.util.Arrays; |
|
37 import java.util.Collections; |
|
38 import java.util.Iterator; |
|
39 import java.util.List; |
|
40 import static sun.dyn.MethodHandleNatives.Constants.*; |
|
41 |
|
42 /** |
|
43 * A {@code MemberName} is a compact symbolic datum which fully characterizes |
|
44 * a method or field reference. |
|
45 * A member name refers to a field, method, constructor, or member type. |
|
46 * Every member name has a simple name (a string) and a type (either a Class or MethodType). |
|
47 * A member name may also have a non-null declaring class, or it may be simply |
|
48 * a naked name/type pair. |
|
49 * A member name may also have non-zero modifier flags. |
|
50 * Finally, a member name may be either resolved or unresolved. |
|
51 * If it is resolved, the existence of the named |
|
52 * <p> |
|
53 * Whether resolved or not, a member name provides no access rights or |
|
54 * invocation capability to its possessor. It is merely a compact |
|
55 * representation of all symbolic information necessary to link to |
|
56 * and properly use the named member. |
|
57 * <p> |
|
58 * When resolved, a member name's internal implementation may include references to JVM metadata. |
|
59 * This representation is stateless and only decriptive. |
|
60 * It provides no private information and no capability to use the member. |
|
61 * <p> |
|
62 * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information |
|
63 * about the internals of a method (except its bytecodes) and also |
|
64 * allows invocation. A MemberName is much lighter than a Method, |
|
65 * since it contains about 7 fields to the 16 of Method (plus its sub-arrays), |
|
66 * and those seven fields omit much of the information in Method. |
|
67 * @author jrose |
|
68 */ |
|
69 public final class MemberName implements Member, Cloneable { |
|
70 private Class<?> clazz; // class in which the method is defined |
|
71 private String name; // may be null if not yet materialized |
|
72 private Object type; // may be null if not yet materialized |
|
73 private int flags; // modifier bits; see reflect.Modifier |
|
74 |
|
75 private Object vmtarget; // VM-specific target value |
|
76 private int vmindex; // method index within class or interface |
|
77 |
|
78 { vmindex = VM_INDEX_UNINITIALIZED; } |
|
79 |
|
80 /** Return the declaring class of this member. |
|
81 * In the case of a bare name and type, the declaring class will be null. |
|
82 */ |
|
83 public Class<?> getDeclaringClass() { |
|
84 if (clazz == null && isResolved()) { |
|
85 expandFromVM(); |
|
86 } |
|
87 return clazz; |
|
88 } |
|
89 |
|
90 /** Utility method producing the class loader of the declaring class. */ |
|
91 public ClassLoader getClassLoader() { |
|
92 return clazz.getClassLoader(); |
|
93 } |
|
94 |
|
95 /** Return the simple name of this member. |
|
96 * For a type, it is the same as {@link Class#getSimpleName}. |
|
97 * For a method or field, it is the simple name of the member. |
|
98 * For a constructor, it is always {@code "<init>"}. |
|
99 */ |
|
100 public String getName() { |
|
101 if (name == null) { |
|
102 expandFromVM(); |
|
103 if (name == null) return null; |
|
104 } |
|
105 return name; |
|
106 } |
|
107 |
|
108 /** Return the declared type of this member, which |
|
109 * must be a method or constructor. |
|
110 */ |
|
111 public MethodType getMethodType() { |
|
112 if (type == null) { |
|
113 expandFromVM(); |
|
114 if (type == null) return null; |
|
115 } |
|
116 if (!isInvocable()) |
|
117 throw newIllegalArgumentException("not invocable, no method type"); |
|
118 if (type instanceof MethodType) { |
|
119 return (MethodType) type; |
|
120 } |
|
121 if (type instanceof String) { |
|
122 String sig = (String) type; |
|
123 MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader()); |
|
124 this.type = res; |
|
125 return res; |
|
126 } |
|
127 if (type instanceof Object[]) { |
|
128 Object[] typeInfo = (Object[]) type; |
|
129 Class<?>[] ptypes = (Class<?>[]) typeInfo[1]; |
|
130 Class<?> rtype = (Class<?>) typeInfo[0]; |
|
131 MethodType res = MethodType.methodType(rtype, ptypes); |
|
132 this.type = res; |
|
133 return res; |
|
134 } |
|
135 throw new InternalError("bad method type "+type); |
|
136 } |
|
137 |
|
138 /** Return the actual type under which this method or constructor must be invoked. |
|
139 * For non-static methods or constructors, this is the type with a leading parameter, |
|
140 * a reference to declaring class. For static methods, it is the same as the declared type. |
|
141 */ |
|
142 public MethodType getInvocationType() { |
|
143 MethodType itype = getMethodType(); |
|
144 if (!isStatic()) |
|
145 itype = itype.insertParameterTypes(0, clazz); |
|
146 return itype; |
|
147 } |
|
148 |
|
149 /** Utility method producing the parameter types of the method type. */ |
|
150 public Class<?>[] getParameterTypes() { |
|
151 return getMethodType().parameterArray(); |
|
152 } |
|
153 |
|
154 /** Utility method producing the return type of the method type. */ |
|
155 public Class<?> getReturnType() { |
|
156 return getMethodType().returnType(); |
|
157 } |
|
158 |
|
159 /** Return the declared type of this member, which |
|
160 * must be a field or type. |
|
161 * If it is a type member, that type itself is returned. |
|
162 */ |
|
163 public Class<?> getFieldType() { |
|
164 if (type == null) { |
|
165 expandFromVM(); |
|
166 if (type == null) return null; |
|
167 } |
|
168 if (isInvocable()) |
|
169 throw newIllegalArgumentException("not a field or nested class, no simple type"); |
|
170 if (type instanceof Class<?>) { |
|
171 return (Class<?>) type; |
|
172 } |
|
173 if (type instanceof String) { |
|
174 String sig = (String) type; |
|
175 MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader()); |
|
176 Class<?> res = mtype.returnType(); |
|
177 this.type = res; |
|
178 return res; |
|
179 } |
|
180 throw new InternalError("bad field type "+type); |
|
181 } |
|
182 |
|
183 /** Utility method to produce either the method type or field type of this member. */ |
|
184 public Object getType() { |
|
185 return (isInvocable() ? getMethodType() : getFieldType()); |
|
186 } |
|
187 |
|
188 /** Utility method to produce the signature of this member, |
|
189 * used within the class file format to describe its type. |
|
190 */ |
|
191 public String getSignature() { |
|
192 if (type == null) { |
|
193 expandFromVM(); |
|
194 if (type == null) return null; |
|
195 } |
|
196 if (type instanceof String) |
|
197 return (String) type; |
|
198 if (isInvocable()) |
|
199 return BytecodeDescriptor.unparse(getMethodType()); |
|
200 else |
|
201 return BytecodeDescriptor.unparse(getFieldType()); |
|
202 } |
|
203 |
|
204 /** Return the modifier flags of this member. |
|
205 * @see java.lang.reflect.Modifier |
|
206 */ |
|
207 public int getModifiers() { |
|
208 return (flags & RECOGNIZED_MODIFIERS); |
|
209 } |
|
210 |
|
211 private void setFlags(int flags) { |
|
212 this.flags = flags; |
|
213 assert(testAnyFlags(ALL_KINDS)); |
|
214 } |
|
215 |
|
216 private boolean testFlags(int mask, int value) { |
|
217 return (flags & mask) == value; |
|
218 } |
|
219 private boolean testAllFlags(int mask) { |
|
220 return testFlags(mask, mask); |
|
221 } |
|
222 private boolean testAnyFlags(int mask) { |
|
223 return !testFlags(mask, 0); |
|
224 } |
|
225 |
|
226 /** Utility method to query the modifier flags of this member. */ |
|
227 public boolean isStatic() { |
|
228 return Modifier.isStatic(flags); |
|
229 } |
|
230 /** Utility method to query the modifier flags of this member. */ |
|
231 public boolean isPublic() { |
|
232 return Modifier.isPublic(flags); |
|
233 } |
|
234 /** Utility method to query the modifier flags of this member. */ |
|
235 public boolean isPrivate() { |
|
236 return Modifier.isPrivate(flags); |
|
237 } |
|
238 /** Utility method to query the modifier flags of this member. */ |
|
239 public boolean isProtected() { |
|
240 return Modifier.isProtected(flags); |
|
241 } |
|
242 /** Utility method to query the modifier flags of this member. */ |
|
243 public boolean isFinal() { |
|
244 return Modifier.isFinal(flags); |
|
245 } |
|
246 /** Utility method to query the modifier flags of this member. */ |
|
247 public boolean isAbstract() { |
|
248 return Modifier.isAbstract(flags); |
|
249 } |
|
250 // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo |
|
251 |
|
252 // unofficial modifier flags, used by HotSpot: |
|
253 static final int BRIDGE = 0x00000040; |
|
254 static final int VARARGS = 0x00000080; |
|
255 static final int SYNTHETIC = 0x00001000; |
|
256 static final int ANNOTATION= 0x00002000; |
|
257 static final int ENUM = 0x00004000; |
|
258 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ |
|
259 public boolean isBridge() { |
|
260 return testAllFlags(IS_METHOD | BRIDGE); |
|
261 } |
|
262 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ |
|
263 public boolean isVarargs() { |
|
264 return testAllFlags(VARARGS) && isInvocable(); |
|
265 } |
|
266 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ |
|
267 public boolean isSynthetic() { |
|
268 return testAllFlags(SYNTHETIC); |
|
269 } |
|
270 |
|
271 static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular |
|
272 |
|
273 // modifiers exported by the JVM: |
|
274 static final int RECOGNIZED_MODIFIERS = 0xFFFF; |
|
275 |
|
276 // private flags, not part of RECOGNIZED_MODIFIERS: |
|
277 static final int |
|
278 IS_METHOD = MN_IS_METHOD, // method (not constructor) |
|
279 IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor |
|
280 IS_FIELD = MN_IS_FIELD, // field |
|
281 IS_TYPE = MN_IS_TYPE; // nested type |
|
282 static final int // for MethodHandleNatives.getMembers |
|
283 SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES, |
|
284 SEARCH_INTERFACES = MN_SEARCH_INTERFACES; |
|
285 |
|
286 static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; |
|
287 static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; |
|
288 static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR; |
|
289 static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD; |
|
290 static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES; |
|
291 |
|
292 /** Utility method to query whether this member is a method or constructor. */ |
|
293 public boolean isInvocable() { |
|
294 return testAnyFlags(IS_INVOCABLE); |
|
295 } |
|
296 /** Utility method to query whether this member is a method, constructor, or field. */ |
|
297 public boolean isFieldOrMethod() { |
|
298 return testAnyFlags(IS_FIELD_OR_METHOD); |
|
299 } |
|
300 /** Query whether this member is a method. */ |
|
301 public boolean isMethod() { |
|
302 return testAllFlags(IS_METHOD); |
|
303 } |
|
304 /** Query whether this member is a constructor. */ |
|
305 public boolean isConstructor() { |
|
306 return testAllFlags(IS_CONSTRUCTOR); |
|
307 } |
|
308 /** Query whether this member is a field. */ |
|
309 public boolean isField() { |
|
310 return testAllFlags(IS_FIELD); |
|
311 } |
|
312 /** Query whether this member is a type. */ |
|
313 public boolean isType() { |
|
314 return testAllFlags(IS_TYPE); |
|
315 } |
|
316 /** Utility method to query whether this member is neither public, private, nor protected. */ |
|
317 public boolean isPackage() { |
|
318 return !testAnyFlags(ALL_ACCESS); |
|
319 } |
|
320 |
|
321 /** Initialize a query. It is not resolved. */ |
|
322 private void init(Class<?> defClass, String name, Object type, int flags) { |
|
323 // defining class is allowed to be null (for a naked name/type pair) |
|
324 //name.toString(); // null check |
|
325 //type.equals(type); // null check |
|
326 // fill in fields: |
|
327 this.clazz = defClass; |
|
328 this.name = name; |
|
329 this.type = type; |
|
330 setFlags(flags); |
|
331 assert(!isResolved()); |
|
332 } |
|
333 |
|
334 private void expandFromVM() { |
|
335 if (!isResolved()) return; |
|
336 if (type instanceof Object[]) |
|
337 type = null; // don't saddle JVM w/ typeInfo |
|
338 MethodHandleNatives.expand(this); |
|
339 } |
|
340 |
|
341 // Capturing information from the Core Reflection API: |
|
342 private static int flagsMods(int flags, int mods) { |
|
343 assert((flags & RECOGNIZED_MODIFIERS) == 0); |
|
344 assert((mods & ~RECOGNIZED_MODIFIERS) == 0); |
|
345 return flags | mods; |
|
346 } |
|
347 /** Create a name for the given reflected method. The resulting name will be in a resolved state. */ |
|
348 public MemberName(Method m) { |
|
349 Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() }; |
|
350 init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers())); |
|
351 // fill in vmtarget, vmindex while we have m in hand: |
|
352 MethodHandleNatives.init(this, m); |
|
353 assert(isResolved()); |
|
354 } |
|
355 /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */ |
|
356 public MemberName(Constructor ctor) { |
|
357 Object[] typeInfo = { void.class, ctor.getParameterTypes() }; |
|
358 init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers())); |
|
359 // fill in vmtarget, vmindex while we have ctor in hand: |
|
360 MethodHandleNatives.init(this, ctor); |
|
361 assert(isResolved()); |
|
362 } |
|
363 /** Create a name for the given reflected field. The resulting name will be in a resolved state. */ |
|
364 public MemberName(Field fld) { |
|
365 init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers())); |
|
366 // fill in vmtarget, vmindex while we have fld in hand: |
|
367 MethodHandleNatives.init(this, fld); |
|
368 assert(isResolved()); |
|
369 } |
|
370 /** Create a name for the given class. The resulting name will be in a resolved state. */ |
|
371 public MemberName(Class<?> type) { |
|
372 init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers())); |
|
373 vmindex = 0; // isResolved |
|
374 assert(isResolved()); |
|
375 } |
|
376 |
|
377 // bare-bones constructor; the JVM will fill it in |
|
378 MemberName() { } |
|
379 |
|
380 // locally useful cloner |
|
381 @Override protected MemberName clone() { |
|
382 try { |
|
383 return (MemberName) super.clone(); |
|
384 } catch (CloneNotSupportedException ex) { |
|
385 throw new InternalError(); |
|
386 } |
|
387 } |
|
388 |
|
389 // %%% define equals/hashcode? |
|
390 |
|
391 // Construction from symbolic parts, for queries: |
|
392 /** Create a field or type name from the given components: Declaring class, name, type, modifiers. |
|
393 * The declaring class may be supplied as null if this is to be a bare name and type. |
|
394 * The resulting name will in an unresolved state. |
|
395 */ |
|
396 public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) { |
|
397 init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS)); |
|
398 } |
|
399 /** Create a field or type name from the given components: Declaring class, name, type. |
|
400 * The declaring class may be supplied as null if this is to be a bare name and type. |
|
401 * The modifier flags default to zero. |
|
402 * The resulting name will in an unresolved state. |
|
403 */ |
|
404 public MemberName(Class<?> defClass, String name, Class<?> type) { |
|
405 this(defClass, name, type, 0); |
|
406 } |
|
407 /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers. |
|
408 * It will be a constructor if and only if the name is {@code "<init>"}. |
|
409 * The declaring class may be supplied as null if this is to be a bare name and type. |
|
410 * The resulting name will in an unresolved state. |
|
411 */ |
|
412 public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) { |
|
413 int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD); |
|
414 init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS)); |
|
415 } |
|
416 /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers. |
|
417 * It will be a constructor if and only if the name is {@code "<init>"}. |
|
418 * The declaring class may be supplied as null if this is to be a bare name and type. |
|
419 * The modifier flags default to zero. |
|
420 * The resulting name will in an unresolved state. |
|
421 */ |
|
422 public MemberName(Class<?> defClass, String name, MethodType type) { |
|
423 this(defClass, name, type, 0); |
|
424 } |
|
425 |
|
426 /** Query whether this member name is resolved. |
|
427 * A resolved member name is one for which the JVM has found |
|
428 * a method, constructor, field, or type binding corresponding exactly to the name. |
|
429 * (Document?) |
|
430 */ |
|
431 public boolean isResolved() { |
|
432 return (vmindex != VM_INDEX_UNINITIALIZED); |
|
433 } |
|
434 |
|
435 /** Query whether this member name is resolved to a non-static, non-final method. |
|
436 */ |
|
437 public boolean hasReceiverTypeDispatch() { |
|
438 return (isMethod() && getVMIndex(Access.TOKEN) >= 0); |
|
439 } |
|
440 |
|
441 /** Produce a string form of this member name. |
|
442 * For types, it is simply the type's own string (as reported by {@code toString}). |
|
443 * For fields, it is {@code "DeclaringClass.name/type"}. |
|
444 * For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}. |
|
445 * If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted. |
|
446 * If the member is unresolved, a prefix {@code "*."} is prepended. |
|
447 */ |
|
448 @Override |
|
449 public String toString() { |
|
450 if (isType()) |
|
451 return type.toString(); // class java.lang.String |
|
452 // else it is a field, method, or constructor |
|
453 StringBuilder buf = new StringBuilder(); |
|
454 if (getDeclaringClass() != null) { |
|
455 buf.append(getName(clazz)); |
|
456 buf.append('.'); |
|
457 } |
|
458 String name = getName(); |
|
459 buf.append(name == null ? "*" : name); |
|
460 Object type = getType(); |
|
461 if (!isInvocable()) { |
|
462 buf.append('/'); |
|
463 buf.append(type == null ? "*" : getName(type)); |
|
464 } else { |
|
465 buf.append(type == null ? "(*)*" : getName(type)); |
|
466 } |
|
467 /* |
|
468 buf.append('/'); |
|
469 // key: Public, private, pRotected, sTatic, Final, sYnchronized, |
|
470 // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic, |
|
471 // (annotation), Enum, (unused) |
|
472 final String FIELD_MOD_CHARS = "PprTF?vt????Y?E?"; |
|
473 final String METHOD_MOD_CHARS = "PprTFybVn?atY???"; |
|
474 String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS); |
|
475 for (int i = 0; i < modChars.length(); i++) { |
|
476 if ((flags & (1 << i)) != 0) { |
|
477 char mc = modChars.charAt(i); |
|
478 if (mc != '?') |
|
479 buf.append(mc); |
|
480 } |
|
481 } |
|
482 */ |
|
483 return buf.toString(); |
|
484 } |
|
485 private static String getName(Object obj) { |
|
486 if (obj instanceof Class<?>) |
|
487 return ((Class<?>)obj).getName(); |
|
488 return String.valueOf(obj); |
|
489 } |
|
490 |
|
491 // Queries to the JVM: |
|
492 /** Document? */ |
|
493 public int getVMIndex(Access token) { |
|
494 Access.check(token); |
|
495 if (!isResolved()) |
|
496 throw newIllegalStateException("not resolved"); |
|
497 return vmindex; |
|
498 } |
|
499 // public Object getVMTarget(Access token) { |
|
500 // Access.check(token); |
|
501 // if (!isResolved()) |
|
502 // throw newIllegalStateException("not resolved"); |
|
503 // return vmtarget; |
|
504 // } |
|
505 private RuntimeException newIllegalStateException(String message) { |
|
506 return new IllegalStateException(message+": "+this); |
|
507 } |
|
508 |
|
509 // handy shared exception makers (they simplify the common case code) |
|
510 public static RuntimeException newIllegalArgumentException(String message) { |
|
511 return new IllegalArgumentException(message); |
|
512 } |
|
513 public static IllegalAccessException newNoAccessException(MemberName name, Object from) { |
|
514 return newNoAccessException("cannot access", name, from); |
|
515 } |
|
516 public static IllegalAccessException newNoAccessException(String message, |
|
517 MemberName name, Object from) { |
|
518 message += ": " + name; |
|
519 if (from != null) message += ", from " + from; |
|
520 return new IllegalAccessException(message); |
|
521 } |
|
522 public static ReflectiveOperationException newNoAccessException(MemberName name) { |
|
523 if (name.isResolved()) |
|
524 return new IllegalAccessException(name.toString()); |
|
525 else if (name.isConstructor()) |
|
526 return new NoSuchMethodException(name.toString()); |
|
527 else if (name.isMethod()) |
|
528 return new NoSuchMethodException(name.toString()); |
|
529 else |
|
530 return new NoSuchFieldException(name.toString()); |
|
531 } |
|
532 public static Error uncaughtException(Exception ex) { |
|
533 Error err = new InternalError("uncaught exception"); |
|
534 err.initCause(ex); |
|
535 return err; |
|
536 } |
|
537 |
|
538 /** Actually making a query requires an access check. */ |
|
539 public static Factory getFactory(Access token) { |
|
540 Access.check(token); |
|
541 return Factory.INSTANCE; |
|
542 } |
|
543 public static Factory getFactory() { |
|
544 return getFactory(Access.getToken()); |
|
545 } |
|
546 /** A factory type for resolving member names with the help of the VM. |
|
547 * TBD: Define access-safe public constructors for this factory. |
|
548 */ |
|
549 public static class Factory { |
|
550 private Factory() { } // singleton pattern |
|
551 static Factory INSTANCE = new Factory(); |
|
552 |
|
553 private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS; |
|
554 |
|
555 /// Queries |
|
556 List<MemberName> getMembers(Class<?> defc, |
|
557 String matchName, Object matchType, |
|
558 int matchFlags, Class<?> lookupClass) { |
|
559 matchFlags &= ALLOWED_FLAGS; |
|
560 String matchSig = null; |
|
561 if (matchType != null) { |
|
562 matchSig = BytecodeDescriptor.unparse(matchType); |
|
563 if (matchSig.startsWith("(")) |
|
564 matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE); |
|
565 else |
|
566 matchFlags &= ~(ALL_KINDS & ~IS_FIELD); |
|
567 } |
|
568 final int BUF_MAX = 0x2000; |
|
569 int len1 = matchName == null ? 10 : matchType == null ? 4 : 1; |
|
570 MemberName[] buf = newMemberBuffer(len1); |
|
571 int totalCount = 0; |
|
572 ArrayList<MemberName[]> bufs = null; |
|
573 int bufCount = 0; |
|
574 for (;;) { |
|
575 bufCount = MethodHandleNatives.getMembers(defc, |
|
576 matchName, matchSig, matchFlags, |
|
577 lookupClass, |
|
578 totalCount, buf); |
|
579 if (bufCount <= buf.length) { |
|
580 if (bufCount < 0) bufCount = 0; |
|
581 totalCount += bufCount; |
|
582 break; |
|
583 } |
|
584 // JVM returned to us with an intentional overflow! |
|
585 totalCount += buf.length; |
|
586 int excess = bufCount - buf.length; |
|
587 if (bufs == null) bufs = new ArrayList<MemberName[]>(1); |
|
588 bufs.add(buf); |
|
589 int len2 = buf.length; |
|
590 len2 = Math.max(len2, excess); |
|
591 len2 = Math.max(len2, totalCount / 4); |
|
592 buf = newMemberBuffer(Math.min(BUF_MAX, len2)); |
|
593 } |
|
594 ArrayList<MemberName> result = new ArrayList<MemberName>(totalCount); |
|
595 if (bufs != null) { |
|
596 for (MemberName[] buf0 : bufs) { |
|
597 Collections.addAll(result, buf0); |
|
598 } |
|
599 } |
|
600 result.addAll(Arrays.asList(buf).subList(0, bufCount)); |
|
601 // Signature matching is not the same as type matching, since |
|
602 // one signature might correspond to several types. |
|
603 // So if matchType is a Class or MethodType, refilter the results. |
|
604 if (matchType != null && matchType != matchSig) { |
|
605 for (Iterator<MemberName> it = result.iterator(); it.hasNext();) { |
|
606 MemberName m = it.next(); |
|
607 if (!matchType.equals(m.getType())) |
|
608 it.remove(); |
|
609 } |
|
610 } |
|
611 return result; |
|
612 } |
|
613 boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> lookupClass) { |
|
614 if (m.name == null || m.type == null) { // find unique non-overloaded name |
|
615 Class<?> defc = m.getDeclaringClass(); |
|
616 List<MemberName> choices = null; |
|
617 if (m.isMethod()) |
|
618 choices = getMethods(defc, searchSupers, m.name, (MethodType) m.type, lookupClass); |
|
619 else if (m.isConstructor()) |
|
620 choices = getConstructors(defc, lookupClass); |
|
621 else if (m.isField()) |
|
622 choices = getFields(defc, searchSupers, m.name, (Class<?>) m.type, lookupClass); |
|
623 //System.out.println("resolving "+m+" to "+choices); |
|
624 if (choices == null || choices.size() != 1) |
|
625 return false; |
|
626 if (m.name == null) m.name = choices.get(0).name; |
|
627 if (m.type == null) m.type = choices.get(0).type; |
|
628 } |
|
629 MethodHandleNatives.resolve(m, lookupClass); |
|
630 if (m.isResolved()) return true; |
|
631 int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0); |
|
632 String matchSig = m.getSignature(); |
|
633 MemberName[] buf = { m }; |
|
634 int n = MethodHandleNatives.getMembers(m.getDeclaringClass(), |
|
635 m.getName(), matchSig, matchFlags, lookupClass, 0, buf); |
|
636 if (n != 1) return false; |
|
637 return m.isResolved(); |
|
638 } |
|
639 /** Produce a resolved version of the given member. |
|
640 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
641 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
642 * If lookup fails or access is not permitted, null is returned. |
|
643 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in. |
|
644 */ |
|
645 public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> lookupClass) { |
|
646 MemberName result = m.clone(); |
|
647 if (resolveInPlace(result, searchSupers, lookupClass)) |
|
648 return result; |
|
649 return null; |
|
650 } |
|
651 /** Produce a resolved version of the given member. |
|
652 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
653 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
654 * If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown. |
|
655 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in. |
|
656 */ |
|
657 public |
|
658 <NoSuchMemberException extends ReflectiveOperationException> |
|
659 MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass, |
|
660 Class<NoSuchMemberException> nsmClass) |
|
661 throws IllegalAccessException, NoSuchMemberException { |
|
662 MemberName result = resolveOrNull(m, searchSupers, lookupClass); |
|
663 if (result != null) |
|
664 return result; |
|
665 ReflectiveOperationException ex = newNoAccessException(m); |
|
666 if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex; |
|
667 throw nsmClass.cast(ex); |
|
668 } |
|
669 /** Return a list of all methods defined by the given class. |
|
670 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
671 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
672 * Inaccessible members are not added to the last. |
|
673 */ |
|
674 public List<MemberName> getMethods(Class<?> defc, boolean searchSupers, |
|
675 Class<?> lookupClass) { |
|
676 return getMethods(defc, searchSupers, null, null, lookupClass); |
|
677 } |
|
678 /** Return a list of matching methods defined by the given class. |
|
679 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
680 * Returned methods will match the name (if not null) and the type (if not null). |
|
681 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
682 * Inaccessible members are not added to the last. |
|
683 */ |
|
684 public List<MemberName> getMethods(Class<?> defc, boolean searchSupers, |
|
685 String name, MethodType type, Class<?> lookupClass) { |
|
686 int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0); |
|
687 return getMembers(defc, name, type, matchFlags, lookupClass); |
|
688 } |
|
689 /** Return a list of all constructors defined by the given class. |
|
690 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
691 * Inaccessible members are not added to the last. |
|
692 */ |
|
693 public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) { |
|
694 return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass); |
|
695 } |
|
696 /** Return a list of all fields defined by the given class. |
|
697 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
698 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
699 * Inaccessible members are not added to the last. |
|
700 */ |
|
701 public List<MemberName> getFields(Class<?> defc, boolean searchSupers, |
|
702 Class<?> lookupClass) { |
|
703 return getFields(defc, searchSupers, null, null, lookupClass); |
|
704 } |
|
705 /** Return a list of all fields defined by the given class. |
|
706 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
707 * Returned fields will match the name (if not null) and the type (if not null). |
|
708 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
709 * Inaccessible members are not added to the last. |
|
710 */ |
|
711 public List<MemberName> getFields(Class<?> defc, boolean searchSupers, |
|
712 String name, Class<?> type, Class<?> lookupClass) { |
|
713 int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0); |
|
714 return getMembers(defc, name, type, matchFlags, lookupClass); |
|
715 } |
|
716 /** Return a list of all nested types defined by the given class. |
|
717 * Super types are searched (for inherited members) if {@code searchSupers} is true. |
|
718 * Access checking is performed on behalf of the given {@code lookupClass}. |
|
719 * Inaccessible members are not added to the last. |
|
720 */ |
|
721 public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers, |
|
722 Class<?> lookupClass) { |
|
723 int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0); |
|
724 return getMembers(defc, null, null, matchFlags, lookupClass); |
|
725 } |
|
726 private static MemberName[] newMemberBuffer(int length) { |
|
727 MemberName[] buf = new MemberName[length]; |
|
728 // fill the buffer with dummy structs for the JVM to fill in |
|
729 for (int i = 0; i < length; i++) |
|
730 buf[i] = new MemberName(); |
|
731 return buf; |
|
732 } |
|
733 } |
|
734 |
|
735 // static { |
|
736 // System.out.println("Hello world! My methods are:"); |
|
737 // System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null)); |
|
738 // } |
|
739 } |
|