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
417 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
418 public boolean isBridge() {
419 return allFlagsSet(IS_METHOD | BRIDGE);
420 }
421 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
422 public boolean isVarargs() {
423 return allFlagsSet(VARARGS) && isInvocable();
424 }
425 /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
426 public boolean isSynthetic() {
427 return allFlagsSet(SYNTHETIC);
428 }
429
430 static final String CONSTRUCTOR_NAME = "<init>";
431
432 // modifiers exported by the JVM:
433 static final int RECOGNIZED_MODIFIERS = 0xFFFF;
434
435 // private flags, not part of RECOGNIZED_MODIFIERS:
436 static final int
437 IS_METHOD = MN_IS_METHOD, // method (not constructor)
438 IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
439 IS_FIELD = MN_IS_FIELD, // field
440 IS_TYPE = MN_IS_TYPE, // nested type
441 CALLER_SENSITIVE = MN_CALLER_SENSITIVE, // @CallerSensitive annotation detected
442 TRUSTED_FINAL = MN_TRUSTED_FINAL; // trusted final field
443
444 static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
445 static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
446 static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
447
448 /** Utility method to query whether this member is a method or constructor. */
449 public boolean isInvocable() {
450 return anyFlagSet(IS_INVOCABLE);
451 }
452 /** Query whether this member is a method. */
453 public boolean isMethod() {
454 return allFlagsSet(IS_METHOD);
455 }
456 /** Query whether this member is a constructor. */
457 public boolean isConstructor() {
458 return allFlagsSet(IS_CONSTRUCTOR);
459 }
460 /** Query whether this member is a field. */
461 public boolean isField() {
462 return allFlagsSet(IS_FIELD);
463 }
464 /** Query whether this member is a type. */
465 public boolean isType() {
466 return allFlagsSet(IS_TYPE);
467 }
468 /** Utility method to query whether this member is neither public, private, nor protected. */
469 public boolean isPackage() {
470 return !anyFlagSet(ALL_ACCESS);
471 }
472 /** Query whether this member has a CallerSensitive annotation. */
473 public boolean isCallerSensitive() {
474 return allFlagsSet(CALLER_SENSITIVE);
475 }
476 /** Query whether this member is a trusted final field. */
477 public boolean isTrustedFinalField() {
478 return allFlagsSet(TRUSTED_FINAL | IS_FIELD);
479 }
480
481 /**
482 * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
483 */
484 public boolean refersTo(Class<?> declc, String n) {
485 return clazz == declc && getName().equals(n);
486 }
487
488 /** Initialize a query. It is not resolved. */
489 private void init(Class<?> defClass, String name, Object type, int flags) {
490 // defining class is allowed to be null (for a naked name/type pair)
491 //name.toString(); // null check
492 //type.equals(type); // null check
493 // fill in fields:
494 this.clazz = defClass;
495 this.name = name;
496 this.type = type;
497 this.flags = flags;
498 assert(anyFlagSet(ALL_KINDS) && this.resolution == null); // nobody should have touched this yet
499 //assert(referenceKindIsConsistent()); // do this after resolution
500 }
501
502 /**
503 * Calls down to the VM to fill in the fields. This method is
504 * synchronized to avoid racing calls.
505 */
506 private void expandFromVM() {
507 if (type != null) {
508 return;
509 }
510 if (!isResolved()) {
511 return;
512 }
513 MethodHandleNatives.expand(this);
514 }
515
516 // Capturing information from the Core Reflection API:
517 private static int flagsMods(int flags, int mods, byte refKind) {
518 assert((flags & RECOGNIZED_MODIFIERS) == 0
519 && (mods & ~RECOGNIZED_MODIFIERS) == 0
520 && (refKind & ~MN_REFERENCE_KIND_MASK) == 0);
521 return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
522 }
523 /** Create a name for the given reflected method. The resulting name will be in a resolved state. */
524 public MemberName(Method m) {
525 this(m, false);
526 }
527 @SuppressWarnings("LeakingThisInConstructor")
528 public MemberName(Method m, boolean wantSpecial) {
529 Objects.requireNonNull(m);
530 // fill in vmtarget, vmindex while we have m in hand:
531 MethodHandleNatives.init(this, m);
532 if (clazz == null) { // MHN.init failed
533 if (m.getDeclaringClass() == MethodHandle.class &&
534 isMethodHandleInvokeName(m.getName())) {
535 // The JVM did not reify this signature-polymorphic instance.
536 // Need a special case here.
537 // See comments on MethodHandleNatives.linkMethod.
538 MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
539 int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
540 init(MethodHandle.class, m.getName(), type, flags);
541 if (isMethodHandleInvoke())
542 return;
543 }
544 if (m.getDeclaringClass() == VarHandle.class &&
545 isVarHandleMethodInvokeName(m.getName())) {
546 // The JVM did not reify this signature-polymorphic instance.
547 // Need a special case here.
548 // See comments on MethodHandleNatives.linkMethod.
549 MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
550 int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
551 init(VarHandle.class, m.getName(), type, flags);
552 if (isVarHandleMethodInvoke())
553 return;
554 }
555 throw new LinkageError(m.toString());
556 }
557 assert(isResolved());
558 this.name = m.getName();
559 if (this.type == null)
560 this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
561 if (wantSpecial) {
562 if (isAbstract())
563 throw new AbstractMethodError(this.toString());
564 if (getReferenceKind() == REF_invokeVirtual)
565 changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
566 else if (getReferenceKind() == REF_invokeInterface)
567 // invokeSpecial on a default method
568 changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
569 }
570 }
571 public MemberName asSpecial() {
572 switch (getReferenceKind()) {
573 case REF_invokeSpecial: return this;
574 case REF_invokeVirtual: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
575 case REF_invokeInterface: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
576 case REF_newInvokeSpecial: return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
577 }
578 throw new IllegalArgumentException(this.toString());
579 }
580 /** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind.
581 * In that case it must already be REF_invokeSpecial.
582 */
583 public MemberName asConstructor() {
584 switch (getReferenceKind()) {
585 case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
586 case REF_newInvokeSpecial: return this;
587 }
588 throw new IllegalArgumentException(this.toString());
589 }
590 /** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind
591 * REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface.
592 * The end result is to get a fully virtualized version of the MN.
593 * (Note that resolving in the JVM will sometimes devirtualize, changing
594 * REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface
595 * in some corner cases to either of the previous two; this transform
596 * undoes that change under the assumption that it occurred.)
597 */
598 public MemberName asNormalOriginal() {
599 byte refKind = getReferenceKind();
600 byte newRefKind = switch (refKind) {
601 case REF_invokeInterface,
602 REF_invokeVirtual,
603 REF_invokeSpecial -> clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
604 default -> refKind;
605 };
606 if (newRefKind == refKind)
607 return this;
608 MemberName result = clone().changeReferenceKind(newRefKind, refKind);
609 assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
610 return result;
611 }
612 /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
613 @SuppressWarnings("LeakingThisInConstructor")
614 public MemberName(Constructor<?> ctor) {
615 Objects.requireNonNull(ctor);
616 // fill in vmtarget, vmindex while we have ctor in hand:
617 MethodHandleNatives.init(this, ctor);
618 assert(isResolved() && this.clazz != null);
619 this.name = CONSTRUCTOR_NAME;
620 if (this.type == null)
621 this.type = new Object[] { void.class, ctor.getParameterTypes() };
622 }
623 /** Create a name for the given reflected field. The resulting name will be in a resolved state.
624 */
625 public MemberName(Field fld) {
626 this(fld, false);
627 }
628 static {
629 // the following MemberName constructor relies on these ranges matching up
630 assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
631 }
632 @SuppressWarnings("LeakingThisInConstructor")
633 public MemberName(Field fld, boolean makeSetter) {
634 Objects.requireNonNull(fld);
635 // fill in vmtarget, vmindex while we have fld in hand:
636 MethodHandleNatives.init(this, fld);
637 assert(isResolved() && this.clazz != null);
638 this.name = fld.getName();
639 this.type = fld.getType();
640 byte refKind = this.getReferenceKind();
641 assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
642 if (makeSetter) {
643 changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind);
644 }
645 }
646 public boolean isGetter() {
647 return MethodHandleNatives.refKindIsGetter(getReferenceKind());
648 }
649 public boolean isSetter() {
650 return MethodHandleNatives.refKindIsSetter(getReferenceKind());
651 }
652
653 /** Create a name for the given class. The resulting name will be in a resolved state. */
654 public MemberName(Class<?> type) {
655 init(type.getDeclaringClass(), type.getSimpleName(), type,
656 flagsMods(IS_TYPE, type.getModifiers(), REF_NONE));
657 initResolved(true);
658 }
659
660 /**
661 * Create a name for a signature-polymorphic invoker.
662 * This is a placeholder for a signature-polymorphic instance
663 * (of MH.invokeExact, etc.) that the JVM does not reify.
664 * See comments on {@link MethodHandleNatives#linkMethod}.
665 */
666 static MemberName makeMethodHandleInvoke(String name, MethodType type) {
667 return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
668 }
669 static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
670 MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
671 mem.flags |= mods; // it's not resolved, but add these modifiers anyway
672 assert(mem.isMethodHandleInvoke()) : mem;
673 return mem;
674 }
675
676 static MemberName makeVarHandleMethodInvoke(String name, MethodType type) {
677 return makeVarHandleMethodInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
678 }
679 static MemberName makeVarHandleMethodInvoke(String name, MethodType type, int mods) {
680 MemberName mem = new MemberName(VarHandle.class, name, type, REF_invokeVirtual);
681 mem.flags |= mods; // it's not resolved, but add these modifiers anyway
682 assert(mem.isVarHandleMethodInvoke()) : mem;
683 return mem;
684 }
685
686 // bare-bones constructor; the JVM will fill it in
687 MemberName() { }
688
689 // locally useful cloner
690 @Override protected MemberName clone() {
691 try {
692 return (MemberName) super.clone();
693 } catch (CloneNotSupportedException ex) {
694 throw newInternalError(ex);
695 }
696 }
697
698 /** Get the definition of this member name.
699 * This may be in a super-class of the declaring class of this member.
700 */
701 public MemberName getDefinition() {
702 if (!isResolved()) throw new IllegalStateException("must be resolved: "+this);
703 if (isType()) return this;
704 MemberName res = this.clone();
705 res.clazz = null;
706 res.type = null;
707 res.name = null;
708 res.resolution = res;
709 res.expandFromVM();
710 assert(res.getName().equals(this.getName()));
711 return res;
712 }
713
714 @Override
715 @SuppressWarnings("deprecation")
716 public int hashCode() {
717 // Avoid autoboxing getReferenceKind(), since this is used early and will force
718 // early initialization of Byte$ByteCache
719 return Objects.hash(clazz, new Byte(getReferenceKind()), name, getType());
720 }
721
722 @Override
723 public boolean equals(Object that) {
724 return that instanceof MemberName mn && this.equals(mn);
725 }
726
727 /** Decide if two member names have exactly the same symbolic content.
728 * Does not take into account any actual class members, so even if
729 * two member names resolve to the same actual member, they may
730 * be distinct references.
731 */
732 public boolean equals(MemberName that) {
733 if (this == that) return true;
734 if (that == null) return false;
735 return this.clazz == that.clazz
736 && this.getReferenceKind() == that.getReferenceKind()
737 && Objects.equals(this.name, that.name)
738 && Objects.equals(this.getType(), that.getType());
739 }
740
741 // Construction from symbolic parts, for queries:
742 /** Create a field or type name from the given components:
743 * Declaring class, name, type, reference kind.
744 * The declaring class may be supplied as null if this is to be a bare name and type.
745 * The resulting name will in an unresolved state.
746 */
747 public MemberName(Class<?> defClass, String name, Class<?> type, byte refKind) {
748 init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
749 initResolved(false);
750 }
751 /** Create a method or constructor name from the given components:
752 * Declaring class, name, type, reference kind.
753 * It will be a constructor if and only if the name is {@code "<init>"}.
754 * The declaring class may be supplied as null if this is to be a bare name and type.
755 * The last argument is optional, a boolean which requests REF_invokeSpecial.
756 * The resulting name will in an unresolved state.
757 */
758 public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
759 int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
760 init(defClass, name, type, flagsMods(initFlags, 0, refKind));
761 initResolved(false);
762 }
763 /** Create a method, constructor, or field name from the given components:
764 * Reference kind, declaring class, name, type.
765 */
766 public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
767 int kindFlags;
768 if (MethodHandleNatives.refKindIsField(refKind)) {
769 kindFlags = IS_FIELD;
770 if (!(type instanceof Class))
771 throw newIllegalArgumentException("not a field type");
772 } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
773 kindFlags = IS_METHOD;
774 if (!(type instanceof MethodType))
775 throw newIllegalArgumentException("not a method type");
776 } else if (refKind == REF_newInvokeSpecial) {
777 kindFlags = IS_CONSTRUCTOR;
778 if (!(type instanceof MethodType) ||
779 !CONSTRUCTOR_NAME.equals(name))
780 throw newIllegalArgumentException("not a constructor type or name");
781 } else {
782 throw newIllegalArgumentException("bad reference kind "+refKind);
783 }
784 init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
785 initResolved(false);
786 }
787
788 /** Query whether this member name is resolved.
789 * A resolved member name is one for which the JVM has found
790 * a method, constructor, field, or type binding corresponding exactly to the name.
791 * (Document?)
792 */
793 public boolean isResolved() {
794 return resolution == null;
795 }
796
797 void initResolved(boolean isResolved) {
798 assert(this.resolution == null); // not initialized yet!
799 if (!isResolved)
800 this.resolution = this;
801 assert(isResolved() == isResolved);
802 }
803
804 void ensureTypeVisible(Class<?> refc) {
805 if (isInvocable()) {
806 MethodType type;
807 if (this.type instanceof MethodType mt)
808 type = mt;
809 else
810 this.type = type = getMethodType();
811 if (type.erase() == type) return;
812 if (VerifyAccess.ensureTypeVisible(type, refc)) return;
813 throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
814 } else {
815 Class<?> type;
816 if (this.type instanceof Class<?> cl)
817 type = cl;
818 else
819 this.type = type = getFieldType();
820 if (VerifyAccess.ensureTypeVisible(type, refc)) return;
821 throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
822 }
823 }
824
825
826 /** Produce a string form of this member name.
827 * For types, it is simply the type's own string (as reported by {@code toString}).
828 * For fields, it is {@code "DeclaringClass.name/type"}.
829 * For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
830 * If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
831 * If the member is unresolved, a prefix {@code "*."} is prepended.
832 */
833 @SuppressWarnings("LocalVariableHidesMemberVariable")
834 @Override
835 public String toString() {
836 if (isType())
837 return type.toString(); // class java.lang.String
838 // else it is a field, method, or constructor
839 StringBuilder buf = new StringBuilder();
840 if (getDeclaringClass() != null) {
841 buf.append(getName(clazz));
842 buf.append('.');
843 }
844 String name = this.name; // avoid expanding from VM
845 buf.append(name == null ? "*" : name);
846 Object type = this.type; // avoid expanding from VM
847 if (!isInvocable()) {
848 buf.append('/');
849 buf.append(type == null ? "*" : getName(type));
850 } else {
851 buf.append(type == null ? "(*)*" : getName(type));
852 }
853 byte refKind = getReferenceKind();
854 if (refKind != REF_NONE) {
855 buf.append('/');
856 buf.append(MethodHandleNatives.refKindName(refKind));
857 }
858 //buf.append("#").append(System.identityHashCode(this));
859 return buf.toString();
860 }
861 private static String getName(Object obj) {
862 if (obj instanceof Class<?> cl)
863 return cl.getName();
864 return String.valueOf(obj);
865 }
866
867 public IllegalAccessException makeAccessException(String message, Object from) {
868 message = message + ": " + this;
869 if (from != null) {
870 if (from == MethodHandles.publicLookup()) {
871 message += ", from public Lookup";
872 } else {
873 Module m;
874 Class<?> plc;
875 if (from instanceof MethodHandles.Lookup lookup) {
876 from = lookup.lookupClass();
877 m = lookup.lookupClass().getModule();
878 plc = lookup.previousLookupClass();
879 } else {
880 m = ((Class<?>)from).getModule();
881 plc = null;
882 }
883 message += ", from " + from + " (" + m + ")";
884 if (plc != null) {
885 message += ", previous lookup " +
886 plc.getName() + " (" + plc.getModule() + ")";
887 }
888 }
889 }
890 return new IllegalAccessException(message);
891 }
892 private String message() {
893 if (isResolved())
894 return "no access";
895 else if (isConstructor())
896 return "no such constructor";
897 else if (isMethod())
898 return "no such method";
899 else
900 return "no such field";
901 }
902 public ReflectiveOperationException makeAccessException() {
903 String message = message() + ": " + this;
904 ReflectiveOperationException ex;
905 if (isResolved() || !(resolution instanceof NoSuchMethodError ||
906 resolution instanceof NoSuchFieldError))
907 ex = new IllegalAccessException(message);
908 else if (isConstructor())
909 ex = new NoSuchMethodException(message);
910 else if (isMethod())
911 ex = new NoSuchMethodException(message);
912 else
913 ex = new NoSuchFieldException(message);
914 if (resolution instanceof Throwable res)
915 ex.initCause(res);
916 return ex;
917 }
918
919 /** Actually making a query requires an access check. */
920 /*non-public*/
921 static Factory getFactory() {
922 return Factory.INSTANCE;
923 }
924 /** A factory type for resolving member names with the help of the VM.
925 * TBD: Define access-safe public constructors for this factory.
926 */
927 /*non-public*/
928 static class Factory {
929 private Factory() { } // singleton pattern
930 static final Factory INSTANCE = new Factory();
931
932 /** Produce a resolved version of the given member.
933 * Super types are searched (for inherited members) if {@code searchSupers} is true.
934 * Access checking is performed on behalf of the given {@code lookupClass}.
935 * If lookup fails or access is not permitted, null is returned.
936 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
937 */
938 private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass, int allowedModes,
939 boolean speculativeResolve) {
940 MemberName m = ref.clone(); // JVM will side-effect the ref
941 assert(refKind == m.getReferenceKind());
942 try {
943 // There are 4 entities in play here:
944 // * LC: lookupClass
945 // * REFC: symbolic reference class (MN.clazz before resolution);
946 // * DEFC: resolved method holder (MN.clazz after resolution);
947 // * PTYPES: parameter types (MN.type)
948 //
949 // What we care about when resolving a MemberName is consistency between DEFC and PTYPES.
950 // We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM
951 // finishes the resolution, so do TA checks right after MHN.resolve() is over.
952 //
953 // All parameters passed by a caller are checked against MH type (PTYPES) on every invocation,
954 // so it is safe to call a MH from any context.
955 //
956 // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't
957 // participate in method selection.
958 m = MethodHandleNatives.resolve(m, lookupClass, allowedModes, speculativeResolve);
959 if (m == null && speculativeResolve) {
960 return null;
961 }
962 m.ensureTypeVisible(m.getDeclaringClass());
963 m.resolution = null;
964 } catch (ClassNotFoundException | LinkageError ex) {
965 // JVM reports that the "bytecode behavior" would get an error
966 assert(!m.isResolved());
967 m.resolution = ex;
968 return m;
969 }
970 assert(m.referenceKindIsConsistent());
971 m.initResolved(true);
972 assert(m.vminfoIsConsistent());
973 return m;
974 }
975 /** Produce a resolved version of the given member.
976 * Super types are searched (for inherited members) if {@code searchSupers} is true.
977 * Access checking is performed on behalf of the given {@code lookupClass}.
978 * If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown.
979 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
980 */
981 public <NoSuchMemberException extends ReflectiveOperationException>
982 MemberName resolveOrFail(byte refKind, MemberName m,
983 Class<?> lookupClass, int allowedModes,
984 Class<NoSuchMemberException> nsmClass)
985 throws IllegalAccessException, NoSuchMemberException {
986 assert lookupClass != null || allowedModes == LM_TRUSTED;
987 MemberName result = resolve(refKind, m, lookupClass, allowedModes, false);
988 if (result.isResolved())
989 return result;
990 ReflectiveOperationException ex = result.makeAccessException();
991 if (ex instanceof IllegalAccessException iae) throw iae;
992 throw nsmClass.cast(ex);
993 }
994 /** Produce a resolved version of the given member.
995 * Super types are searched (for inherited members) if {@code searchSupers} is true.
996 * Access checking is performed on behalf of the given {@code lookupClass}.
997 * If lookup fails or access is not permitted, return null.
998 * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
999 */
1000 public MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass, int allowedModes) {
1001 assert lookupClass != null || allowedModes == LM_TRUSTED;
1002 MemberName result = resolve(refKind, m, lookupClass, allowedModes, true);
1003 if (result != null && result.isResolved())
1004 return result;
1005 return null;
1006 }
1007 }
1008 }
--- EOF ---