1 /*
2 * Copyright (c) 2008, 2025, 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 java.lang.invoke;
27
28 import sun.invoke.util.VerifyAccess;
29
30 import java.lang.reflect.Constructor;
31 import java.lang.reflect.Field;
32 import java.lang.reflect.Member;
33 import java.lang.reflect.Method;
34 import java.lang.reflect.Modifier;
35 import java.util.Objects;
36
37 import static java.lang.invoke.MethodHandleNatives.Constants.*;
38 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
39 import static java.lang.invoke.MethodHandleStatics.newInternalError;
40
41 /**
42 * A {@code MemberName} is a compact symbolic datum which fully characterizes
43 * a method or field reference.
44 * A member name refers to a field, method, constructor, or member type.
45 * Every member name has a simple name (a string) and a type (either a Class or MethodType).
46 * A member name may also have a non-null declaring class, or it may be simply
47 * a naked name/type pair.
48 * A member name may also have non-zero modifier flags.
49 * Finally, a member name may be either resolved or unresolved.
50 * If it is resolved, the existence of the named member has been determined by the JVM.
51 * <p>
52 * Whether resolved or not, a member name provides no access rights or
53 * invocation capability to its possessor. It is merely a compact
54 * representation of all symbolic information necessary to link to
55 * and properly use the named member.
56 * <p>
57 * When resolved, a member name's internal implementation may include references to JVM metadata.
58 * This representation is stateless and only descriptive.
59 * It provides no private information and no capability to use the member.
60 * <p>
61 * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information
62 * about the internals of a method (except its bytecodes) and also
63 * allows invocation. A MemberName is much lighter than a Method,
64 * since it contains about 7 fields to the 16 of Method (plus its sub-arrays),
65 * and those seven fields omit much of the information in Method.
66 * @author jrose
67 */
68
69 /*non-public*/
70 final class MemberName implements Member, Cloneable {
71 private Class<?> clazz; // class in which the member is defined
72 private String name; // may be null if not yet materialized
73 private Object type; // may be null if not yet materialized
74 private int flags; // modifier bits; see reflect.Modifier
75 private ResolvedMethodName method; // cached resolved method information
76 //@Injected intptr_t vmindex; // vtable index or offset of resolved member
77 Object resolution; // if null, this guy is resolved
78
79 /** Return the declaring class of this member.
80 * In the case of a bare name and type, the declaring class will be null.
81 */
82 public Class<?> getDeclaringClass() {
83 return clazz;
84 }
85
86 /** Utility method producing the class loader of the declaring class. */
87 public ClassLoader getClassLoader() {
88 return clazz.getClassLoader();
89 }
90
91 /** Return the simple name of this member.
92 * For a type, it is the same as {@link Class#getSimpleName}.
93 * For a method or field, it is the simple name of the member.
94 * For a constructor, it is always {@code "<init>"}.
95 */
96 public String getName() {
97 if (name == null) {
98 expandFromVM();
99 if (name == null) {
100 return null;
101 }
102 }
103 return name;
104 }
105
106 public MethodType getMethodOrFieldType() {
107 if (isInvocable())
108 return getMethodType();
109 if (isGetter())
110 return MethodType.methodType(getFieldType());
111 if (isSetter())
112 return MethodType.methodType(void.class, getFieldType());
113 throw new InternalError("not a method or field: "+this);
114 }
115
116 /** Return the declared type of this member, which
117 * must be a method or constructor.
118 */
119 public MethodType getMethodType() {
120 if (type == null) {
121 expandFromVM();
122 if (type == null) {
123 return null;
124 }
125 }
126 if (!isInvocable()) {
127 throw newIllegalArgumentException("not invocable, no method type");
128 }
129
130 {
131 // Get a snapshot of type which doesn't get changed by racing threads.
132 final Object type = this.type;
133 if (type instanceof MethodType mt) {
134 return mt;
135 }
136 }
137
138 // type is not a MethodType yet. Convert it thread-safely.
139 synchronized (this) {
140 if (type instanceof String sig) {
141 MethodType res = MethodType.fromDescriptor(sig, getClassLoader());
142 type = res;
143 } else if (type instanceof Object[] typeInfo) {
144 Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
145 Class<?> rtype = (Class<?>) typeInfo[0];
146 MethodType res = MethodType.methodType(rtype, ptypes, true);
147 type = res;
148 }
149 // Make sure type is a MethodType for racing threads.
150 assert type instanceof MethodType : "bad method type " + type;
151 }
152 return (MethodType) type;
153 }
154
155 /** Return the descriptor of this member, which
156 * must be a method or constructor.
157 */
158 String getMethodDescriptor() {
159 if (type == null) {
160 expandFromVM();
161 if (type == null) {
162 return null;
163 }
164 }
165 if (!isInvocable()) {
166 throw newIllegalArgumentException("not invocable, no method type");
167 }
168
169 // Get a snapshot of type which doesn't get changed by racing threads.
170 final Object type = this.type;
171 if (type instanceof String str) {
172 return str;
173 } else {
174 return getMethodType().toMethodDescriptorString();
175 }
176 }
177
178 /** Return the actual type under which this method or constructor must be invoked.
179 * For non-static methods or constructors, this is the type with a leading parameter,
180 * a reference to declaring class. For static methods, it is the same as the declared type.
181 */
182 public MethodType getInvocationType() {
183 MethodType itype = getMethodOrFieldType();
184 if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
185 return itype.changeReturnType(clazz);
186 if (!isStatic())
187 return itype.insertParameterTypes(0, clazz);
188 return itype;
189 }
190
191 /** Return the declared type of this member, which
192 * must be a field or type.
193 * If it is a type member, that type itself is returned.
194 */
195 public Class<?> getFieldType() {
196 if (type == null) {
197 expandFromVM();
198 if (type == null) {
199 return null;
200 }
201 }
202 if (isInvocable()) {
203 throw newIllegalArgumentException("not a field or nested class, no simple type");
204 }
205
206 {
207 // Get a snapshot of type which doesn't get changed by racing threads.
208 final Object type = this.type;
209 if (type instanceof Class<?> cl) {
210 return cl;
211 }
212 }
213
214 // type is not a Class yet. Convert it thread-safely.
215 synchronized (this) {
216 if (type instanceof String sig) {
217 MethodType mtype = MethodType.fromDescriptor("()"+sig, getClassLoader());
218 Class<?> res = mtype.returnType();
219 type = res;
220 }
221 // Make sure type is a Class for racing threads.
222 assert type instanceof Class<?> : "bad field type " + type;
223 }
224 return (Class<?>) type;
225 }
226
227 /** Utility method to produce either the method type or field type of this member. */
228 public Object getType() {
229 return (isInvocable() ? getMethodType() : getFieldType());
230 }
231
232 /** Return the modifier flags of this member.
233 * @see java.lang.reflect.Modifier
234 */
235 public int getModifiers() {
236 return (flags & RECOGNIZED_MODIFIERS);
237 }
238
239 /** Return the reference kind of this member, or zero if none.
240 */
241 public byte getReferenceKind() {
242 return (byte) ((flags >>> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK);
243 }
244 private boolean referenceKindIsConsistent() {
245 byte refKind = getReferenceKind();
246 if (refKind == REF_NONE) return isType();
247 if (isField()) {
248 assert(staticIsConsistent());
249 assert(MethodHandleNatives.refKindIsField(refKind));
250 } else if (isConstructor()) {
251 assert(refKind == REF_newInvokeSpecial || refKind == REF_invokeSpecial);
252 } else if (isMethod()) {
253 assert(staticIsConsistent());
254 assert(MethodHandleNatives.refKindIsMethod(refKind));
255 if (clazz.isInterface())
256 assert(refKind == REF_invokeInterface ||
257 refKind == REF_invokeStatic ||
258 refKind == REF_invokeSpecial ||
259 refKind == REF_invokeVirtual && isObjectPublicMethod());
260 } else {
261 assert(false);
262 }
263 return true;
264 }
265 private boolean isObjectPublicMethod() {
266 if (clazz == Object.class) return true;
267 MethodType mtype = getMethodType();
268 if (name.equals("toString") && mtype.returnType() == String.class && mtype.parameterCount() == 0)
269 return true;
270 if (name.equals("hashCode") && mtype.returnType() == int.class && mtype.parameterCount() == 0)
271 return true;
272 if (name.equals("equals") && mtype.returnType() == boolean.class && mtype.parameterCount() == 1 && mtype.parameterType(0) == Object.class)
273 return true;
274 return false;
275 }
276
277 /*non-public*/
278 boolean referenceKindIsConsistentWith(int originalRefKind) {
279 int refKind = getReferenceKind();
280 if (refKind == originalRefKind) return true;
281 if (getClass().desiredAssertionStatus()) {
282 switch (originalRefKind) {
283 case REF_invokeInterface -> {
284 // Looking up an interface method, can get (e.g.) Object.hashCode
285 assert (refKind == REF_invokeVirtual || refKind == REF_invokeSpecial) : this;
286 }
287 case REF_invokeVirtual, REF_newInvokeSpecial -> {
288 // Looked up a virtual, can get (e.g.) final String.hashCode.
289 assert (refKind == REF_invokeSpecial) : this;
290 }
291 default -> {
292 assert (false) : this + " != " + MethodHandleNatives.refKindName((byte) originalRefKind);
293 }
294 }
295 }
296 return true;
297 }
298 private boolean staticIsConsistent() {
299 byte refKind = getReferenceKind();
300 return MethodHandleNatives.refKindIsStatic(refKind) == isStatic() || getModifiers() == 0;
301 }
302 private boolean vminfoIsConsistent() {
303 byte refKind = getReferenceKind();
304 assert(isResolved()); // else don't call
305 Object vminfo = MethodHandleNatives.getMemberVMInfo(this);
306 assert(vminfo instanceof Object[]);
307 long vmindex = (Long) ((Object[])vminfo)[0];
308 Object vmtarget = ((Object[])vminfo)[1];
309 if (MethodHandleNatives.refKindIsField(refKind)) {
310 assert(vmindex >= 0) : vmindex + ":" + this;
311 assert(vmtarget instanceof Class);
312 } else {
313 if (MethodHandleNatives.refKindDoesDispatch(refKind))
314 assert(vmindex >= 0) : vmindex + ":" + this;
315 else
316 assert(vmindex < 0) : vmindex;
317 assert(vmtarget instanceof MemberName) : vmtarget + " in " + this;
318 }
319 return true;
320 }
321
322 private MemberName changeReferenceKind(byte refKind, byte oldKind) {
323 assert(getReferenceKind() == oldKind && MethodHandleNatives.refKindIsValid(refKind));
324 flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
325 return this;
326 }
327
328 private boolean matchingFlagsSet(int mask, int flags) {
329 return (this.flags & mask) == flags;
330 }
331 private boolean allFlagsSet(int flags) {
332 return (this.flags & flags) == flags;
333 }
334 private boolean anyFlagSet(int flags) {
335 return (this.flags & flags) != 0;
336 }
337
338 /** Utility method to query if this member is a method handle invocation (invoke or invokeExact).
339 */
340 public boolean isMethodHandleInvoke() {
341 final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
342 final int negs = Modifier.STATIC;
343 if (matchingFlagsSet(bits | negs, bits) && clazz == MethodHandle.class) {
344 return isMethodHandleInvokeName(name);
345 }
346 return false;
347 }
348 public static boolean isMethodHandleInvokeName(String name) {
349 return switch (name) {
350 case "invoke", "invokeExact" -> true;
351 default -> false;
352 };
353 }
354 public boolean isVarHandleMethodInvoke() {
355 final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
356 final int negs = Modifier.STATIC;
357 if (matchingFlagsSet(bits | negs, bits) && clazz == VarHandle.class) {
358 return isVarHandleMethodInvokeName(name);
359 }
360 return false;
361 }
362 public static boolean isVarHandleMethodInvokeName(String name) {
363 try {
364 VarHandle.AccessMode.valueFromMethodName(name);
365 return true;
366 } catch (IllegalArgumentException e) {
367 return false;
368 }
369 }
370 private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
371
372 /** Utility method to query the modifier flags of this member. */
373 public boolean isStatic() {
374 return Modifier.isStatic(flags);
375 }
376 /** Utility method to query the modifier flags of this member. */
377 public boolean isPublic() {
378 return Modifier.isPublic(flags);
379 }
380 /** Utility method to query the modifier flags of this member. */
381 public boolean isPrivate() {
382 return Modifier.isPrivate(flags);
383 }
384 /** Utility method to query the modifier flags of this member. */
385 public boolean isProtected() {
386 return Modifier.isProtected(flags);
387 }
388 /** Utility method to query the modifier flags of this member. */
389 public boolean isFinal() {
390 return Modifier.isFinal(flags);
391 }
392 /** Utility method to query whether this member or its defining class is final. */
393 public boolean canBeStaticallyBound() {
394 return Modifier.isFinal(flags | clazz.getModifiers());
395 }
396 /** Utility method to query the modifier flags of this member. */
397 public boolean isVolatile() {
398 return Modifier.isVolatile(flags);
399 }
400 /** Utility method to query the modifier flags of this member. */
401 public boolean isAbstract() {
402 return Modifier.isAbstract(flags);
403 }
404 /** Utility method to query the modifier flags of this member. */
405 public boolean isNative() {
406 return Modifier.isNative(flags);
407 }
408 // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
409
410 // unofficial modifier flags, used by HotSpot:
411 static final int BRIDGE = 0x00000040;
412 static final int VARARGS = 0x00000080;
413 static final int SYNTHETIC = 0x00001000;
414 static final int ANNOTATION= 0x00002000;
415 static final int ENUM = 0x00004000;
416 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
417 public boolean isBridge() {
418 return allFlagsSet(IS_METHOD | BRIDGE);
419 }
420 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
421 public boolean isVarargs() {
422 return allFlagsSet(VARARGS) && isInvocable();
423 }
424 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
425 public boolean isSynthetic() {
426 return allFlagsSet(SYNTHETIC);
427 }
428
429 static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
430
431 // modifiers exported by the JVM:
432 static final int RECOGNIZED_MODIFIERS = 0xFFFF;
433
434 // private flags, not part of RECOGNIZED_MODIFIERS:
435 static final int
436 IS_METHOD = MN_IS_METHOD, // method (not constructor)
437 IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
438 IS_FIELD = MN_IS_FIELD, // field
439 IS_TYPE = MN_IS_TYPE, // nested type
440 CALLER_SENSITIVE = MN_CALLER_SENSITIVE, // @CallerSensitive annotation detected
441 TRUSTED_FINAL = MN_TRUSTED_FINAL; // trusted final field
442
443 static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
444 static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
445 static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
446
447 /** Utility method to query whether this member is a method or constructor. */
448 public boolean isInvocable() {
449 return anyFlagSet(IS_INVOCABLE);
450 }
451 /** Query whether this member is a method. */
452 public boolean isMethod() {
453 return allFlagsSet(IS_METHOD);
454 }
455 /** Query whether this member is a constructor. */
456 public boolean isConstructor() {
457 return allFlagsSet(IS_CONSTRUCTOR);
458 }
459 /** Query whether this member is a field. */
460 public boolean isField() {
461 return allFlagsSet(IS_FIELD);
462 }
463 /** Query whether this member is a type. */
464 public boolean isType() {
465 return allFlagsSet(IS_TYPE);
466 }
467 /** Utility method to query whether this member is neither public, private, nor protected. */
468 public boolean isPackage() {
469 return !anyFlagSet(ALL_ACCESS);
470 }
471 /** Query whether this member has a CallerSensitive annotation. */
472 public boolean isCallerSensitive() {
473 return allFlagsSet(CALLER_SENSITIVE);
474 }
475 /** Query whether this member is a trusted final field. */
476 public boolean isTrustedFinalField() {
477 return allFlagsSet(TRUSTED_FINAL | IS_FIELD);
478 }
479
480 /**
481 * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
482 */
483 public boolean refersTo(Class<?> declc, String n) {
484 return clazz == declc && getName().equals(n);
485 }
486
487 /** Initialize a query. It is not resolved. */
488 private void init(Class<?> defClass, String name, Object type, int flags) {
489 // defining class is allowed to be null (for a naked name/type pair)
490 //name.toString(); // null check
491 //type.equals(type); // null check
492 // fill in fields:
493 this.clazz = defClass;
494 this.name = name;
495 this.type = type;
496 this.flags = flags;
497 assert(anyFlagSet(ALL_KINDS) && this.resolution == null); // nobody should have touched this yet
498 //assert(referenceKindIsConsistent()); // do this after resolution
499 }
500
501 /**
502 * Calls down to the VM to fill in the fields. This method is
503 * synchronized to avoid racing calls.
504 */
505 private void expandFromVM() {
506 if (type != null) {
507 return;
508 }
509 if (!isResolved()) {
510 return;
511 }
512 MethodHandleNatives.expand(this);
513 }
514
515 // Capturing information from the Core Reflection API:
516 private static int flagsMods(int flags, int mods, byte refKind) {
517 assert((flags & RECOGNIZED_MODIFIERS) == 0
518 && (mods & ~RECOGNIZED_MODIFIERS) == 0
519 && (refKind & ~MN_REFERENCE_KIND_MASK) == 0);
520 return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
521 }
522 /** Create a name for the given reflected method. The resulting name will be in a resolved state. */
523 public MemberName(Method m) {
524 this(m, false);
525 }
526 @SuppressWarnings("LeakingThisInConstructor")
527 public MemberName(Method m, boolean wantSpecial) {
528 Objects.requireNonNull(m);
529 // fill in vmtarget, vmindex while we have m in hand:
530 MethodHandleNatives.init(this, m);
531 if (clazz == null) { // MHN.init failed
532 if (m.getDeclaringClass() == MethodHandle.class &&
533 isMethodHandleInvokeName(m.getName())) {
534 // The JVM did not reify this signature-polymorphic instance.
535 // Need a special case here.
536 // See comments on MethodHandleNatives.linkMethod.
537 MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
538 int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
539 init(MethodHandle.class, m.getName(), type, flags);
540 if (isMethodHandleInvoke())
541 return;
542 }
543 if (m.getDeclaringClass() == VarHandle.class &&
544 isVarHandleMethodInvokeName(m.getName())) {
545 // The JVM did not reify this signature-polymorphic instance.
546 // Need a special case here.
547 // See comments on MethodHandleNatives.linkMethod.
548 MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
549 int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
550 init(VarHandle.class, m.getName(), type, flags);
551 if (isVarHandleMethodInvoke())
552 return;
553 }
554 throw new LinkageError(m.toString());
555 }
556 assert(isResolved());
557 this.name = m.getName();
558 if (this.type == null)
559 this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
560 if (wantSpecial) {
561 if (isAbstract())
562 throw new AbstractMethodError(this.toString());
563 if (getReferenceKind() == REF_invokeVirtual)
564 changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
565 else if (getReferenceKind() == REF_invokeInterface)
566 // invokeSpecial on a default method
567 changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
568 }
569 }
570 public MemberName asSpecial() {
571 switch (getReferenceKind()) {
572 case REF_invokeSpecial: return this;
573 case REF_invokeVirtual: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
574 case REF_invokeInterface: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
575 case REF_newInvokeSpecial: return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
576 }
577 throw new IllegalArgumentException(this.toString());
578 }
579 /** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind.
580 * In that case it must already be REF_invokeSpecial.
581 */
582 public MemberName asConstructor() {
583 switch (getReferenceKind()) {
584 case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
585 case REF_newInvokeSpecial: return this;
586 }
587 throw new IllegalArgumentException(this.toString());
588 }
589 /** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind
590 * REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface.
591 * The end result is to get a fully virtualized version of the MN.
592 * (Note that resolving in the JVM will sometimes devirtualize, changing
593 * REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface
594 * in some corner cases to either of the previous two; this transform
595 * undoes that change under the assumption that it occurred.)
596 */
597 public MemberName asNormalOriginal() {
598 byte refKind = getReferenceKind();
599 byte newRefKind = switch (refKind) {
600 case REF_invokeInterface,
601 REF_invokeVirtual,
602 REF_invokeSpecial -> clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
603 default -> refKind;
604 };
605 if (newRefKind == refKind)
606 return this;
607 MemberName result = clone().changeReferenceKind(newRefKind, refKind);
608 assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
609 return result;
610 }
611 /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
612 @SuppressWarnings("LeakingThisInConstructor")
613 public MemberName(Constructor<?> ctor) {
614 Objects.requireNonNull(ctor);
615 // fill in vmtarget, vmindex while we have ctor in hand:
616 MethodHandleNatives.init(this, ctor);
617 assert(isResolved() && this.clazz != null);
618 this.name = CONSTRUCTOR_NAME;
619 if (this.type == null)
620 this.type = new Object[] { void.class, ctor.getParameterTypes() };
621 }
622 /** Create a name for the given reflected field. The resulting name will be in a resolved state.
623 */
624 public MemberName(Field fld) {
625 this(fld, false);
626 }
627 static {
628 // the following MemberName constructor relies on these ranges matching up
629 assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
630 }
631 @SuppressWarnings("LeakingThisInConstructor")
632 public MemberName(Field fld, boolean makeSetter) {
633 Objects.requireNonNull(fld);
634 // fill in vmtarget, vmindex while we have fld in hand:
635 MethodHandleNatives.init(this, fld);
636 assert(isResolved() && this.clazz != null);
637 this.name = fld.getName();
638 this.type = fld.getType();
639 byte refKind = this.getReferenceKind();
640 assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
641 if (makeSetter) {
642 changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind);
643 }
644 }
645 public boolean isGetter() {
646 return MethodHandleNatives.refKindIsGetter(getReferenceKind());
647 }
648 public boolean isSetter() {
649 return MethodHandleNatives.refKindIsSetter(getReferenceKind());
650 }
651
652 /** Create a name for the given class. The resulting name will be in a resolved state. */
653 public MemberName(Class<?> type) {
654 init(type.getDeclaringClass(), type.getSimpleName(), type,
655 flagsMods(IS_TYPE, type.getModifiers(), REF_NONE));
656 initResolved(true);
657 }
658
659 /**
660 * Create a name for a signature-polymorphic invoker.
661 * This is a placeholder for a signature-polymorphic instance
662 * (of MH.invokeExact, etc.) that the JVM does not reify.
663 * See comments on {@link MethodHandleNatives#linkMethod}.
664 */
665 static MemberName makeMethodHandleInvoke(String name, MethodType type) {
666 return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
667 }
668 static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
669 MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
670 mem.flags |= mods; // it's not resolved, but add these modifiers anyway
671 assert(mem.isMethodHandleInvoke()) : mem;
672 return mem;
673 }
674
675 static MemberName makeVarHandleMethodInvoke(String name, MethodType type) {
676 return makeVarHandleMethodInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
677 }
678 static MemberName makeVarHandleMethodInvoke(String name, MethodType type, int mods) {
679 MemberName mem = new MemberName(VarHandle.class, name, type, REF_invokeVirtual);
680 mem.flags |= mods; // it's not resolved, but add these modifiers anyway
681 assert(mem.isVarHandleMethodInvoke()) : mem;
682 return mem;
683 }
684
685 // bare-bones constructor; the JVM will fill it in
686 MemberName() { }
687
688 // locally useful cloner
689 @Override protected MemberName clone() {
690 try {
691 return (MemberName) super.clone();
692 } catch (CloneNotSupportedException ex) {
693 throw newInternalError(ex);
694 }
695 }
696
697 /** Get the definition of this member name.
698 * This may be in a super-class of the declaring class of this member.
699 */
700 public MemberName getDefinition() {
701 if (!isResolved()) throw new IllegalStateException("must be resolved: "+this);
702 if (isType()) return this;
703 MemberName res = this.clone();
704 res.clazz = null;
705 res.type = null;
706 res.name = null;
707 res.resolution = res;
708 res.expandFromVM();
709 assert(res.getName().equals(this.getName()));
710 return res;
711 }
712
713 @Override
714 @SuppressWarnings("deprecation")
715 public int hashCode() {
716 // Avoid autoboxing getReferenceKind(), since this is used early and will force
717 // early initialization of Byte$ByteCache
718 return Objects.hash(clazz, new Byte(getReferenceKind()), name, getType());
719 }
720
721 @Override
722 public boolean equals(Object that) {
723 return that instanceof MemberName mn && this.equals(mn);
724 }
725
726 /** Decide if two member names have exactly the same symbolic content.
727 * Does not take into account any actual class members, so even if
728 * two member names resolve to the same actual member, they may
729 * be distinct references.
730 */
731 public boolean equals(MemberName that) {
732 if (this == that) return true;
733 if (that == null) return false;
734 return this.clazz == that.clazz
735 && this.getReferenceKind() == that.getReferenceKind()
736 && Objects.equals(this.name, that.name)
737 && Objects.equals(this.getType(), that.getType());
738 }
739
740 // Construction from symbolic parts, for queries:
741 /** Create a field or type name from the given components:
742 * Declaring class, name, type, reference kind.
743 * The declaring class may be supplied as null if this is to be a bare name and type.
744 * The resulting name will in an unresolved state.
745 */
746 public MemberName(Class<?> defClass, String name, Class<?> type, byte refKind) {
747 init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
748 initResolved(false);
749 }
750 /** Create a method or constructor name from the given components:
751 * Declaring class, name, type, reference kind.
752 * It will be a constructor if and only if the name is {@code "<init>"}.
753 * The declaring class may be supplied as null if this is to be a bare name and type.
754 * The last argument is optional, a boolean which requests REF_invokeSpecial.
755 * The resulting name will in an unresolved state.
756 */
757 public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
758 int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
759 init(defClass, name, type, flagsMods(initFlags, 0, refKind));
760 initResolved(false);
761 }
762 /** Create a method, constructor, or field name from the given components:
763 * Reference kind, declaring class, name, type.
764 */
765 public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
766 int kindFlags;
767 if (MethodHandleNatives.refKindIsField(refKind)) {
768 kindFlags = IS_FIELD;
769 if (!(type instanceof Class))
770 throw newIllegalArgumentException("not a field type");
771 } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
772 kindFlags = IS_METHOD;
773 if (!(type instanceof MethodType))
774 throw newIllegalArgumentException("not a method type");
775 } else if (refKind == REF_newInvokeSpecial) {
776 kindFlags = IS_CONSTRUCTOR;
777 if (!(type instanceof MethodType) ||
778 !CONSTRUCTOR_NAME.equals(name))
779 throw newIllegalArgumentException("not a constructor type or name");
780 } else {
781 throw newIllegalArgumentException("bad reference kind "+refKind);
782 }
783 init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
784 initResolved(false);
785 }
786
787 /** Query whether this member name is resolved.
788 * A resolved member name is one for which the JVM has found
789 * a method, constructor, field, or type binding corresponding exactly to the name.
790 * (Document?)
791 */
792 public boolean isResolved() {
793 return resolution == null;
794 }
795
796 void initResolved(boolean isResolved) {
797 assert(this.resolution == null); // not initialized yet!
798 if (!isResolved)
799 this.resolution = this;
800 assert(isResolved() == isResolved);
801 }
802
803 void ensureTypeVisible(Class<?> refc) {
804 if (isInvocable()) {
805 MethodType type;
806 if (this.type instanceof MethodType mt)
807 type = mt;
808 else
809 this.type = type = getMethodType();
810 if (type.erase() == type) return;
811 if (VerifyAccess.ensureTypeVisible(type, refc)) return;
812 throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
813 } else {
814 Class<?> type;
815 if (this.type instanceof Class<?> cl)
816 type = cl;
817 else
818 this.type = type = getFieldType();
819 if (VerifyAccess.ensureTypeVisible(type, refc)) return;
820 throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
821 }
822 }
823
824
825 /** Produce a string form of this member name.
826 * For types, it is simply the type's own string (as reported by {@code toString}).
827 * For fields, it is {@code "DeclaringClass.name/type"}.
828 * For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
829 * If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
830 * If the member is unresolved, a prefix {@code "*."} is prepended.
831 */
832 @SuppressWarnings("LocalVariableHidesMemberVariable")
833 @Override
834 public String toString() {
835 if (isType())
836 return type.toString(); // class java.lang.String
837 // else it is a field, method, or constructor
838 StringBuilder buf = new StringBuilder();
839 if (getDeclaringClass() != null) {
840 buf.append(getName(clazz));
841 buf.append('.');
842 }
843 String name = this.name; // avoid expanding from VM
844 buf.append(name == null ? "*" : name);
845 Object type = this.type; // avoid expanding from VM
846 if (!isInvocable()) {
847 buf.append('/');
848 buf.append(type == null ? "*" : getName(type));
849 } else {
850 buf.append(type == null ? "(*)*" : getName(type));
851 }
852 byte refKind = getReferenceKind();
853 if (refKind != REF_NONE) {
854 buf.append('/');
855 buf.append(MethodHandleNatives.refKindName(refKind));
856 }
857 //buf.append("#").append(System.identityHashCode(this));
858 return buf.toString();
859 }
860 private static String getName(Object obj) {
861 if (obj instanceof Class<?> cl)
862 return cl.getName();
863 return String.valueOf(obj);
864 }
865
866 public IllegalAccessException makeAccessException(String message, Object from) {
867 message = message + ": " + this;
868 if (from != null) {
869 if (from == MethodHandles.publicLookup()) {
870 message += ", from public Lookup";
871 } else {
872 Module m;
873 Class<?> plc;
874 if (from instanceof MethodHandles.Lookup lookup) {
875 from = lookup.lookupClass();
876 m = lookup.lookupClass().getModule();
877 plc = lookup.previousLookupClass();
878 } else {
879 m = ((Class<?>)from).getModule();
880 plc = null;
881 }
882 message += ", from " + from + " (" + m + ")";
883 if (plc != null) {
884 message += ", previous lookup " +
885 plc.getName() + " (" + plc.getModule() + ")";
886 }
887 }
888 }
889 return new IllegalAccessException(message);
890 }
891 private String message() {
892 if (isResolved())
893 return "no access";
894 else if (isConstructor())
895 return "no such constructor";
896 else if (isMethod())
897 return "no such method";
898 else
899 return "no such field";
900 }
901 public ReflectiveOperationException makeAccessException() {
902 String message = message() + ": " + this;
903 ReflectiveOperationException ex;
904 if (isResolved() || !(resolution instanceof NoSuchMethodError ||
905 resolution instanceof NoSuchFieldError))
906 ex = new IllegalAccessException(message);
907 else if (isConstructor())
908 ex = new NoSuchMethodException(message);
909 else if (isMethod())
910 ex = new NoSuchMethodException(message);
911 else
912 ex = new NoSuchFieldException(message);
913 if (resolution instanceof Throwable res)
914 ex.initCause(res);
915 return ex;
916 }
917
918 /** Actually making a query requires an access check. */
919 /*non-public*/
920 static Factory getFactory() {
921 return Factory.INSTANCE;
922 }
923 /** A factory type for resolving member names with the help of the VM.
924 * TBD: Define access-safe public constructors for this factory.
925 */
926 /*non-public*/
927 static class Factory {
928 private Factory() { } // singleton pattern
929 static final Factory INSTANCE = new Factory();
930
931 /** Produce a resolved version of the given member.
932 * Super types are searched (for inherited members) if {@code searchSupers} is true.
933 * Access checking is performed on behalf of the given {@code lookupClass}.
934 * If lookup fails or access is not permitted, null is returned.
935 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
936 */
937 private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass, int allowedModes,
938 boolean speculativeResolve) {
939 MemberName m = ref.clone(); // JVM will side-effect the ref
940 assert(refKind == m.getReferenceKind());
941 try {
942 // There are 4 entities in play here:
943 // * LC: lookupClass
944 // * REFC: symbolic reference class (MN.clazz before resolution);
945 // * DEFC: resolved method holder (MN.clazz after resolution);
946 // * PTYPES: parameter types (MN.type)
947 //
948 // What we care about when resolving a MemberName is consistency between DEFC and PTYPES.
949 // We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM
950 // finishes the resolution, so do TA checks right after MHN.resolve() is over.
951 //
952 // All parameters passed by a caller are checked against MH type (PTYPES) on every invocation,
953 // so it is safe to call a MH from any context.
954 //
955 // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't
956 // participate in method selection.
957 m = MethodHandleNatives.resolve(m, lookupClass, allowedModes, speculativeResolve);
958 if (m == null && speculativeResolve) {
959 return null;
960 }
961 m.ensureTypeVisible(m.getDeclaringClass());
962 m.resolution = null;
963 } catch (ClassNotFoundException | LinkageError ex) {
964 // JVM reports that the "bytecode behavior" would get an error
965 assert(!m.isResolved());
966 m.resolution = ex;
967 return m;
968 }
969 assert(m.referenceKindIsConsistent());
970 m.initResolved(true);
971 assert(m.vminfoIsConsistent());
972 return m;
973 }
974 /** Produce a resolved version of the given member.
975 * Super types are searched (for inherited members) if {@code searchSupers} is true.
976 * Access checking is performed on behalf of the given {@code lookupClass}.
977 * If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown.
978 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
979 */
980 public <NoSuchMemberException extends ReflectiveOperationException>
981 MemberName resolveOrFail(byte refKind, MemberName m,
982 Class<?> lookupClass, int allowedModes,
983 Class<NoSuchMemberException> nsmClass)
984 throws IllegalAccessException, NoSuchMemberException {
985 assert lookupClass != null || allowedModes == LM_TRUSTED;
986 MemberName result = resolve(refKind, m, lookupClass, allowedModes, false);
987 if (result.isResolved())
988 return result;
989 ReflectiveOperationException ex = result.makeAccessException();
990 if (ex instanceof IllegalAccessException iae) throw iae;
991 throw nsmClass.cast(ex);
992 }
993 /** Produce a resolved version of the given member.
994 * Super types are searched (for inherited members) if {@code searchSupers} is true.
995 * Access checking is performed on behalf of the given {@code lookupClass}.
996 * If lookup fails or access is not permitted, return null.
997 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
998 */
999 public MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass, int allowedModes) {
1000 assert lookupClass != null || allowedModes == LM_TRUSTED;
1001 MemberName result = resolve(refKind, m, lookupClass, allowedModes, true);
1002 if (result != null && result.isResolved())
1003 return result;
1004 return null;
1005 }
1006 }
1007 }