1 /*
2 * Copyright 2008-2009 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package impl.java.dyn;
27
28 import impl.java.dyn.util.Signatures;
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.Collections;
37 import java.util.Iterator;
38 import java.util.List;
39 import static impl.java.dyn.MethodHandleNatives.Constants.*;
40
41 /**
42 * Compact information which fully characterizes a method or field reference.
43 * When resolved, it includes a direct pointer to JVM metadata.
44 * This representation is stateless and only decriptive.
45 * It provides no private information and no capability to use the member.
46 * <p>
47 * By contrast, a java.lang.reflect.Method contains fuller information
48 * about the internals of a method (except its bytecodes) and also
49 * allows invocation. A MemberName is much lighter than a reflect.Method,
50 * since it contains about 7 fields to Method's 16 (plus its sub-arrays),
51 * and those seven fields omit much of the information in Method.
52 * @author jrose
53 */
54 public final class MemberName implements Member, Cloneable {
55 private Class<?> clazz; // class in which the method is defined
56 private String name; // may be null if not yet materialized
57 private Object type; // may be null if not yet materialized
58 private int flags; // modifier bits; see reflect.Modifier
59
60 private Object vmtarget; // VM-specific target value
61 private int vmindex; // method index within class or interface
62
63 { vmindex = VM_INDEX_UNINITIALIZED; }
64
65 public Class<?> getDeclaringClass() {
66 if (clazz == null && isResolved()) {
67 expandFromVM();
68 }
69 return clazz;
70 }
71
72 public ClassLoader getClassLoader() {
73 return clazz.getClassLoader();
74 }
75
76 public String getName() {
77 if (name == null) {
78 expandFromVM();
79 if (name == null) return null;
80 }
81 return name;
82 }
83
84 public MethodType getMethodType() {
85 if (type == null) {
86 expandFromVM();
87 if (type == null) return null;
88 }
89 if (!isInvocable())
90 throw newIllegalArgumentException("not invocable, no method type");
91 if (type instanceof MethodType) {
92 return (MethodType) type;
93 }
94 if (type instanceof String) {
95 String sig = (String) type;
96 MethodType res = MethodType.fromBytecodeString(sig, getClassLoader());
97 this.type = res;
98 return res;
99 }
100 if (type instanceof Object[]) {
101 Object[] typeInfo = (Object[]) type;
102 Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
103 Class<?> rtype = (Class<?>) typeInfo[0];
104 MethodType res = MethodType.make(rtype, ptypes);
105 this.type = res;
106 return res;
107 }
108 throw new InternalError("bad method type "+type);
109 }
110
111 public MethodType getInvocationType() {
112 MethodType itype = getMethodType();
113 if (!isStatic())
114 itype = itype.insertParameterType(0, clazz);
115 return itype;
116 }
117
118 public Class<?>[] getParameterTypes() {
119 return getMethodType().parameterArray();
120 }
121
122 public Class<?> getReturnType() {
123 return getMethodType().returnType();
124 }
125
126 public Class<?> getFieldType() {
127 if (type == null) {
128 expandFromVM();
129 if (type == null) return null;
130 }
131 if (isInvocable())
132 throw newIllegalArgumentException("not a field or nested class, no simple type");
133 if (type instanceof Class<?>) {
134 return (Class<?>) type;
135 }
136 if (type instanceof String) {
137 String sig = (String) type;
138 MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader());
139 Class<?> res = mtype.returnType();
140 this.type = res;
141 return res;
142 }
143 throw new InternalError("bad field type "+type);
144 }
145
146 public Object getType() {
147 return (isInvocable() ? getMethodType() : getFieldType());
148 }
149
150 public String getSignature() {
151 if (type == null) {
152 expandFromVM();
153 if (type == null) return null;
154 }
155 if (type instanceof String)
156 return (String) type;
157 if (isInvocable())
158 return Signatures.unparse(getMethodType());
159 else
160 return Signatures.unparse(getFieldType());
161 }
162
163 public int getModifiers() {
164 return (flags & RECOGNIZED_MODIFIERS);
165 }
166
167 private void setFlags(int flags) {
168 this.flags = flags;
169 assert(testAnyFlags(ALL_KINDS));
170 }
171
172 private boolean testFlags(int mask, int value) {
173 return (flags & mask) == value;
174 }
175 private boolean testAllFlags(int mask) {
176 return testFlags(mask, mask);
177 }
178 private boolean testAnyFlags(int mask) {
179 return !testFlags(mask, 0);
180 }
181
182 public boolean isStatic() {
183 return Modifier.isStatic(flags);
184 }
185 public boolean isPublic() {
186 return Modifier.isPublic(flags);
187 }
188 public boolean isPrivate() {
189 return Modifier.isPrivate(flags);
190 }
191 public boolean isProtected() {
192 return Modifier.isProtected(flags);
193 }
194 public boolean isFinal() {
195 return Modifier.isFinal(flags);
196 }
197 public boolean isAbstract() {
198 return Modifier.isAbstract(flags);
199 }
200 // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
201
202 // unofficial modifier flags, used by HotSpot:
203 static final int BRIDGE = 0x00000040;
204 static final int VARARGS = 0x00000080;
205 static final int SYNTHETIC = 0x00001000;
206 static final int ANNOTATION= 0x00002000;
207 static final int ENUM = 0x00004000;
208 public boolean isBridge() {
209 return testAllFlags(IS_METHOD | BRIDGE);
210 }
211 public boolean isVarargs() {
212 return testAllFlags(VARARGS) && isInvocable();
213 }
214 public boolean isSynthetic() {
215 return testAllFlags(SYNTHETIC);
216 }
217
218 static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
219
220 // modifiers exported by the JVM:
221 static final int RECOGNIZED_MODIFIERS = 0xFFFF;
222
223 // private flags, not part of RECOGNIZED_MODIFIERS:
224 static final int
225 IS_METHOD = MN_IS_METHOD, // method (not constructor)
226 IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
227 IS_FIELD = MN_IS_FIELD, // field
228 IS_TYPE = MN_IS_TYPE; // nested type
229 static final int // for MethodHandleNatives.getMembers
230 SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES,
231 SEARCH_INTERFACES = MN_SEARCH_INTERFACES;
232
233 static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
234 static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
235 static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
236 static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
237 static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
238
239 public boolean isInvocable() {
240 return testAnyFlags(IS_INVOCABLE);
241 }
242 public boolean isFieldOrMethod() {
243 return testAnyFlags(IS_FIELD_OR_METHOD);
244 }
245 public boolean isMethod() {
246 return testAllFlags(IS_METHOD);
247 }
248 public boolean isConstructor() {
249 return testAllFlags(IS_CONSTRUCTOR);
250 }
251 public boolean isField() {
252 return testAllFlags(IS_FIELD);
253 }
254 public boolean isType() {
255 return testAllFlags(IS_TYPE);
256 }
257 public boolean isPackage() {
258 return !testAnyFlags(ALL_ACCESS);
259 }
260
261 /** Initialize a query. It is not resolved. */
262 private void init(Class<?> defClass, String name, Object type, int flags) {
263 // defining class is allowed to be null (for a naked name/type pair)
264 name.toString(); // null check
265 type.equals(type); // null check
266 // fill in fields:
267 this.clazz = defClass;
268 this.name = name;
269 this.type = type;
270 setFlags(flags);
271 assert(!isResolved());
272 }
273
274 private void expandFromVM() {
275 if (!isResolved()) return;
276 if (type instanceof Object[])
277 type = null; // don't saddle JVM w/ typeInfo
278 MethodHandleNatives.expand(this);
279 }
280
281 // Capturing information from the Core Reflection API:
282 private static int flagsMods(int flags, int mods) {
283 assert((flags & RECOGNIZED_MODIFIERS) == 0);
284 assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
285 return flags | mods;
286 }
287 public MemberName(Method m) {
288 Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
289 init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
290 // fill in vmtarget, vmindex while we have m in hand:
291 MethodHandleNatives.init(this, m);
292 assert(isResolved());
293 }
294 public MemberName(Constructor ctor) {
295 Object[] typeInfo = { void.class, ctor.getParameterTypes() };
296 init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
297 // fill in vmtarget, vmindex while we have ctor in hand:
298 MethodHandleNatives.init(this, ctor);
299 assert(isResolved());
300 }
301 public MemberName(Field fld) {
302 init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
303 // fill in vmtarget, vmindex while we have fld in hand:
304 MethodHandleNatives.init(this, fld);
305 assert(isResolved());
306 }
307 public MemberName(Class<?> type) {
308 init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
309 vmindex = 0; // isResolved
310 assert(isResolved());
311 }
312
313 // bare-bones constructor; the JVM will fill it in
314 MemberName() { }
315
316 // locally useful cloner
317 @Override protected MemberName clone() {
318 try {
319 return (MemberName) super.clone();
320 } catch (CloneNotSupportedException ex) {
321 throw new InternalError();
322 }
323 }
324
325 // %%% define equals/hashcode?
326
327 // Construction from symbolic parts, for queries:
328 public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) {
329 init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
330 }
331 public MemberName(Class<?> defClass, String name, Class<?> type) {
332 this(defClass, name, type, 0);
333 }
334 public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) {
335 int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
336 init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
337 }
338 public MemberName(Class<?> defClass, String name, MethodType type) {
339 this(defClass, name, type, 0);
340 }
341
342 boolean isResolved() {
343 return (vmindex != VM_INDEX_UNINITIALIZED);
344 }
345
346 public boolean hasReceiverTypeDispatch() {
347 return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
348 }
349
350 @Override
351 public String toString() {
352 if (isType())
353 return type.toString(); // class java.lang.String
354 // else it is a field, method, or constructor
355 StringBuilder buf = new StringBuilder();
356 if (getDeclaringClass() != null) {
357 buf.append(getName(clazz));
358 buf.append('.');
359 }
360 buf.append(getName());
361 if (!isInvocable()) buf.append('/');
362 buf.append(getName(getType()));
363 /*
364 buf.append('/');
365 // key: Public, private, pRotected, sTatic, Final, sYnchronized,
366 // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic,
367 // (annotation), Enum, (unused)
368 final String FIELD_MOD_CHARS = "PprTF?vt????Y?E?";
369 final String METHOD_MOD_CHARS = "PprTFybVn?atY???";
370 String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS);
371 for (int i = 0; i < modChars.length(); i++) {
372 if ((flags & (1 << i)) != 0) {
373 char mc = modChars.charAt(i);
374 if (mc != '.')
375 buf.append(mc);
376 }
377 }
378 */
379 return buf.toString();
380 }
381 private static String getName(Object obj) {
382 if (obj instanceof Class<?>)
383 return ((Class<?>)obj).getName();
384 return obj.toString();
385 }
386
387 // Queries to the JVM:
388 public int getVMIndex(Access token) {
389 Access.check(token);
390 if (!isResolved())
391 throw newIllegalStateException("not resolved");
392 return vmindex;
393 }
394 // public Object getVMTarget(Access token) {
395 // Access.check(token);
396 // if (!isResolved())
397 // throw newIllegalStateException("not resolved");
398 // return vmtarget;
399 // }
400 private RuntimeException newIllegalStateException(String message) {
401 return new IllegalStateException(message+": "+this);
402 }
403
404 // handy shared exception makers (they simplify the common case code)
405 public static RuntimeException newIllegalArgumentException(String message) {
406 return new IllegalArgumentException(message);
407 }
408 public static NoAccessException newNoAccessException(MemberName name, Class<?> caller) {
409 return newNoAccessException("cannot access", name, caller);
410 }
411 public static NoAccessException newNoAccessException(String message,
412 MemberName name, Class<?> caller) {
413 message += ": " + name;
414 if (caller != null) message += ", from " + caller.getName();
415 return new NoAccessException(message);
416 }
417
418 /** Actually making a query requires an access check. */
419 public static Factory getFactory(Access token) {
420 Access.check(token);
421 return Factory.INSTANCE;
422 }
423 public static Factory getFactory() {
424 return getFactory(Access.getToken());
425 }
426 public static class Factory {
427 private Factory() { } // singleton pattern
428 static Factory INSTANCE = new Factory();
429
430 private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS;
431
432 /// Queries
433 List<MemberName> getMembers(Class<?> defc,
434 String matchName, Object matchType,
435 int matchFlags, Class<?> caller) {
436 matchFlags &= ALLOWED_FLAGS;
437 String matchSig = null;
438 if (matchType != null) {
439 matchSig = Signatures.unparse(matchType);
440 if (matchSig.startsWith("("))
441 matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
442 else
443 matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
444 }
445 final int BUF_MAX = 0x2000;
446 int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
447 MemberName[] buf = newMemberBuffer(len1);
448 int totalCount = 0;
449 ArrayList<MemberName[]> bufs = null;
450 for (;;) {
451 int bufCount = MethodHandleNatives.getMembers(defc,
452 matchName, matchSig, matchFlags, caller,
453 totalCount, buf);
454 if (bufCount <= buf.length) {
455 if (bufCount >= 0)
456 totalCount += bufCount;
457 break;
458 }
459 // JVM returned tp us with an intentional overflow!
460 totalCount += buf.length;
461 int excess = bufCount - buf.length;
462 if (bufs == null) bufs = new ArrayList<MemberName[]>(1);
463 bufs.add(buf);
464 int len2 = buf.length;
465 len2 = Math.max(len2, excess);
466 len2 = Math.max(len2, totalCount / 4);
467 buf = newMemberBuffer(Math.min(BUF_MAX, len2));
468 }
469 ArrayList<MemberName> result = new ArrayList<MemberName>(totalCount);
470 if (bufs != null) {
471 for (MemberName[] buf0 : bufs) {
472 Collections.addAll(result, buf0);
473 }
474 }
475 Collections.addAll(result, buf);
476 // Signature matching is not the same as type matching, since
477 // one signature might correspond to several types.
478 // So if matchType is a Class or MethodType, refilter the results.
479 if (matchType != null && matchType != matchSig) {
480 for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
481 MemberName m = it.next();
482 if (!matchType.equals(m.getType()))
483 it.remove();
484 }
485 }
486 return result;
487 }
488 boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> caller) {
489 MethodHandleNatives.resolve(m, caller);
490 if (m.isResolved()) return true;
491 int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
492 String matchSig = m.getSignature();
493 MemberName[] buf = { m };
494 int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
495 m.getName(), matchSig, matchFlags, caller, 0, buf);
496 if (n != 1) return false;
497 return m.isResolved();
498 }
499 public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> caller) {
500 MemberName result = m.clone();
501 if (resolveInPlace(result, searchSupers, caller))
502 return result;
503 return null;
504 }
505 public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> caller) {
506 MemberName result = resolveOrNull(m, searchSupers, caller);
507 if (result != null)
508 return result;
509 throw newNoAccessException(m, caller);
510 }
511 public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
512 Class<?> caller) {
513 return getMethods(defc, searchSupers, null, null, caller);
514 }
515 public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
516 String name, MethodType type, Class<?> caller) {
517 int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
518 return getMembers(defc, name, type, matchFlags, caller);
519 }
520 public List<MemberName> getConstructors(Class<?> defc, Class<?> caller) {
521 return getMembers(defc, null, null, IS_CONSTRUCTOR, caller);
522 }
523 public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
524 Class<?> caller) {
525 return getFields(defc, searchSupers, null, null, caller);
526 }
527 public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
528 String name, Class<?> type, Class<?> caller) {
529 int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
530 return getMembers(defc, name, type, matchFlags, caller);
531 }
532 public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
533 Class<?> caller) {
534 int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
535 return getMembers(defc, null, null, matchFlags, caller);
536 }
537 private static MemberName[] newMemberBuffer(int length) {
538 MemberName[] buf = new MemberName[length];
539 // fill the buffer with dummy structs for the JVM to fill in
540 for (int i = 0; i < length; i++)
541 buf[i] = new MemberName();
542 return buf;
543 }
544 }
545
546 // static {
547 // System.out.println("Hello world! My methods are:");
548 // System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
549 // }
550 }