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