MemberName.java revision 10471:d56a71cf0b9e
118334Speter/*
290075Sobrien * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3117395Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
418334Speter *
590075Sobrien * This code is free software; you can redistribute it and/or modify it
618334Speter * under the terms of the GNU General Public License version 2 only, as
790075Sobrien * published by the Free Software Foundation.  Oracle designates this
890075Sobrien * particular file as subject to the "Classpath" exception as provided
990075Sobrien * by Oracle in the LICENSE file that accompanied this code.
1090075Sobrien *
1118334Speter * This code is distributed in the hope that it will be useful, but WITHOUT
1290075Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1390075Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1490075Sobrien * version 2 for more details (a copy is included in the LICENSE file that
1590075Sobrien * accompanied this code).
1618334Speter *
1718334Speter * You should have received a copy of the GNU General Public License version
1890075Sobrien * 2 along with this work; if not, write to the Free Software Foundation,
1990075Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2090075Sobrien *
2118334Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2218334Speter * or visit www.oracle.com if you need additional information or have any
2350397Sobrien * questions.
2450397Sobrien */
2550397Sobrien
2650397Sobrienpackage java.lang.invoke;
2750397Sobrien
2890075Sobrienimport sun.invoke.util.BytecodeDescriptor;
2990075Sobrienimport sun.invoke.util.VerifyAccess;
3050397Sobrien
3150397Sobrienimport java.lang.reflect.Constructor;
3250397Sobrienimport java.lang.reflect.Field;
3390075Sobrienimport java.lang.reflect.Method;
3490075Sobrienimport java.lang.reflect.Member;
3590075Sobrienimport java.lang.reflect.Modifier;
36117395Skanimport java.util.ArrayList;
37117395Skanimport java.util.Arrays;
38117395Skanimport java.util.Collections;
3918334Speterimport java.util.Iterator;
4090075Sobrienimport java.util.List;
4190075Sobrienimport static java.lang.invoke.MethodHandleNatives.Constants.*;
4252284Sobrienimport static java.lang.invoke.MethodHandleStatics.*;
4352284Sobrienimport java.util.Objects;
4418334Speter
4518334Speter/**
4618334Speter * A {@code MemberName} is a compact symbolic datum which fully characterizes
4718334Speter * a method or field reference.
4818334Speter * A member name refers to a field, method, constructor, or member type.
4918334Speter * Every member name has a simple name (a string) and a type (either a Class or MethodType).
5018334Speter * A member name may also have a non-null declaring class, or it may be simply
5118334Speter * a naked name/type pair.
52107590Sobrien * A member name may also have non-zero modifier flags.
5318334Speter * Finally, a member name may be either resolved or unresolved.
5490075Sobrien * If it is resolved, the existence of the named
5518334Speter * <p>
56107590Sobrien * Whether resolved or not, a member name provides no access rights or
5718334Speter * invocation capability to its possessor.  It is merely a compact
5818334Speter * representation of all symbolic information necessary to link to
5918334Speter * and properly use the named member.
6090075Sobrien * <p>
6190075Sobrien * When resolved, a member name's internal implementation may include references to JVM metadata.
6290075Sobrien * This representation is stateless and only descriptive.
6390075Sobrien * It provides no private information and no capability to use the member.
6490075Sobrien * <p>
6590075Sobrien * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information
6690075Sobrien * about the internals of a method (except its bytecodes) and also
6790075Sobrien * allows invocation.  A MemberName is much lighter than a Method,
6852284Sobrien * since it contains about 7 fields to the 16 of Method (plus its sub-arrays),
6952284Sobrien * and those seven fields omit much of the information in Method.
7018334Speter * @author jrose
7118334Speter */
7218334Speter/*non-public*/ final class MemberName implements Member, Cloneable {
7318334Speter    private Class<?> clazz;       // class in which the method is defined
7418334Speter    private String   name;        // may be null if not yet materialized
7518334Speter    private Object   type;        // may be null if not yet materialized
7618334Speter    private int      flags;       // modifier bits; see reflect.Modifier
7718334Speter    //@Injected JVM_Method* vmtarget;
7818334Speter    //@Injected int         vmindex;
7918334Speter    private Object   resolution;  // if null, this guy is resolved
8018334Speter
8118334Speter    /** Return the declaring class of this member.
8218334Speter     *  In the case of a bare name and type, the declaring class will be null.
8318334Speter     */
8450397Sobrien    public Class<?> getDeclaringClass() {
8518334Speter        return clazz;
8618334Speter    }
8790075Sobrien
8890075Sobrien    /** Utility method producing the class loader of the declaring class. */
8990075Sobrien    public ClassLoader getClassLoader() {
9090075Sobrien        return clazz.getClassLoader();
9118334Speter    }
9218334Speter
9318334Speter    /** Return the simple name of this member.
9418334Speter     *  For a type, it is the same as {@link Class#getSimpleName}.
9518334Speter     *  For a method or field, it is the simple name of the member.
9618334Speter     *  For a constructor, it is always {@code "&lt;init&gt;"}.
97117395Skan     */
9818334Speter    public String getName() {
9918334Speter        if (name == null) {
10018334Speter            expandFromVM();
10118334Speter            if (name == null) {
10218334Speter                return null;
10318334Speter            }
10418334Speter        }
10518334Speter        return name;
10618334Speter    }
10718334Speter
10818334Speter    public MethodType getMethodOrFieldType() {
10918334Speter        if (isInvocable())
11018334Speter            return getMethodType();
11118334Speter        if (isGetter())
11218334Speter            return MethodType.methodType(getFieldType());
11318334Speter        if (isSetter())
11418334Speter            return MethodType.methodType(void.class, getFieldType());
11518334Speter        throw new InternalError("not a method or field: "+this);
11618334Speter    }
11718334Speter
11818334Speter    /** Return the declared type of this member, which
11918334Speter     *  must be a method or constructor.
12018334Speter     */
12118334Speter    public MethodType getMethodType() {
12218334Speter        if (type == null) {
12318334Speter            expandFromVM();
12418334Speter            if (type == null) {
12518334Speter                return null;
12618334Speter            }
12790075Sobrien        }
12890075Sobrien        if (!isInvocable()) {
12990075Sobrien            throw newIllegalArgumentException("not invocable, no method type");
13018334Speter        }
13118334Speter
132117395Skan        {
13318334Speter            // Get a snapshot of type which doesn't get changed by racing threads.
13418334Speter            final Object type = this.type;
13518334Speter            if (type instanceof MethodType) {
13618334Speter                return (MethodType) type;
13718334Speter            }
13818334Speter        }
13918334Speter
14018334Speter        // type is not a MethodType yet.  Convert it thread-safely.
14190075Sobrien        synchronized (this) {
14290075Sobrien            if (type instanceof String) {
14390075Sobrien                String sig = (String) type;
14490075Sobrien                MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
14590075Sobrien                type = res;
14690075Sobrien            } else if (type instanceof Object[]) {
14790075Sobrien                Object[] typeInfo = (Object[]) type;
14818334Speter                Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
14918334Speter                Class<?> rtype = (Class<?>) typeInfo[0];
15018334Speter                MethodType res = MethodType.methodType(rtype, ptypes);
15118334Speter                type = res;
15218334Speter            }
15318334Speter            // Make sure type is a MethodType for racing threads.
15418334Speter            assert type instanceof MethodType : "bad method type " + type;
15590075Sobrien        }
15690075Sobrien        return (MethodType) type;
15752284Sobrien    }
15890075Sobrien
15990075Sobrien    /** Return the actual type under which this method or constructor must be invoked.
16090075Sobrien     *  For non-static methods or constructors, this is the type with a leading parameter,
16190075Sobrien     *  a reference to declaring class.  For static methods, it is the same as the declared type.
16290075Sobrien     */
16390075Sobrien    public MethodType getInvocationType() {
16490075Sobrien        MethodType itype = getMethodOrFieldType();
16590075Sobrien        if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
16690075Sobrien            return itype.changeReturnType(clazz);
16790075Sobrien        if (!isStatic())
16890075Sobrien            return itype.insertParameterTypes(0, clazz);
16990075Sobrien        return itype;
17090075Sobrien    }
17190075Sobrien
17290075Sobrien    /** Utility method producing the parameter types of the method type. */
17390075Sobrien    public Class<?>[] getParameterTypes() {
17490075Sobrien        return getMethodType().parameterArray();
17590075Sobrien    }
17690075Sobrien
17790075Sobrien    /** Utility method producing the return type of the method type. */
17890075Sobrien    public Class<?> getReturnType() {
17990075Sobrien        return getMethodType().returnType();
18090075Sobrien    }
18190075Sobrien
18290075Sobrien    /** Return the declared type of this member, which
18390075Sobrien     *  must be a field or type.
18490075Sobrien     *  If it is a type member, that type itself is returned.
18590075Sobrien     */
18690075Sobrien    public Class<?> getFieldType() {
18790075Sobrien        if (type == null) {
18890075Sobrien            expandFromVM();
18996263Sobrien            if (type == null) {
19096263Sobrien                return null;
19190075Sobrien            }
19290075Sobrien        }
19390075Sobrien        if (isInvocable()) {
19490075Sobrien            throw newIllegalArgumentException("not a field or nested class, no simple type");
19590075Sobrien        }
19690075Sobrien
19790075Sobrien        {
19890075Sobrien            // Get a snapshot of type which doesn't get changed by racing threads.
19990075Sobrien            final Object type = this.type;
20090075Sobrien            if (type instanceof Class<?>) {
20190075Sobrien                return (Class<?>) type;
20290075Sobrien            }
20390075Sobrien        }
20490075Sobrien
20590075Sobrien        // type is not a Class yet.  Convert it thread-safely.
20690075Sobrien        synchronized (this) {
20790075Sobrien            if (type instanceof String) {
20890075Sobrien                String sig = (String) type;
20990075Sobrien                MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
21090075Sobrien                Class<?> res = mtype.returnType();
21190075Sobrien                type = res;
21290075Sobrien            }
21390075Sobrien            // Make sure type is a Class for racing threads.
21490075Sobrien            assert type instanceof Class<?> : "bad field type " + type;
21590075Sobrien        }
21690075Sobrien        return (Class<?>) type;
21790075Sobrien    }
21890075Sobrien
21990075Sobrien    /** Utility method to produce either the method type or field type of this member. */
22090075Sobrien    public Object getType() {
22190075Sobrien        return (isInvocable() ? getMethodType() : getFieldType());
22290075Sobrien    }
22390075Sobrien
22490075Sobrien    /** Utility method to produce the signature of this member,
22590075Sobrien     *  used within the class file format to describe its type.
22690075Sobrien     */
22790075Sobrien    public String getSignature() {
22890075Sobrien        if (type == null) {
22990075Sobrien            expandFromVM();
23090075Sobrien            if (type == null) {
231117395Skan                return null;
23290075Sobrien            }
23390075Sobrien        }
23490075Sobrien        if (isInvocable())
23590075Sobrien            return BytecodeDescriptor.unparse(getMethodType());
23652284Sobrien        else
23718334Speter            return BytecodeDescriptor.unparse(getFieldType());
23818334Speter    }
23918334Speter
24018334Speter    /** Return the modifier flags of this member.
24118334Speter     *  @see java.lang.reflect.Modifier
24218334Speter     */
24318334Speter    public int getModifiers() {
24418334Speter        return (flags & RECOGNIZED_MODIFIERS);
24518334Speter    }
24618334Speter
24718334Speter    /** Return the reference kind of this member, or zero if none.
24818334Speter     */
24918334Speter    public byte getReferenceKind() {
25018334Speter        return (byte) ((flags >>> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK);
25118334Speter    }
25218334Speter    private boolean referenceKindIsConsistent() {
25318334Speter        byte refKind = getReferenceKind();
25490075Sobrien        if (refKind == REF_NONE)  return isType();
25518334Speter        if (isField()) {
25618334Speter            assert(staticIsConsistent());
25718334Speter            assert(MethodHandleNatives.refKindIsField(refKind));
25818334Speter        } else if (isConstructor()) {
25918334Speter            assert(refKind == REF_newInvokeSpecial || refKind == REF_invokeSpecial);
26018334Speter        } else if (isMethod()) {
26190075Sobrien            assert(staticIsConsistent());
26290075Sobrien            assert(MethodHandleNatives.refKindIsMethod(refKind));
26318334Speter            if (clazz.isInterface())
26418334Speter                assert(refKind == REF_invokeInterface ||
26518334Speter                       refKind == REF_invokeStatic    ||
26618334Speter                       refKind == REF_invokeSpecial   ||
26718334Speter                       refKind == REF_invokeVirtual && isObjectPublicMethod());
26890075Sobrien        } else {
26918334Speter            assert(false);
27090075Sobrien        }
27190075Sobrien        return true;
27218334Speter    }
27318334Speter    private boolean isObjectPublicMethod() {
27418334Speter        if (clazz == Object.class)  return true;
27518334Speter        MethodType mtype = getMethodType();
27618334Speter        if (name.equals("toString") && mtype.returnType() == String.class && mtype.parameterCount() == 0)
27718334Speter            return true;
27818334Speter        if (name.equals("hashCode") && mtype.returnType() == int.class && mtype.parameterCount() == 0)
27918334Speter            return true;
28018334Speter        if (name.equals("equals") && mtype.returnType() == boolean.class && mtype.parameterCount() == 1 && mtype.parameterType(0) == Object.class)
28118334Speter            return true;
28290075Sobrien        return false;
28390075Sobrien    }
28490075Sobrien    /*non-public*/ boolean referenceKindIsConsistentWith(int originalRefKind) {
28590075Sobrien        int refKind = getReferenceKind();
28690075Sobrien        if (refKind == originalRefKind)  return true;
28718334Speter        switch (originalRefKind) {
28818334Speter        case REF_invokeInterface:
28990075Sobrien            // Looking up an interface method, can get (e.g.) Object.hashCode
29090075Sobrien            assert(refKind == REF_invokeVirtual ||
29190075Sobrien                   refKind == REF_invokeSpecial) : this;
29290075Sobrien            return true;
29390075Sobrien        case REF_invokeVirtual:
29418334Speter        case REF_newInvokeSpecial:
29590075Sobrien            // Looked up a virtual, can get (e.g.) final String.hashCode.
29690075Sobrien            assert(refKind == REF_invokeSpecial) : this;
29790075Sobrien            return true;
29890075Sobrien        }
29990075Sobrien        assert(false) : this+" != "+MethodHandleNatives.refKindName((byte)originalRefKind);
30090075Sobrien        return true;
30190075Sobrien    }
30290075Sobrien    private boolean staticIsConsistent() {
30318334Speter        byte refKind = getReferenceKind();
30490075Sobrien        return MethodHandleNatives.refKindIsStatic(refKind) == isStatic() || getModifiers() == 0;
30518334Speter    }
30690075Sobrien    private boolean vminfoIsConsistent() {
30718334Speter        byte refKind = getReferenceKind();
30818334Speter        assert(isResolved());  // else don't call
30918334Speter        Object vminfo = MethodHandleNatives.getMemberVMInfo(this);
31018334Speter        assert(vminfo instanceof Object[]);
31118334Speter        long vmindex = (Long) ((Object[])vminfo)[0];
31218334Speter        Object vmtarget = ((Object[])vminfo)[1];
31318334Speter        if (MethodHandleNatives.refKindIsField(refKind)) {
31418334Speter            assert(vmindex >= 0) : vmindex + ":" + this;
31518334Speter            assert(vmtarget instanceof Class);
31618334Speter        } else {
31718334Speter            if (MethodHandleNatives.refKindDoesDispatch(refKind))
31818334Speter                assert(vmindex >= 0) : vmindex + ":" + this;
31918334Speter            else
32090075Sobrien                assert(vmindex < 0) : vmindex;
32190075Sobrien            assert(vmtarget instanceof MemberName) : vmtarget + " in " + this;
32218334Speter        }
32318334Speter        return true;
32418334Speter    }
32518334Speter
32618334Speter    private MemberName changeReferenceKind(byte refKind, byte oldKind) {
32718334Speter        assert(getReferenceKind() == oldKind);
32818334Speter        assert(MethodHandleNatives.refKindIsValid(refKind));
32918334Speter        flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
33018334Speter//        if (isConstructor() && refKind != REF_newInvokeSpecial)
33118334Speter//            flags += (IS_METHOD - IS_CONSTRUCTOR);
33218334Speter//        else if (refKind == REF_newInvokeSpecial && isMethod())
33318334Speter//            flags += (IS_CONSTRUCTOR - IS_METHOD);
33418334Speter        return this;
33518334Speter    }
33690075Sobrien
33790075Sobrien    private boolean testFlags(int mask, int value) {
33890075Sobrien        return (flags & mask) == value;
33990075Sobrien    }
34090075Sobrien    private boolean testAllFlags(int mask) {
34118334Speter        return testFlags(mask, mask);
34250397Sobrien    }
34350397Sobrien    private boolean testAnyFlags(int mask) {
34418334Speter        return !testFlags(mask, 0);
34518334Speter    }
34690075Sobrien
34790075Sobrien    /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
34890075Sobrien    public boolean isMethodHandleInvoke() {
34990075Sobrien        final int bits = MH_INVOKE_MODS;
35018334Speter        final int negs = Modifier.STATIC;
35118334Speter        if (testFlags(bits | negs, bits) &&
35218334Speter            clazz == MethodHandle.class) {
35318334Speter            return isMethodHandleInvokeName(name);
35418334Speter        }
35518334Speter        return false;
35618334Speter    }
35718334Speter    public static boolean isMethodHandleInvokeName(String name) {
35818334Speter        return name.equals("invoke") || name.equals("invokeExact");
35918334Speter    }
36018334Speter    private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
36118334Speter
36218334Speter    /** Utility method to query the modifier flags of this member. */
36318334Speter    public boolean isStatic() {
36418334Speter        return Modifier.isStatic(flags);
36518334Speter    }
36690075Sobrien    /** Utility method to query the modifier flags of this member. */
36718334Speter    public boolean isPublic() {
36818334Speter        return Modifier.isPublic(flags);
36918334Speter    }
37018334Speter    /** Utility method to query the modifier flags of this member. */
37190075Sobrien    public boolean isPrivate() {
37218334Speter        return Modifier.isPrivate(flags);
37318334Speter    }
37418334Speter    /** Utility method to query the modifier flags of this member. */
37518334Speter    public boolean isProtected() {
37618334Speter        return Modifier.isProtected(flags);
37718334Speter    }
37850397Sobrien    /** Utility method to query the modifier flags of this member. */
37918334Speter    public boolean isFinal() {
38018334Speter        return Modifier.isFinal(flags);
38118334Speter    }
38218334Speter    /** Utility method to query whether this member or its defining class is final. */
38318334Speter    public boolean canBeStaticallyBound() {
38418334Speter        return Modifier.isFinal(flags | clazz.getModifiers());
38550397Sobrien    }
38650397Sobrien    /** Utility method to query the modifier flags of this member. */
38750397Sobrien    public boolean isVolatile() {
38850397Sobrien        return Modifier.isVolatile(flags);
38990075Sobrien    }
39018334Speter    /** Utility method to query the modifier flags of this member. */
39118334Speter    public boolean isAbstract() {
39218334Speter        return Modifier.isAbstract(flags);
39318334Speter    }
39418334Speter    /** Utility method to query the modifier flags of this member. */
39518334Speter    public boolean isNative() {
39618334Speter        return Modifier.isNative(flags);
39718334Speter    }
39818334Speter    // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
39918334Speter
40018334Speter    // unofficial modifier flags, used by HotSpot:
40118334Speter    static final int BRIDGE    = 0x00000040;
40218334Speter    static final int VARARGS   = 0x00000080;
40318334Speter    static final int SYNTHETIC = 0x00001000;
40418334Speter    static final int ANNOTATION= 0x00002000;
40518334Speter    static final int ENUM      = 0x00004000;
40618334Speter    /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
40718334Speter    public boolean isBridge() {
40818334Speter        return testAllFlags(IS_METHOD | BRIDGE);
40918334Speter    }
41018334Speter    /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
41118334Speter    public boolean isVarargs() {
41218334Speter        return testAllFlags(VARARGS) && isInvocable();
41318334Speter    }
41418334Speter    /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
41550397Sobrien    public boolean isSynthetic() {
41618334Speter        return testAllFlags(SYNTHETIC);
41718334Speter    }
41850397Sobrien
41950397Sobrien    static final String CONSTRUCTOR_NAME = "<init>";  // the ever-popular
42050397Sobrien
42150397Sobrien    // modifiers exported by the JVM:
42250397Sobrien    static final int RECOGNIZED_MODIFIERS = 0xFFFF;
42318334Speter
42418334Speter    // private flags, not part of RECOGNIZED_MODIFIERS:
42590075Sobrien    static final int
42690075Sobrien            IS_METHOD        = MN_IS_METHOD,        // method (not constructor)
42790075Sobrien            IS_CONSTRUCTOR   = MN_IS_CONSTRUCTOR,   // constructor
42890075Sobrien            IS_FIELD         = MN_IS_FIELD,         // field
42918334Speter            IS_TYPE          = MN_IS_TYPE,          // nested type
43018334Speter            CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected
43118334Speter
43218334Speter    static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
43318334Speter    static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
43418334Speter    static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
43518334Speter    static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
43618334Speter    static final int SEARCH_ALL_SUPERS = MN_SEARCH_SUPERCLASSES | MN_SEARCH_INTERFACES;
43718334Speter
43818334Speter    /** Utility method to query whether this member is a method or constructor. */
43918334Speter    public boolean isInvocable() {
44018334Speter        return testAnyFlags(IS_INVOCABLE);
44118334Speter    }
44218334Speter    /** Utility method to query whether this member is a method, constructor, or field. */
44318334Speter    public boolean isFieldOrMethod() {
44418334Speter        return testAnyFlags(IS_FIELD_OR_METHOD);
44518334Speter    }
44618334Speter    /** Query whether this member is a method. */
44718334Speter    public boolean isMethod() {
44818334Speter        return testAllFlags(IS_METHOD);
44990075Sobrien    }
45018334Speter    /** Query whether this member is a constructor. */
45118334Speter    public boolean isConstructor() {
45252284Sobrien        return testAllFlags(IS_CONSTRUCTOR);
45352284Sobrien    }
45496263Sobrien    /** Query whether this member is a field. */
45518334Speter    public boolean isField() {
45652284Sobrien        return testAllFlags(IS_FIELD);
45752284Sobrien    }
45890075Sobrien    /** Query whether this member is a type. */
45952284Sobrien    public boolean isType() {
46090075Sobrien        return testAllFlags(IS_TYPE);
46190075Sobrien    }
46218334Speter    /** Utility method to query whether this member is neither public, private, nor protected. */
46318334Speter    public boolean isPackage() {
46418334Speter        return !testAnyFlags(ALL_ACCESS);
46590075Sobrien    }
46696263Sobrien    /** Query whether this member has a CallerSensitive annotation. */
46718334Speter    public boolean isCallerSensitive() {
46852284Sobrien        return testAllFlags(CALLER_SENSITIVE);
46918334Speter    }
47018334Speter
47152284Sobrien    /** Utility method to query whether this member is accessible from a given lookup class. */
47290075Sobrien    public boolean isAccessibleFrom(Class<?> lookupClass) {
47390075Sobrien        return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
47490075Sobrien                                               lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE);
47550397Sobrien    }
47618334Speter
47796263Sobrien    /** Initialize a query.   It is not resolved. */
47896263Sobrien    private void init(Class<?> defClass, String name, Object type, int flags) {
47996263Sobrien        // defining class is allowed to be null (for a naked name/type pair)
48096263Sobrien        //name.toString();  // null check
48118334Speter        //type.equals(type);  // null check
48218334Speter        // fill in fields:
48318334Speter        this.clazz = defClass;
48418334Speter        this.name = name;
48518334Speter        this.type = type;
48618334Speter        this.flags = flags;
48790075Sobrien        assert(testAnyFlags(ALL_KINDS));
48890075Sobrien        assert(this.resolution == null);  // nobody should have touched this yet
48990075Sobrien        //assert(referenceKindIsConsistent());  // do this after resolution
49090075Sobrien    }
49190075Sobrien
49290075Sobrien    /**
49390075Sobrien     * Calls down to the VM to fill in the fields.  This method is
49490075Sobrien     * synchronized to avoid racing calls.
49590075Sobrien     */
49690075Sobrien    private void expandFromVM() {
49790075Sobrien        if (type != null) {
49890075Sobrien            return;
49990075Sobrien        }
50090075Sobrien        if (!isResolved()) {
50190075Sobrien            return;
50290075Sobrien        }
50390075Sobrien        MethodHandleNatives.expand(this);
50490075Sobrien    }
50590075Sobrien
50690075Sobrien    // Capturing information from the Core Reflection API:
50790075Sobrien    private static int flagsMods(int flags, int mods, byte refKind) {
50890075Sobrien        assert((flags & RECOGNIZED_MODIFIERS) == 0);
50990075Sobrien        assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
51090075Sobrien        assert((refKind & ~MN_REFERENCE_KIND_MASK) == 0);
51190075Sobrien        return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
51290075Sobrien    }
51318334Speter    /** Create a name for the given reflected method.  The resulting name will be in a resolved state. */
51490075Sobrien    public MemberName(Method m) {
51590075Sobrien        this(m, false);
51690075Sobrien    }
51790075Sobrien    @SuppressWarnings("LeakingThisInConstructor")
51870635Sobrien    public MemberName(Method m, boolean wantSpecial) {
51990075Sobrien        m.getClass();  // NPE check
52090075Sobrien        // fill in vmtarget, vmindex while we have m in hand:
52190075Sobrien        MethodHandleNatives.init(this, m);
52290075Sobrien        if (clazz == null) {  // MHN.init failed
52370635Sobrien            if (m.getDeclaringClass() == MethodHandle.class &&
52418334Speter                isMethodHandleInvokeName(m.getName())) {
52552284Sobrien                // The JVM did not reify this signature-polymorphic instance.
52618334Speter                // Need a special case here.
52718334Speter                // See comments on MethodHandleNatives.linkMethod.
52818334Speter                MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
52918334Speter                int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
53018334Speter                init(MethodHandle.class, m.getName(), type, flags);
53118334Speter                if (isMethodHandleInvoke())
53290075Sobrien                    return;
53350397Sobrien            }
53452284Sobrien            throw new LinkageError(m.toString());
53518334Speter        }
53690075Sobrien        assert(isResolved() && this.clazz != null);
53752284Sobrien        this.name = m.getName();
53818334Speter        if (this.type == null)
53918334Speter            this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
54018334Speter        if (wantSpecial) {
54118334Speter            if (isAbstract())
54218334Speter                throw new AbstractMethodError(this.toString());
54318334Speter            if (getReferenceKind() == REF_invokeVirtual)
54490075Sobrien                changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
54590075Sobrien            else if (getReferenceKind() == REF_invokeInterface)
54690075Sobrien                // invokeSpecial on a default method
54790075Sobrien                changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
54890075Sobrien        }
54990075Sobrien    }
55090075Sobrien    public MemberName asSpecial() {
55190075Sobrien        switch (getReferenceKind()) {
55290075Sobrien        case REF_invokeSpecial:     return this;
55390075Sobrien        case REF_invokeVirtual:     return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
55490075Sobrien        case REF_invokeInterface:   return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
55590075Sobrien        case REF_newInvokeSpecial:  return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
55690075Sobrien        }
55790075Sobrien        throw new IllegalArgumentException(this.toString());
55890075Sobrien    }
55990075Sobrien    /** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind.
56018334Speter     *  In that case it must already be REF_invokeSpecial.
56118334Speter     */
56218334Speter    public MemberName asConstructor() {
56318334Speter        switch (getReferenceKind()) {
56418334Speter        case REF_invokeSpecial:     return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
56518334Speter        case REF_newInvokeSpecial:  return this;
56690075Sobrien        }
56750397Sobrien        throw new IllegalArgumentException(this.toString());
56852284Sobrien    }
56918334Speter    /** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind
57018334Speter     *  REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface.
57190075Sobrien     *  The end result is to get a fully virtualized version of the MN.
57252284Sobrien     *  (Note that resolving in the JVM will sometimes devirtualize, changing
57318334Speter     *  REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface
57418334Speter     *  in some corner cases to either of the previous two; this transform
57518334Speter     *  undoes that change under the assumption that it occurred.)
57618334Speter     */
57718334Speter    public MemberName asNormalOriginal() {
57818334Speter        byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
57918334Speter        byte refKind = getReferenceKind();
58018334Speter        byte newRefKind = refKind;
58118334Speter        MemberName result = this;
58218334Speter        switch (refKind) {
58318334Speter        case REF_invokeInterface:
58418334Speter        case REF_invokeVirtual:
58518334Speter        case REF_invokeSpecial:
58618334Speter            newRefKind = normalVirtual;
58718334Speter            break;
58890075Sobrien        }
58990075Sobrien        if (newRefKind == refKind)
59090075Sobrien            return this;
59190075Sobrien        result = clone().changeReferenceKind(newRefKind, refKind);
59290075Sobrien        assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
59390075Sobrien        return result;
59490075Sobrien    }
59590075Sobrien    /** Create a name for the given reflected constructor.  The resulting name will be in a resolved state. */
59690075Sobrien    @SuppressWarnings("LeakingThisInConstructor")
59718334Speter    public MemberName(Constructor<?> ctor) {
59818334Speter        ctor.getClass();  // NPE check
59918334Speter        // fill in vmtarget, vmindex while we have ctor in hand:
60018334Speter        MethodHandleNatives.init(this, ctor);
60118334Speter        assert(isResolved() && this.clazz != null);
60218334Speter        this.name = CONSTRUCTOR_NAME;
60318334Speter        if (this.type == null)
60418334Speter            this.type = new Object[] { void.class, ctor.getParameterTypes() };
60518334Speter    }
60618334Speter    /** Create a name for the given reflected field.  The resulting name will be in a resolved state.
60718334Speter     */
60818334Speter    public MemberName(Field fld) {
60918334Speter        this(fld, false);
61018334Speter    }
61118334Speter    @SuppressWarnings("LeakingThisInConstructor")
61218334Speter    public MemberName(Field fld, boolean makeSetter) {
61390075Sobrien        fld.getClass();  // NPE check
61490075Sobrien        // fill in vmtarget, vmindex while we have fld in hand:
61518334Speter        MethodHandleNatives.init(this, fld);
61690075Sobrien        assert(isResolved() && this.clazz != null);
61790075Sobrien        this.name = fld.getName();
61890075Sobrien        this.type = fld.getType();
61990075Sobrien        assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
62090075Sobrien        byte refKind = this.getReferenceKind();
621117395Skan        assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
622117395Skan        if (makeSetter) {
62390075Sobrien            changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind);
62490075Sobrien        }
62590075Sobrien    }
62690075Sobrien    public boolean isGetter() {
62790075Sobrien        return MethodHandleNatives.refKindIsGetter(getReferenceKind());
62890075Sobrien    }
62990075Sobrien    public boolean isSetter() {
63090075Sobrien        return MethodHandleNatives.refKindIsSetter(getReferenceKind());
63190075Sobrien    }
63290075Sobrien    public MemberName asSetter() {
63390075Sobrien        byte refKind = getReferenceKind();
63490075Sobrien        assert(MethodHandleNatives.refKindIsGetter(refKind));
63590075Sobrien        assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
63690075Sobrien        byte setterRefKind = (byte)(refKind + (REF_putField - REF_getField));
63790075Sobrien        return clone().changeReferenceKind(setterRefKind, refKind);
63890075Sobrien    }
63990075Sobrien    /** Create a name for the given class.  The resulting name will be in a resolved state. */
64018334Speter    public MemberName(Class<?> type) {
64118334Speter        init(type.getDeclaringClass(), type.getSimpleName(), type,
64218334Speter                flagsMods(IS_TYPE, type.getModifiers(), REF_NONE));
64318334Speter        initResolved(true);
64452284Sobrien    }
64518334Speter
64618334Speter    /**
64750397Sobrien     * Create a name for a signature-polymorphic invoker.
64850397Sobrien     * This is a placeholder for a signature-polymorphic instance
64950397Sobrien     * (of MH.invokeExact, etc.) that the JVM does not reify.
65050397Sobrien     * See comments on {@link MethodHandleNatives#linkMethod}.
65152284Sobrien     */
65252284Sobrien    static MemberName makeMethodHandleInvoke(String name, MethodType type) {
65390075Sobrien        return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
65418334Speter    }
65518334Speter    static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
65690075Sobrien        MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
65718334Speter        mem.flags |= mods;  // it's not resolved, but add these modifiers anyway
65890075Sobrien        assert(mem.isMethodHandleInvoke()) : mem;
65990075Sobrien        return mem;
66090075Sobrien    }
66190075Sobrien
66290075Sobrien    // bare-bones constructor; the JVM will fill it in
66390075Sobrien    MemberName() { }
66490075Sobrien
66590075Sobrien    // locally useful cloner
66690075Sobrien    @Override protected MemberName clone() {
66790075Sobrien        try {
66890075Sobrien            return (MemberName) super.clone();
66990075Sobrien        } catch (CloneNotSupportedException ex) {
67090075Sobrien            throw newInternalError(ex);
67190075Sobrien        }
67290075Sobrien     }
67390075Sobrien
67490075Sobrien    /** Get the definition of this member name.
67590075Sobrien     *  This may be in a super-class of the declaring class of this member.
67618334Speter     */
67790075Sobrien    public MemberName getDefinition() {
67890075Sobrien        if (!isResolved())  throw new IllegalStateException("must be resolved: "+this);
67990075Sobrien        if (isType())  return this;
68090075Sobrien        MemberName res = this.clone();
68190075Sobrien        res.clazz = null;
68290075Sobrien        res.type = null;
68390075Sobrien        res.name = null;
68490075Sobrien        res.resolution = res;
68590075Sobrien        res.expandFromVM();
68690075Sobrien        assert(res.getName().equals(this.getName()));
68790075Sobrien        return res;
68890075Sobrien    }
68990075Sobrien
69018334Speter    @Override
69118334Speter    public int hashCode() {
69252284Sobrien        return Objects.hash(clazz, getReferenceKind(), name, getType());
69352284Sobrien    }
69452284Sobrien    @Override
69552284Sobrien    public boolean equals(Object that) {
69652284Sobrien        return (that instanceof MemberName && this.equals((MemberName)that));
69752284Sobrien    }
69890075Sobrien
69952284Sobrien    /** Decide if two member names have exactly the same symbolic content.
70090075Sobrien     *  Does not take into account any actual class members, so even if
70152284Sobrien     *  two member names resolve to the same actual member, they may
70252284Sobrien     *  be distinct references.
70352284Sobrien     */
70452284Sobrien    public boolean equals(MemberName that) {
70552284Sobrien        if (this == that)  return true;
70690075Sobrien        if (that == null)  return false;
70790075Sobrien        return this.clazz == that.clazz
70852284Sobrien                && this.getReferenceKind() == that.getReferenceKind()
70990075Sobrien                && Objects.equals(this.name, that.name)
71052284Sobrien                && Objects.equals(this.getType(), that.getType());
71190075Sobrien    }
71290075Sobrien
71390075Sobrien    // Construction from symbolic parts, for queries:
71452284Sobrien    /** Create a field or type name from the given components:
71552284Sobrien     *  Declaring class, name, type, reference kind.
71652284Sobrien     *  The declaring class may be supplied as null if this is to be a bare name and type.
71752284Sobrien     *  The resulting name will in an unresolved state.
71852284Sobrien     */
71990075Sobrien    public MemberName(Class<?> defClass, String name, Class<?> type, byte refKind) {
72090075Sobrien        init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
72152284Sobrien        initResolved(false);
72252284Sobrien    }
72352284Sobrien    /** Create a field or type name from the given components:  Declaring class, name, type.
72452284Sobrien     *  The declaring class may be supplied as null if this is to be a bare name and type.
72590075Sobrien     *  The modifier flags default to zero.
72690075Sobrien     *  The resulting name will in an unresolved state.
72790075Sobrien     */
72890075Sobrien    public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
72990075Sobrien        this(defClass, name, type, REF_NONE);
73090075Sobrien        initResolved(false);
73190075Sobrien    }
73252284Sobrien    /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
73352284Sobrien     *  It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
73452284Sobrien     *  The declaring class may be supplied as null if this is to be a bare name and type.
73552284Sobrien     *  The last argument is optional, a boolean which requests REF_invokeSpecial.
73652284Sobrien     *  The resulting name will in an unresolved state.
73752284Sobrien     */
73852284Sobrien    public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
73952284Sobrien        int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
74052284Sobrien        init(defClass, name, type, flagsMods(initFlags, 0, refKind));
74152284Sobrien        initResolved(false);
74252284Sobrien    }
74352284Sobrien    /** Create a method, constructor, or field name from the given components:
74452284Sobrien     *  Reference kind, declaring class, name, type.
74552284Sobrien     */
74690075Sobrien    public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
74790075Sobrien        int kindFlags;
74890075Sobrien        if (MethodHandleNatives.refKindIsField(refKind)) {
74990075Sobrien            kindFlags = IS_FIELD;
75090075Sobrien            if (!(type instanceof Class))
75190075Sobrien                throw newIllegalArgumentException("not a field type");
75290075Sobrien        } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
75390075Sobrien            kindFlags = IS_METHOD;
75490075Sobrien            if (!(type instanceof MethodType))
75552284Sobrien                throw newIllegalArgumentException("not a method type");
75652284Sobrien        } else if (refKind == REF_newInvokeSpecial) {
75790075Sobrien            kindFlags = IS_CONSTRUCTOR;
75852284Sobrien            if (!(type instanceof MethodType) ||
75952284Sobrien                !CONSTRUCTOR_NAME.equals(name))
76052284Sobrien                throw newIllegalArgumentException("not a constructor type or name");
76152284Sobrien        } else {
76252284Sobrien            throw newIllegalArgumentException("bad reference kind "+refKind);
76390075Sobrien        }
76452284Sobrien        init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
76552284Sobrien        initResolved(false);
76652284Sobrien    }
76790075Sobrien    /** Query whether this member name is resolved to a non-static, non-final method.
76890075Sobrien     */
76990075Sobrien    public boolean hasReceiverTypeDispatch() {
77090075Sobrien        return MethodHandleNatives.refKindDoesDispatch(getReferenceKind());
77190075Sobrien    }
77290075Sobrien
77390075Sobrien    /** Query whether this member name is resolved.
77490075Sobrien     *  A resolved member name is one for which the JVM has found
77590075Sobrien     *  a method, constructor, field, or type binding corresponding exactly to the name.
77690075Sobrien     *  (Document?)
77790075Sobrien     */
77890075Sobrien    public boolean isResolved() {
77990075Sobrien        return resolution == null;
78090075Sobrien    }
78190075Sobrien
78290075Sobrien    private void initResolved(boolean isResolved) {
78390075Sobrien        assert(this.resolution == null);  // not initialized yet!
78490075Sobrien        if (!isResolved)
78590075Sobrien            this.resolution = this;
78690075Sobrien        assert(isResolved() == isResolved);
78790075Sobrien    }
78890075Sobrien
78990075Sobrien    void checkForTypeAlias() {
79090075Sobrien        if (isInvocable()) {
79190075Sobrien            MethodType type;
79290075Sobrien            if (this.type instanceof MethodType)
79390075Sobrien                type = (MethodType) this.type;
79490075Sobrien            else
79552284Sobrien                this.type = type = getMethodType();
79690075Sobrien            if (type.erase() == type)  return;
79752284Sobrien            if (VerifyAccess.isTypeVisible(type, clazz))  return;
79852284Sobrien            throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
79990075Sobrien        } else {
80090075Sobrien            Class<?> type;
80190075Sobrien            if (this.type instanceof Class<?>)
80290075Sobrien                type = (Class<?>) this.type;
80390075Sobrien            else
80490075Sobrien                this.type = type = getFieldType();
80590075Sobrien            if (VerifyAccess.isTypeVisible(type, clazz))  return;
80690075Sobrien            throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
80790075Sobrien        }
808117395Skan    }
809117395Skan
810117395Skan
811117395Skan    /** Produce a string form of this member name.
812117395Skan     *  For types, it is simply the type's own string (as reported by {@code toString}).
813117395Skan     *  For fields, it is {@code "DeclaringClass.name/type"}.
814117395Skan     *  For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
815117395Skan     *  If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
816117395Skan     *  If the member is unresolved, a prefix {@code "*."} is prepended.
817117395Skan     */
818117395Skan    @SuppressWarnings("LocalVariableHidesMemberVariable")
819117395Skan    @Override
820117395Skan    public String toString() {
821117395Skan        if (isType())
822117395Skan            return type.toString();  // class java.lang.String
82390075Sobrien        // else it is a field, method, or constructor
82490075Sobrien        StringBuilder buf = new StringBuilder();
82590075Sobrien        if (getDeclaringClass() != null) {
82690075Sobrien            buf.append(getName(clazz));
82790075Sobrien            buf.append('.');
82890075Sobrien        }
82990075Sobrien        String name = getName();
83090075Sobrien        buf.append(name == null ? "*" : name);
83190075Sobrien        Object type = getType();
83290075Sobrien        if (!isInvocable()) {
83390075Sobrien            buf.append('/');
83490075Sobrien            buf.append(type == null ? "*" : getName(type));
83590075Sobrien        } else {
83690075Sobrien            buf.append(type == null ? "(*)*" : getName(type));
83790075Sobrien        }
83890075Sobrien        byte refKind = getReferenceKind();
83990075Sobrien        if (refKind != REF_NONE) {
84090075Sobrien            buf.append('/');
84190075Sobrien            buf.append(MethodHandleNatives.refKindName(refKind));
84290075Sobrien        }
84390075Sobrien        //buf.append("#").append(System.identityHashCode(this));
84490075Sobrien        return buf.toString();
84590075Sobrien    }
846119256Skan    private static String getName(Object obj) {
847119256Skan        if (obj instanceof Class<?>)
848119256Skan            return ((Class<?>)obj).getName();
84990075Sobrien        return String.valueOf(obj);
85090075Sobrien    }
85190075Sobrien
852119256Skan    public IllegalAccessException makeAccessException(String message, Object from) {
85390075Sobrien        message = message + ": "+ toString();
85490075Sobrien        if (from != null)  message += ", from " + from;
85590075Sobrien        return new IllegalAccessException(message);
85690075Sobrien    }
85790075Sobrien    private String message() {
85890075Sobrien        if (isResolved())
85990075Sobrien            return "no access";
86090075Sobrien        else if (isConstructor())
86190075Sobrien            return "no such constructor";
86290075Sobrien        else if (isMethod())
86390075Sobrien            return "no such method";
86490075Sobrien        else
86590075Sobrien            return "no such field";
86690075Sobrien    }
86790075Sobrien    public ReflectiveOperationException makeAccessException() {
86852284Sobrien        String message = message() + ": "+ toString();
86952284Sobrien        ReflectiveOperationException ex;
87052284Sobrien        if (isResolved() || !(resolution instanceof NoSuchMethodError ||
87152284Sobrien                              resolution instanceof NoSuchFieldError))
87252284Sobrien            ex = new IllegalAccessException(message);
87352284Sobrien        else if (isConstructor())
87452284Sobrien            ex = new NoSuchMethodException(message);
87552284Sobrien        else if (isMethod())
87652284Sobrien            ex = new NoSuchMethodException(message);
87752284Sobrien        else
87852284Sobrien            ex = new NoSuchFieldException(message);
87952284Sobrien        if (resolution instanceof Throwable)
88052284Sobrien            ex.initCause((Throwable) resolution);
88152284Sobrien        return ex;
88252284Sobrien    }
88352284Sobrien
88452284Sobrien    /** Actually making a query requires an access check. */
88552284Sobrien    /*non-public*/ static Factory getFactory() {
88652284Sobrien        return Factory.INSTANCE;
88752284Sobrien    }
88852284Sobrien    /** A factory type for resolving member names with the help of the VM.
88952284Sobrien     *  TBD: Define access-safe public constructors for this factory.
89052284Sobrien     */
89152284Sobrien    /*non-public*/ static class Factory {
89252284Sobrien        private Factory() { } // singleton pattern
89352284Sobrien        static Factory INSTANCE = new Factory();
89452284Sobrien
89552284Sobrien        private static int ALLOWED_FLAGS = ALL_KINDS;
89652284Sobrien
89752284Sobrien        /// Queries
89852284Sobrien        List<MemberName> getMembers(Class<?> defc,
89952284Sobrien                String matchName, Object matchType,
90052284Sobrien                int matchFlags, Class<?> lookupClass) {
90152284Sobrien            matchFlags &= ALLOWED_FLAGS;
90252284Sobrien            String matchSig = null;
903117395Skan            if (matchType != null) {
904117395Skan                matchSig = BytecodeDescriptor.unparse(matchType);
905117395Skan                if (matchSig.startsWith("("))
906117395Skan                    matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
907117395Skan                else
908117395Skan                    matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
90952284Sobrien            }
91052284Sobrien            final int BUF_MAX = 0x2000;
91152284Sobrien            int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
91252284Sobrien            MemberName[] buf = newMemberBuffer(len1);
91352284Sobrien            int totalCount = 0;
91452284Sobrien            ArrayList<MemberName[]> bufs = null;
91552284Sobrien            int bufCount = 0;
91652284Sobrien            for (;;) {
91752284Sobrien                bufCount = MethodHandleNatives.getMembers(defc,
91890075Sobrien                        matchName, matchSig, matchFlags,
91952284Sobrien                        lookupClass,
92052284Sobrien                        totalCount, buf);
92152284Sobrien                if (bufCount <= buf.length) {
92252284Sobrien                    if (bufCount < 0)  bufCount = 0;
92352284Sobrien                    totalCount += bufCount;
92452284Sobrien                    break;
92552284Sobrien                }
92652284Sobrien                // JVM returned to us with an intentional overflow!
92752284Sobrien                totalCount += buf.length;
92852284Sobrien                int excess = bufCount - buf.length;
92952284Sobrien                if (bufs == null)  bufs = new ArrayList<>(1);
93090075Sobrien                bufs.add(buf);
93152284Sobrien                int len2 = buf.length;
93252284Sobrien                len2 = Math.max(len2, excess);
93352284Sobrien                len2 = Math.max(len2, totalCount / 4);
93452284Sobrien                buf = newMemberBuffer(Math.min(BUF_MAX, len2));
93552284Sobrien            }
93652284Sobrien            ArrayList<MemberName> result = new ArrayList<>(totalCount);
93790075Sobrien            if (bufs != null) {
93852284Sobrien                for (MemberName[] buf0 : bufs) {
93952284Sobrien                    Collections.addAll(result, buf0);
94052284Sobrien                }
94152284Sobrien            }
94290075Sobrien            result.addAll(Arrays.asList(buf).subList(0, bufCount));
94352284Sobrien            // Signature matching is not the same as type matching, since
94452284Sobrien            // one signature might correspond to several types.
94552284Sobrien            // So if matchType is a Class or MethodType, refilter the results.
94652284Sobrien            if (matchType != null && matchType != matchSig) {
94752284Sobrien                for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
94852284Sobrien                    MemberName m = it.next();
94952284Sobrien                    if (!matchType.equals(m.getType()))
95052284Sobrien                        it.remove();
95152284Sobrien                }
95252284Sobrien            }
95352284Sobrien            return result;
95452284Sobrien        }
95552284Sobrien        /** Produce a resolved version of the given member.
95652284Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
95752284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
95852284Sobrien         *  If lookup fails or access is not permitted, null is returned.
95952284Sobrien         *  Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
96052284Sobrien         */
96152284Sobrien        private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass) {
96252284Sobrien            MemberName m = ref.clone();  // JVM will side-effect the ref
96352284Sobrien            assert(refKind == m.getReferenceKind());
96452284Sobrien            try {
96552284Sobrien                m = MethodHandleNatives.resolve(m, lookupClass);
96652284Sobrien                m.checkForTypeAlias();
96752284Sobrien                m.resolution = null;
96852284Sobrien            } catch (LinkageError ex) {
96952284Sobrien                // JVM reports that the "bytecode behavior" would get an error
97052284Sobrien                assert(!m.isResolved());
97152284Sobrien                m.resolution = ex;
97252284Sobrien                return m;
97352284Sobrien            }
97452284Sobrien            assert(m.referenceKindIsConsistent());
97552284Sobrien            m.initResolved(true);
97652284Sobrien            assert(m.vminfoIsConsistent());
97752284Sobrien            return m;
97852284Sobrien        }
97952284Sobrien        /** Produce a resolved version of the given member.
98090075Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
98152284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
98252284Sobrien         *  If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown.
98352284Sobrien         *  Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
98490075Sobrien         */
98590075Sobrien        public
98690075Sobrien        <NoSuchMemberException extends ReflectiveOperationException>
98790075Sobrien        MemberName resolveOrFail(byte refKind, MemberName m, Class<?> lookupClass,
98890075Sobrien                                 Class<NoSuchMemberException> nsmClass)
98952284Sobrien                throws IllegalAccessException, NoSuchMemberException {
99052284Sobrien            MemberName result = resolve(refKind, m, lookupClass);
99152284Sobrien            if (result.isResolved())
99252284Sobrien                return result;
99352284Sobrien            ReflectiveOperationException ex = result.makeAccessException();
99452284Sobrien            if (ex instanceof IllegalAccessException)  throw (IllegalAccessException) ex;
99590075Sobrien            throw nsmClass.cast(ex);
99690075Sobrien        }
99752284Sobrien        /** Produce a resolved version of the given member.
99852284Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
99952284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
1000117395Skan         *  If lookup fails or access is not permitted, return null.
1001117395Skan         *  Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
100252284Sobrien         */
100352284Sobrien        public
100452284Sobrien        MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass) {
100552284Sobrien            MemberName result = resolve(refKind, m, lookupClass);
100652284Sobrien            if (result.isResolved())
100752284Sobrien                return result;
100852284Sobrien            return null;
100990075Sobrien        }
101052284Sobrien        /** Return a list of all methods defined by the given class.
101152284Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
101252284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
101352284Sobrien         *  Inaccessible members are not added to the last.
101452284Sobrien         */
101552284Sobrien        public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
101652284Sobrien                Class<?> lookupClass) {
101752284Sobrien            return getMethods(defc, searchSupers, null, null, lookupClass);
101852284Sobrien        }
101952284Sobrien        /** Return a list of matching methods defined by the given class.
102052284Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
102152284Sobrien         *  Returned methods will match the name (if not null) and the type (if not null).
102252284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
102352284Sobrien         *  Inaccessible members are not added to the last.
102452284Sobrien         */
102552284Sobrien        public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
102652284Sobrien                String name, MethodType type, Class<?> lookupClass) {
102752284Sobrien            int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
102852284Sobrien            return getMembers(defc, name, type, matchFlags, lookupClass);
102952284Sobrien        }
103052284Sobrien        /** Return a list of all constructors defined by the given class.
103152284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
103252284Sobrien         *  Inaccessible members are not added to the last.
103352284Sobrien         */
103452284Sobrien        public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
103552284Sobrien            return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
103652284Sobrien        }
103752284Sobrien        /** Return a list of all fields defined by the given class.
1038117395Skan         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
1039117395Skan         *  Access checking is performed on behalf of the given {@code lookupClass}.
1040117395Skan         *  Inaccessible members are not added to the last.
104152284Sobrien         */
104290075Sobrien        public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
104390075Sobrien                Class<?> lookupClass) {
104452284Sobrien            return getFields(defc, searchSupers, null, null, lookupClass);
104552284Sobrien        }
104652284Sobrien        /** Return a list of all fields defined by the given class.
104790075Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
104852284Sobrien         *  Returned fields will match the name (if not null) and the type (if not null).
104952284Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
105052284Sobrien         *  Inaccessible members are not added to the last.
105152284Sobrien         */
105252284Sobrien        public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
105352284Sobrien                String name, Class<?> type, Class<?> lookupClass) {
105452284Sobrien            int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
105552284Sobrien            return getMembers(defc, name, type, matchFlags, lookupClass);
105652284Sobrien        }
105752284Sobrien        /** Return a list of all nested types defined by the given class.
105852284Sobrien         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
105990075Sobrien         *  Access checking is performed on behalf of the given {@code lookupClass}.
106052284Sobrien         *  Inaccessible members are not added to the last.
106152284Sobrien         */
106252284Sobrien        public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
106352284Sobrien                Class<?> lookupClass) {
106452284Sobrien            int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
106552284Sobrien            return getMembers(defc, null, null, matchFlags, lookupClass);
106652284Sobrien        }
106752284Sobrien        private static MemberName[] newMemberBuffer(int length) {
106852284Sobrien            MemberName[] buf = new MemberName[length];
106952284Sobrien            // fill the buffer with dummy structs for the JVM to fill in
107052284Sobrien            for (int i = 0; i < length; i++)
107152284Sobrien                buf[i] = new MemberName();
107252284Sobrien            return buf;
107352284Sobrien        }
107452284Sobrien    }
107552284Sobrien
107652284Sobrien//    static {
107752284Sobrien//        System.out.println("Hello world!  My methods are:");
107852284Sobrien//        System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
107952284Sobrien//    }
108090075Sobrien}
108190075Sobrien