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