jaroslav@1646: /* jaroslav@1646: * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. jaroslav@1646: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@1646: * jaroslav@1646: * This code is free software; you can redistribute it and/or modify it jaroslav@1646: * under the terms of the GNU General Public License version 2 only, as jaroslav@1646: * published by the Free Software Foundation. Oracle designates this jaroslav@1646: * particular file as subject to the "Classpath" exception as provided jaroslav@1646: * by Oracle in the LICENSE file that accompanied this code. jaroslav@1646: * jaroslav@1646: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@1646: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@1646: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@1646: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@1646: * accompanied this code). jaroslav@1646: * jaroslav@1646: * You should have received a copy of the GNU General Public License version jaroslav@1646: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@1646: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@1646: * jaroslav@1646: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@1646: * or visit www.oracle.com if you need additional information or have any jaroslav@1646: * questions. jaroslav@1646: */ jaroslav@1646: jaroslav@1646: package java.lang.invoke; jaroslav@1646: jaroslav@1646: import sun.invoke.util.BytecodeDescriptor; jaroslav@1646: import sun.invoke.util.VerifyAccess; jaroslav@1646: jaroslav@1646: import java.lang.reflect.Constructor; jaroslav@1646: import java.lang.reflect.Field; jaroslav@1646: import java.lang.reflect.Method; jaroslav@1646: import java.lang.reflect.Member; jaroslav@1646: import java.lang.reflect.Modifier; jaroslav@1646: import java.util.ArrayList; jaroslav@1646: import java.util.Arrays; jaroslav@1646: import java.util.Collections; jaroslav@1646: import java.util.Iterator; jaroslav@1646: import java.util.List; jaroslav@1646: import static java.lang.invoke.MethodHandleNatives.Constants.*; jaroslav@1646: import static java.lang.invoke.MethodHandleStatics.*; jaroslav@1646: import java.util.Objects; jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * A {@code MemberName} is a compact symbolic datum which fully characterizes jaroslav@1646: * a method or field reference. jaroslav@1646: * A member name refers to a field, method, constructor, or member type. jaroslav@1646: * Every member name has a simple name (a string) and a type (either a Class or MethodType). jaroslav@1646: * A member name may also have a non-null declaring class, or it may be simply jaroslav@1646: * a naked name/type pair. jaroslav@1646: * A member name may also have non-zero modifier flags. jaroslav@1646: * Finally, a member name may be either resolved or unresolved. jaroslav@1646: * If it is resolved, the existence of the named jaroslav@1646: *

jaroslav@1646: * Whether resolved or not, a member name provides no access rights or jaroslav@1646: * invocation capability to its possessor. It is merely a compact jaroslav@1646: * representation of all symbolic information necessary to link to jaroslav@1646: * and properly use the named member. jaroslav@1646: *

jaroslav@1646: * When resolved, a member name's internal implementation may include references to JVM metadata. jaroslav@1646: * This representation is stateless and only decriptive. jaroslav@1646: * It provides no private information and no capability to use the member. jaroslav@1646: *

jaroslav@1646: * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information jaroslav@1646: * about the internals of a method (except its bytecodes) and also jaroslav@1646: * allows invocation. A MemberName is much lighter than a Method, jaroslav@1646: * since it contains about 7 fields to the 16 of Method (plus its sub-arrays), jaroslav@1646: * and those seven fields omit much of the information in Method. jaroslav@1646: * @author jrose jaroslav@1646: */ jaroslav@1646: /*non-public*/ final class MemberName implements Member, Cloneable { jaroslav@1646: private Class clazz; // class in which the method is defined jaroslav@1646: private String name; // may be null if not yet materialized jaroslav@1646: private Object type; // may be null if not yet materialized jaroslav@1646: private int flags; // modifier bits; see reflect.Modifier jaroslav@1646: //@Injected JVM_Method* vmtarget; jaroslav@1646: //@Injected int vmindex; jaroslav@1646: private Object resolution; // if null, this guy is resolved jaroslav@1646: jaroslav@1646: /** Return the declaring class of this member. jaroslav@1646: * In the case of a bare name and type, the declaring class will be null. jaroslav@1646: */ jaroslav@1646: public Class getDeclaringClass() { jaroslav@1646: return clazz; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method producing the class loader of the declaring class. */ jaroslav@1646: public ClassLoader getClassLoader() { jaroslav@1646: return clazz.getClassLoader(); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Return the simple name of this member. jaroslav@1646: * For a type, it is the same as {@link Class#getSimpleName}. jaroslav@1646: * For a method or field, it is the simple name of the member. jaroslav@1646: * For a constructor, it is always {@code "<init>"}. jaroslav@1646: */ jaroslav@1646: public String getName() { jaroslav@1646: if (name == null) { jaroslav@1646: expandFromVM(); jaroslav@1646: if (name == null) { jaroslav@1646: return null; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: return name; jaroslav@1646: } jaroslav@1646: jaroslav@1646: public MethodType getMethodOrFieldType() { jaroslav@1646: if (isInvocable()) jaroslav@1646: return getMethodType(); jaroslav@1646: if (isGetter()) jaroslav@1646: return MethodType.methodType(getFieldType()); jaroslav@1646: if (isSetter()) jaroslav@1646: return MethodType.methodType(void.class, getFieldType()); jaroslav@1646: throw new InternalError("not a method or field: "+this); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Return the declared type of this member, which jaroslav@1646: * must be a method or constructor. jaroslav@1646: */ jaroslav@1646: public MethodType getMethodType() { jaroslav@1646: if (type == null) { jaroslav@1646: expandFromVM(); jaroslav@1646: if (type == null) { jaroslav@1646: return null; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: if (!isInvocable()) { jaroslav@1646: throw newIllegalArgumentException("not invocable, no method type"); jaroslav@1646: } jaroslav@1646: jaroslav@1646: { jaroslav@1646: // Get a snapshot of type which doesn't get changed by racing threads. jaroslav@1646: final Object type = this.type; jaroslav@1646: if (type instanceof MethodType) { jaroslav@1646: return (MethodType) type; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: // type is not a MethodType yet. Convert it thread-safely. jaroslav@1646: synchronized (this) { jaroslav@1646: if (type instanceof String) { jaroslav@1646: String sig = (String) type; jaroslav@1646: MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader()); jaroslav@1646: type = res; jaroslav@1646: } else if (type instanceof Object[]) { jaroslav@1646: Object[] typeInfo = (Object[]) type; jaroslav@1646: Class[] ptypes = (Class[]) typeInfo[1]; jaroslav@1646: Class rtype = (Class) typeInfo[0]; jaroslav@1646: MethodType res = MethodType.methodType(rtype, ptypes); jaroslav@1646: type = res; jaroslav@1646: } jaroslav@1646: // Make sure type is a MethodType for racing threads. jaroslav@1646: assert type instanceof MethodType : "bad method type " + type; jaroslav@1646: } jaroslav@1646: return (MethodType) type; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Return the actual type under which this method or constructor must be invoked. jaroslav@1646: * For non-static methods or constructors, this is the type with a leading parameter, jaroslav@1646: * a reference to declaring class. For static methods, it is the same as the declared type. jaroslav@1646: */ jaroslav@1646: public MethodType getInvocationType() { jaroslav@1646: MethodType itype = getMethodOrFieldType(); jaroslav@1646: if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial) jaroslav@1646: return itype.changeReturnType(clazz); jaroslav@1646: if (!isStatic()) jaroslav@1646: return itype.insertParameterTypes(0, clazz); jaroslav@1646: return itype; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method producing the parameter types of the method type. */ jaroslav@1646: public Class[] getParameterTypes() { jaroslav@1646: return getMethodType().parameterArray(); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method producing the return type of the method type. */ jaroslav@1646: public Class getReturnType() { jaroslav@1646: return getMethodType().returnType(); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Return the declared type of this member, which jaroslav@1646: * must be a field or type. jaroslav@1646: * If it is a type member, that type itself is returned. jaroslav@1646: */ jaroslav@1646: public Class getFieldType() { jaroslav@1646: if (type == null) { jaroslav@1646: expandFromVM(); jaroslav@1646: if (type == null) { jaroslav@1646: return null; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: if (isInvocable()) { jaroslav@1646: throw newIllegalArgumentException("not a field or nested class, no simple type"); jaroslav@1646: } jaroslav@1646: jaroslav@1646: { jaroslav@1646: // Get a snapshot of type which doesn't get changed by racing threads. jaroslav@1646: final Object type = this.type; jaroslav@1646: if (type instanceof Class) { jaroslav@1646: return (Class) type; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: // type is not a Class yet. Convert it thread-safely. jaroslav@1646: synchronized (this) { jaroslav@1646: if (type instanceof String) { jaroslav@1646: String sig = (String) type; jaroslav@1646: MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader()); jaroslav@1646: Class res = mtype.returnType(); jaroslav@1646: type = res; jaroslav@1646: } jaroslav@1646: // Make sure type is a Class for racing threads. jaroslav@1646: assert type instanceof Class : "bad field type " + type; jaroslav@1646: } jaroslav@1646: return (Class) type; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method to produce either the method type or field type of this member. */ jaroslav@1646: public Object getType() { jaroslav@1646: return (isInvocable() ? getMethodType() : getFieldType()); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method to produce the signature of this member, jaroslav@1646: * used within the class file format to describe its type. jaroslav@1646: */ jaroslav@1646: public String getSignature() { jaroslav@1646: if (type == null) { jaroslav@1646: expandFromVM(); jaroslav@1646: if (type == null) { jaroslav@1646: return null; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: if (isInvocable()) jaroslav@1646: return BytecodeDescriptor.unparse(getMethodType()); jaroslav@1646: else jaroslav@1646: return BytecodeDescriptor.unparse(getFieldType()); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Return the modifier flags of this member. jaroslav@1646: * @see java.lang.reflect.Modifier jaroslav@1646: */ jaroslav@1646: public int getModifiers() { jaroslav@1646: return (flags & RECOGNIZED_MODIFIERS); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Return the reference kind of this member, or zero if none. jaroslav@1646: */ jaroslav@1646: public byte getReferenceKind() { jaroslav@1646: return (byte) ((flags >>> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK); jaroslav@1646: } jaroslav@1646: private boolean referenceKindIsConsistent() { jaroslav@1646: byte refKind = getReferenceKind(); jaroslav@1646: if (refKind == REF_NONE) return isType(); jaroslav@1646: if (isField()) { jaroslav@1646: assert(staticIsConsistent()); jaroslav@1646: assert(MethodHandleNatives.refKindIsField(refKind)); jaroslav@1646: } else if (isConstructor()) { jaroslav@1646: assert(refKind == REF_newInvokeSpecial || refKind == REF_invokeSpecial); jaroslav@1646: } else if (isMethod()) { jaroslav@1646: assert(staticIsConsistent()); jaroslav@1646: assert(MethodHandleNatives.refKindIsMethod(refKind)); jaroslav@1646: if (clazz.isInterface()) jaroslav@1646: assert(refKind == REF_invokeInterface || jaroslav@1646: refKind == REF_invokeStatic || jaroslav@1646: refKind == REF_invokeSpecial || jaroslav@1646: refKind == REF_invokeVirtual && isObjectPublicMethod()); jaroslav@1646: } else { jaroslav@1646: assert(false); jaroslav@1646: } jaroslav@1646: return true; jaroslav@1646: } jaroslav@1646: private boolean isObjectPublicMethod() { jaroslav@1646: if (clazz == Object.class) return true; jaroslav@1646: MethodType mtype = getMethodType(); jaroslav@1646: if (name.equals("toString") && mtype.returnType() == String.class && mtype.parameterCount() == 0) jaroslav@1646: return true; jaroslav@1646: if (name.equals("hashCode") && mtype.returnType() == int.class && mtype.parameterCount() == 0) jaroslav@1646: return true; jaroslav@1646: if (name.equals("equals") && mtype.returnType() == boolean.class && mtype.parameterCount() == 1 && mtype.parameterType(0) == Object.class) jaroslav@1646: return true; jaroslav@1646: return false; jaroslav@1646: } jaroslav@1646: /*non-public*/ boolean referenceKindIsConsistentWith(int originalRefKind) { jaroslav@1646: int refKind = getReferenceKind(); jaroslav@1646: if (refKind == originalRefKind) return true; jaroslav@1646: switch (originalRefKind) { jaroslav@1646: case REF_invokeInterface: jaroslav@1646: // Looking up an interface method, can get (e.g.) Object.hashCode jaroslav@1646: assert(refKind == REF_invokeVirtual || jaroslav@1646: refKind == REF_invokeSpecial) : this; jaroslav@1646: return true; jaroslav@1646: case REF_invokeVirtual: jaroslav@1646: case REF_newInvokeSpecial: jaroslav@1646: // Looked up a virtual, can get (e.g.) final String.hashCode. jaroslav@1646: assert(refKind == REF_invokeSpecial) : this; jaroslav@1646: return true; jaroslav@1646: } jaroslav@1646: assert(false) : this+" != "+MethodHandleNatives.refKindName((byte)originalRefKind); jaroslav@1646: return true; jaroslav@1646: } jaroslav@1646: private boolean staticIsConsistent() { jaroslav@1646: byte refKind = getReferenceKind(); jaroslav@1646: return MethodHandleNatives.refKindIsStatic(refKind) == isStatic() || getModifiers() == 0; jaroslav@1646: } jaroslav@1646: private boolean vminfoIsConsistent() { jaroslav@1646: byte refKind = getReferenceKind(); jaroslav@1646: assert(isResolved()); // else don't call jaroslav@1646: Object vminfo = MethodHandleNatives.getMemberVMInfo(this); jaroslav@1646: assert(vminfo instanceof Object[]); jaroslav@1646: long vmindex = (Long) ((Object[])vminfo)[0]; jaroslav@1646: Object vmtarget = ((Object[])vminfo)[1]; jaroslav@1646: if (MethodHandleNatives.refKindIsField(refKind)) { jaroslav@1646: assert(vmindex >= 0) : vmindex + ":" + this; jaroslav@1646: assert(vmtarget instanceof Class); jaroslav@1646: } else { jaroslav@1646: if (MethodHandleNatives.refKindDoesDispatch(refKind)) jaroslav@1646: assert(vmindex >= 0) : vmindex + ":" + this; jaroslav@1646: else jaroslav@1646: assert(vmindex < 0) : vmindex; jaroslav@1646: assert(vmtarget instanceof MemberName) : vmtarget + " in " + this; jaroslav@1646: } jaroslav@1646: return true; jaroslav@1646: } jaroslav@1646: jaroslav@1646: private MemberName changeReferenceKind(byte refKind, byte oldKind) { jaroslav@1646: assert(getReferenceKind() == oldKind); jaroslav@1646: assert(MethodHandleNatives.refKindIsValid(refKind)); jaroslav@1646: flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT); jaroslav@1646: // if (isConstructor() && refKind != REF_newInvokeSpecial) jaroslav@1646: // flags += (IS_METHOD - IS_CONSTRUCTOR); jaroslav@1646: // else if (refKind == REF_newInvokeSpecial && isMethod()) jaroslav@1646: // flags += (IS_CONSTRUCTOR - IS_METHOD); jaroslav@1646: return this; jaroslav@1646: } jaroslav@1646: jaroslav@1646: private boolean testFlags(int mask, int value) { jaroslav@1646: return (flags & mask) == value; jaroslav@1646: } jaroslav@1646: private boolean testAllFlags(int mask) { jaroslav@1646: return testFlags(mask, mask); jaroslav@1646: } jaroslav@1646: private boolean testAnyFlags(int mask) { jaroslav@1646: return !testFlags(mask, 0); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */ jaroslav@1646: public boolean isMethodHandleInvoke() { jaroslav@1646: final int bits = MH_INVOKE_MODS; jaroslav@1646: final int negs = Modifier.STATIC; jaroslav@1646: if (testFlags(bits | negs, bits) && jaroslav@1646: clazz == MethodHandle.class) { jaroslav@1646: return isMethodHandleInvokeName(name); jaroslav@1646: } jaroslav@1646: return false; jaroslav@1646: } jaroslav@1646: public static boolean isMethodHandleInvokeName(String name) { jaroslav@1646: return name.equals("invoke") || name.equals("invokeExact"); jaroslav@1646: } jaroslav@1646: private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC; jaroslav@1646: jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isStatic() { jaroslav@1646: return Modifier.isStatic(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isPublic() { jaroslav@1646: return Modifier.isPublic(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isPrivate() { jaroslav@1646: return Modifier.isPrivate(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isProtected() { jaroslav@1646: return Modifier.isProtected(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isFinal() { jaroslav@1646: return Modifier.isFinal(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query whether this member or its defining class is final. */ jaroslav@1646: public boolean canBeStaticallyBound() { jaroslav@1646: return Modifier.isFinal(flags | clazz.getModifiers()); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isVolatile() { jaroslav@1646: return Modifier.isVolatile(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isAbstract() { jaroslav@1646: return Modifier.isAbstract(flags); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member. */ jaroslav@1646: public boolean isNative() { jaroslav@1646: return Modifier.isNative(flags); jaroslav@1646: } jaroslav@1646: // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo jaroslav@1646: jaroslav@1646: // unofficial modifier flags, used by HotSpot: jaroslav@1646: static final int BRIDGE = 0x00000040; jaroslav@1646: static final int VARARGS = 0x00000080; jaroslav@1646: static final int SYNTHETIC = 0x00001000; jaroslav@1646: static final int ANNOTATION= 0x00002000; jaroslav@1646: static final int ENUM = 0x00004000; jaroslav@1646: /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ jaroslav@1646: public boolean isBridge() { jaroslav@1646: return testAllFlags(IS_METHOD | BRIDGE); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ jaroslav@1646: public boolean isVarargs() { jaroslav@1646: return testAllFlags(VARARGS) && isInvocable(); jaroslav@1646: } jaroslav@1646: /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ jaroslav@1646: public boolean isSynthetic() { jaroslav@1646: return testAllFlags(SYNTHETIC); jaroslav@1646: } jaroslav@1646: jaroslav@1646: static final String CONSTRUCTOR_NAME = ""; // the ever-popular jaroslav@1646: jaroslav@1646: // modifiers exported by the JVM: jaroslav@1646: static final int RECOGNIZED_MODIFIERS = 0xFFFF; jaroslav@1646: jaroslav@1646: // private flags, not part of RECOGNIZED_MODIFIERS: jaroslav@1646: static final int jaroslav@1646: IS_METHOD = MN_IS_METHOD, // method (not constructor) jaroslav@1646: IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor jaroslav@1646: IS_FIELD = MN_IS_FIELD, // field jaroslav@1646: IS_TYPE = MN_IS_TYPE, // nested type jaroslav@1646: CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected jaroslav@1646: jaroslav@1646: static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; jaroslav@1646: static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; jaroslav@1646: static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR; jaroslav@1646: static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD; jaroslav@1646: static final int SEARCH_ALL_SUPERS = MN_SEARCH_SUPERCLASSES | MN_SEARCH_INTERFACES; jaroslav@1646: jaroslav@1646: /** Utility method to query whether this member is a method or constructor. */ jaroslav@1646: public boolean isInvocable() { jaroslav@1646: return testAnyFlags(IS_INVOCABLE); jaroslav@1646: } jaroslav@1646: /** Utility method to query whether this member is a method, constructor, or field. */ jaroslav@1646: public boolean isFieldOrMethod() { jaroslav@1646: return testAnyFlags(IS_FIELD_OR_METHOD); jaroslav@1646: } jaroslav@1646: /** Query whether this member is a method. */ jaroslav@1646: public boolean isMethod() { jaroslav@1646: return testAllFlags(IS_METHOD); jaroslav@1646: } jaroslav@1646: /** Query whether this member is a constructor. */ jaroslav@1646: public boolean isConstructor() { jaroslav@1646: return testAllFlags(IS_CONSTRUCTOR); jaroslav@1646: } jaroslav@1646: /** Query whether this member is a field. */ jaroslav@1646: public boolean isField() { jaroslav@1646: return testAllFlags(IS_FIELD); jaroslav@1646: } jaroslav@1646: /** Query whether this member is a type. */ jaroslav@1646: public boolean isType() { jaroslav@1646: return testAllFlags(IS_TYPE); jaroslav@1646: } jaroslav@1646: /** Utility method to query whether this member is neither public, private, nor protected. */ jaroslav@1646: public boolean isPackage() { jaroslav@1646: return !testAnyFlags(ALL_ACCESS); jaroslav@1646: } jaroslav@1646: /** Query whether this member has a CallerSensitive annotation. */ jaroslav@1646: public boolean isCallerSensitive() { jaroslav@1646: return testAllFlags(CALLER_SENSITIVE); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Utility method to query whether this member is accessible from a given lookup class. */ jaroslav@1646: public boolean isAccessibleFrom(Class lookupClass) { jaroslav@1646: return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags, jaroslav@1646: lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Initialize a query. It is not resolved. */ jaroslav@1646: private void init(Class defClass, String name, Object type, int flags) { jaroslav@1646: // defining class is allowed to be null (for a naked name/type pair) jaroslav@1646: //name.toString(); // null check jaroslav@1646: //type.equals(type); // null check jaroslav@1646: // fill in fields: jaroslav@1646: this.clazz = defClass; jaroslav@1646: this.name = name; jaroslav@1646: this.type = type; jaroslav@1646: this.flags = flags; jaroslav@1646: assert(testAnyFlags(ALL_KINDS)); jaroslav@1646: assert(this.resolution == null); // nobody should have touched this yet jaroslav@1646: //assert(referenceKindIsConsistent()); // do this after resolution jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Calls down to the VM to fill in the fields. This method is jaroslav@1646: * synchronized to avoid racing calls. jaroslav@1646: */ jaroslav@1646: private void expandFromVM() { jaroslav@1646: if (type != null) { jaroslav@1646: return; jaroslav@1646: } jaroslav@1646: if (!isResolved()) { jaroslav@1646: return; jaroslav@1646: } jaroslav@1646: MethodHandleNatives.expand(this); jaroslav@1646: } jaroslav@1646: jaroslav@1646: // Capturing information from the Core Reflection API: jaroslav@1646: private static int flagsMods(int flags, int mods, byte refKind) { jaroslav@1646: assert((flags & RECOGNIZED_MODIFIERS) == 0); jaroslav@1646: assert((mods & ~RECOGNIZED_MODIFIERS) == 0); jaroslav@1646: assert((refKind & ~MN_REFERENCE_KIND_MASK) == 0); jaroslav@1646: return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT); jaroslav@1646: } jaroslav@1646: /** Create a name for the given reflected method. The resulting name will be in a resolved state. */ jaroslav@1646: public MemberName(Method m) { jaroslav@1646: this(m, false); jaroslav@1646: } jaroslav@1646: @SuppressWarnings("LeakingThisInConstructor") jaroslav@1646: public MemberName(Method m, boolean wantSpecial) { jaroslav@1646: m.getClass(); // NPE check jaroslav@1646: // fill in vmtarget, vmindex while we have m in hand: jaroslav@1646: MethodHandleNatives.init(this, m); jaroslav@1646: if (clazz == null) { // MHN.init failed jaroslav@1646: if (m.getDeclaringClass() == MethodHandle.class && jaroslav@1646: isMethodHandleInvokeName(m.getName())) { jaroslav@1646: // The JVM did not reify this signature-polymorphic instance. jaroslav@1646: // Need a special case here. jaroslav@1646: // See comments on MethodHandleNatives.linkMethod. jaroslav@1646: MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes()); jaroslav@1646: int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual); jaroslav@1646: init(MethodHandle.class, m.getName(), type, flags); jaroslav@1646: if (isMethodHandleInvoke()) jaroslav@1646: return; jaroslav@1646: } jaroslav@1646: throw new LinkageError(m.toString()); jaroslav@1646: } jaroslav@1646: assert(isResolved() && this.clazz != null); jaroslav@1646: this.name = m.getName(); jaroslav@1646: if (this.type == null) jaroslav@1646: this.type = new Object[] { m.getReturnType(), m.getParameterTypes() }; jaroslav@1646: if (wantSpecial) { jaroslav@1646: if (isAbstract()) jaroslav@1646: throw new AbstractMethodError(this.toString()); jaroslav@1646: if (getReferenceKind() == REF_invokeVirtual) jaroslav@1646: changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual); jaroslav@1646: else if (getReferenceKind() == REF_invokeInterface) jaroslav@1646: // invokeSpecial on a default method jaroslav@1646: changeReferenceKind(REF_invokeSpecial, REF_invokeInterface); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: public MemberName asSpecial() { jaroslav@1646: switch (getReferenceKind()) { jaroslav@1646: case REF_invokeSpecial: return this; jaroslav@1646: case REF_invokeVirtual: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual); jaroslav@1646: case REF_invokeInterface: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface); jaroslav@1646: case REF_newInvokeSpecial: return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial); jaroslav@1646: } jaroslav@1646: throw new IllegalArgumentException(this.toString()); jaroslav@1646: } jaroslav@1646: /** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind. jaroslav@1646: * In that case it must already be REF_invokeSpecial. jaroslav@1646: */ jaroslav@1646: public MemberName asConstructor() { jaroslav@1646: switch (getReferenceKind()) { jaroslav@1646: case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial); jaroslav@1646: case REF_newInvokeSpecial: return this; jaroslav@1646: } jaroslav@1646: throw new IllegalArgumentException(this.toString()); jaroslav@1646: } jaroslav@1646: /** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind jaroslav@1646: * REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface. jaroslav@1646: * The end result is to get a fully virtualized version of the MN. jaroslav@1646: * (Note that resolving in the JVM will sometimes devirtualize, changing jaroslav@1646: * REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface jaroslav@1646: * in some corner cases to either of the previous two; this transform jaroslav@1646: * undoes that change under the assumption that it occurred.) jaroslav@1646: */ jaroslav@1646: public MemberName asNormalOriginal() { jaroslav@1646: byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual; jaroslav@1646: byte refKind = getReferenceKind(); jaroslav@1646: byte newRefKind = refKind; jaroslav@1646: MemberName result = this; jaroslav@1646: switch (refKind) { jaroslav@1646: case REF_invokeInterface: jaroslav@1646: case REF_invokeVirtual: jaroslav@1646: case REF_invokeSpecial: jaroslav@1646: newRefKind = normalVirtual; jaroslav@1646: break; jaroslav@1646: } jaroslav@1646: if (newRefKind == refKind) jaroslav@1646: return this; jaroslav@1646: result = clone().changeReferenceKind(newRefKind, refKind); jaroslav@1646: assert(this.referenceKindIsConsistentWith(result.getReferenceKind())); jaroslav@1646: return result; jaroslav@1646: } jaroslav@1646: /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */ jaroslav@1646: @SuppressWarnings("LeakingThisInConstructor") jaroslav@1646: public MemberName(Constructor ctor) { jaroslav@1646: ctor.getClass(); // NPE check jaroslav@1646: // fill in vmtarget, vmindex while we have ctor in hand: jaroslav@1646: MethodHandleNatives.init(this, ctor); jaroslav@1646: assert(isResolved() && this.clazz != null); jaroslav@1646: this.name = CONSTRUCTOR_NAME; jaroslav@1646: if (this.type == null) jaroslav@1646: this.type = new Object[] { void.class, ctor.getParameterTypes() }; jaroslav@1646: } jaroslav@1646: /** Create a name for the given reflected field. The resulting name will be in a resolved state. jaroslav@1646: */ jaroslav@1646: public MemberName(Field fld) { jaroslav@1646: this(fld, false); jaroslav@1646: } jaroslav@1646: @SuppressWarnings("LeakingThisInConstructor") jaroslav@1646: public MemberName(Field fld, boolean makeSetter) { jaroslav@1646: fld.getClass(); // NPE check jaroslav@1646: // fill in vmtarget, vmindex while we have fld in hand: jaroslav@1646: MethodHandleNatives.init(this, fld); jaroslav@1646: assert(isResolved() && this.clazz != null); jaroslav@1646: this.name = fld.getName(); jaroslav@1646: this.type = fld.getType(); jaroslav@1646: assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField)); jaroslav@1646: byte refKind = this.getReferenceKind(); jaroslav@1646: assert(refKind == (isStatic() ? REF_getStatic : REF_getField)); jaroslav@1646: if (makeSetter) { jaroslav@1646: changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: public boolean isGetter() { jaroslav@1646: return MethodHandleNatives.refKindIsGetter(getReferenceKind()); jaroslav@1646: } jaroslav@1646: public boolean isSetter() { jaroslav@1646: return MethodHandleNatives.refKindIsSetter(getReferenceKind()); jaroslav@1646: } jaroslav@1646: public MemberName asSetter() { jaroslav@1646: byte refKind = getReferenceKind(); jaroslav@1646: assert(MethodHandleNatives.refKindIsGetter(refKind)); jaroslav@1646: assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField)); jaroslav@1646: byte setterRefKind = (byte)(refKind + (REF_putField - REF_getField)); jaroslav@1646: return clone().changeReferenceKind(setterRefKind, refKind); jaroslav@1646: } jaroslav@1646: /** Create a name for the given class. The resulting name will be in a resolved state. */ jaroslav@1646: public MemberName(Class type) { jaroslav@1646: init(type.getDeclaringClass(), type.getSimpleName(), type, jaroslav@1646: flagsMods(IS_TYPE, type.getModifiers(), REF_NONE)); jaroslav@1646: initResolved(true); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Create a name for a signature-polymorphic invoker. jaroslav@1646: * This is a placeholder for a signature-polymorphic instance jaroslav@1646: * (of MH.invokeExact, etc.) that the JVM does not reify. jaroslav@1646: * See comments on {@link MethodHandleNatives#linkMethod}. jaroslav@1646: */ jaroslav@1646: static MemberName makeMethodHandleInvoke(String name, MethodType type) { jaroslav@1646: return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC); jaroslav@1646: } jaroslav@1646: static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) { jaroslav@1646: MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual); jaroslav@1646: mem.flags |= mods; // it's not resolved, but add these modifiers anyway jaroslav@1646: assert(mem.isMethodHandleInvoke()) : mem; jaroslav@1646: return mem; jaroslav@1646: } jaroslav@1646: jaroslav@1646: // bare-bones constructor; the JVM will fill it in jaroslav@1646: MemberName() { } jaroslav@1646: jaroslav@1646: // locally useful cloner jaroslav@1646: @Override protected MemberName clone() { jaroslav@1646: try { jaroslav@1646: return (MemberName) super.clone(); jaroslav@1646: } catch (CloneNotSupportedException ex) { jaroslav@1646: throw newInternalError(ex); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Get the definition of this member name. jaroslav@1646: * This may be in a super-class of the declaring class of this member. jaroslav@1646: */ jaroslav@1646: public MemberName getDefinition() { jaroslav@1646: if (!isResolved()) throw new IllegalStateException("must be resolved: "+this); jaroslav@1646: if (isType()) return this; jaroslav@1646: MemberName res = this.clone(); jaroslav@1646: res.clazz = null; jaroslav@1646: res.type = null; jaroslav@1646: res.name = null; jaroslav@1646: res.resolution = res; jaroslav@1646: res.expandFromVM(); jaroslav@1646: assert(res.getName().equals(this.getName())); jaroslav@1646: return res; jaroslav@1646: } jaroslav@1646: jaroslav@1646: @Override jaroslav@1646: public int hashCode() { jaroslav@1646: return Objects.hash(clazz, getReferenceKind(), name, getType()); jaroslav@1646: } jaroslav@1646: @Override jaroslav@1646: public boolean equals(Object that) { jaroslav@1646: return (that instanceof MemberName && this.equals((MemberName)that)); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Decide if two member names have exactly the same symbolic content. jaroslav@1646: * Does not take into account any actual class members, so even if jaroslav@1646: * two member names resolve to the same actual member, they may jaroslav@1646: * be distinct references. jaroslav@1646: */ jaroslav@1646: public boolean equals(MemberName that) { jaroslav@1646: if (this == that) return true; jaroslav@1646: if (that == null) return false; jaroslav@1646: return this.clazz == that.clazz jaroslav@1646: && this.getReferenceKind() == that.getReferenceKind() jaroslav@1646: && Objects.equals(this.name, that.name) jaroslav@1646: && Objects.equals(this.getType(), that.getType()); jaroslav@1646: } jaroslav@1646: jaroslav@1646: // Construction from symbolic parts, for queries: jaroslav@1646: /** Create a field or type name from the given components: jaroslav@1646: * Declaring class, name, type, reference kind. jaroslav@1646: * The declaring class may be supplied as null if this is to be a bare name and type. jaroslav@1646: * The resulting name will in an unresolved state. jaroslav@1646: */ jaroslav@1646: public MemberName(Class defClass, String name, Class type, byte refKind) { jaroslav@1646: init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind)); jaroslav@1646: initResolved(false); jaroslav@1646: } jaroslav@1646: /** Create a field or type name from the given components: Declaring class, name, type. jaroslav@1646: * The declaring class may be supplied as null if this is to be a bare name and type. jaroslav@1646: * The modifier flags default to zero. jaroslav@1646: * The resulting name will in an unresolved state. jaroslav@1646: */ jaroslav@1646: public MemberName(Class defClass, String name, Class type, Void unused) { jaroslav@1646: this(defClass, name, type, REF_NONE); jaroslav@1646: initResolved(false); jaroslav@1646: } jaroslav@1646: /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers. jaroslav@1646: * It will be a constructor if and only if the name is {@code "<init>"}. jaroslav@1646: * The declaring class may be supplied as null if this is to be a bare name and type. jaroslav@1646: * The last argument is optional, a boolean which requests REF_invokeSpecial. jaroslav@1646: * The resulting name will in an unresolved state. jaroslav@1646: */ jaroslav@1646: public MemberName(Class defClass, String name, MethodType type, byte refKind) { jaroslav@1646: int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD); jaroslav@1646: init(defClass, name, type, flagsMods(initFlags, 0, refKind)); jaroslav@1646: initResolved(false); jaroslav@1646: } jaroslav@1646: /** Create a method, constructor, or field name from the given components: jaroslav@1646: * Reference kind, declaring class, name, type. jaroslav@1646: */ jaroslav@1646: public MemberName(byte refKind, Class defClass, String name, Object type) { jaroslav@1646: int kindFlags; jaroslav@1646: if (MethodHandleNatives.refKindIsField(refKind)) { jaroslav@1646: kindFlags = IS_FIELD; jaroslav@1646: if (!(type instanceof Class)) jaroslav@1646: throw newIllegalArgumentException("not a field type"); jaroslav@1646: } else if (MethodHandleNatives.refKindIsMethod(refKind)) { jaroslav@1646: kindFlags = IS_METHOD; jaroslav@1646: if (!(type instanceof MethodType)) jaroslav@1646: throw newIllegalArgumentException("not a method type"); jaroslav@1646: } else if (refKind == REF_newInvokeSpecial) { jaroslav@1646: kindFlags = IS_CONSTRUCTOR; jaroslav@1646: if (!(type instanceof MethodType) || jaroslav@1646: !CONSTRUCTOR_NAME.equals(name)) jaroslav@1646: throw newIllegalArgumentException("not a constructor type or name"); jaroslav@1646: } else { jaroslav@1646: throw newIllegalArgumentException("bad reference kind "+refKind); jaroslav@1646: } jaroslav@1646: init(defClass, name, type, flagsMods(kindFlags, 0, refKind)); jaroslav@1646: initResolved(false); jaroslav@1646: } jaroslav@1646: /** Query whether this member name is resolved to a non-static, non-final method. jaroslav@1646: */ jaroslav@1646: public boolean hasReceiverTypeDispatch() { jaroslav@1646: return MethodHandleNatives.refKindDoesDispatch(getReferenceKind()); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Query whether this member name is resolved. jaroslav@1646: * A resolved member name is one for which the JVM has found jaroslav@1646: * a method, constructor, field, or type binding corresponding exactly to the name. jaroslav@1646: * (Document?) jaroslav@1646: */ jaroslav@1646: public boolean isResolved() { jaroslav@1646: return resolution == null; jaroslav@1646: } jaroslav@1646: jaroslav@1646: private void initResolved(boolean isResolved) { jaroslav@1646: assert(this.resolution == null); // not initialized yet! jaroslav@1646: if (!isResolved) jaroslav@1646: this.resolution = this; jaroslav@1646: assert(isResolved() == isResolved); jaroslav@1646: } jaroslav@1646: jaroslav@1646: void checkForTypeAlias() { jaroslav@1646: if (isInvocable()) { jaroslav@1646: MethodType type; jaroslav@1646: if (this.type instanceof MethodType) jaroslav@1646: type = (MethodType) this.type; jaroslav@1646: else jaroslav@1646: this.type = type = getMethodType(); jaroslav@1646: if (type.erase() == type) return; jaroslav@1646: if (VerifyAccess.isTypeVisible(type, clazz)) return; jaroslav@1646: throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz); jaroslav@1646: } else { jaroslav@1646: Class type; jaroslav@1646: if (this.type instanceof Class) jaroslav@1646: type = (Class) this.type; jaroslav@1646: else jaroslav@1646: this.type = type = getFieldType(); jaroslav@1646: if (VerifyAccess.isTypeVisible(type, clazz)) return; jaroslav@1646: throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: jaroslav@1646: /** Produce a string form of this member name. jaroslav@1646: * For types, it is simply the type's own string (as reported by {@code toString}). jaroslav@1646: * For fields, it is {@code "DeclaringClass.name/type"}. jaroslav@1646: * For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}. jaroslav@1646: * If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted. jaroslav@1646: * If the member is unresolved, a prefix {@code "*."} is prepended. jaroslav@1646: */ jaroslav@1646: @SuppressWarnings("LocalVariableHidesMemberVariable") jaroslav@1646: @Override jaroslav@1646: public String toString() { jaroslav@1646: if (isType()) jaroslav@1646: return type.toString(); // class java.lang.String jaroslav@1646: // else it is a field, method, or constructor jaroslav@1646: StringBuilder buf = new StringBuilder(); jaroslav@1646: if (getDeclaringClass() != null) { jaroslav@1646: buf.append(getName(clazz)); jaroslav@1646: buf.append('.'); jaroslav@1646: } jaroslav@1646: String name = getName(); jaroslav@1646: buf.append(name == null ? "*" : name); jaroslav@1646: Object type = getType(); jaroslav@1646: if (!isInvocable()) { jaroslav@1646: buf.append('/'); jaroslav@1646: buf.append(type == null ? "*" : getName(type)); jaroslav@1646: } else { jaroslav@1646: buf.append(type == null ? "(*)*" : getName(type)); jaroslav@1646: } jaroslav@1646: byte refKind = getReferenceKind(); jaroslav@1646: if (refKind != REF_NONE) { jaroslav@1646: buf.append('/'); jaroslav@1646: buf.append(MethodHandleNatives.refKindName(refKind)); jaroslav@1646: } jaroslav@1646: //buf.append("#").append(System.identityHashCode(this)); jaroslav@1646: return buf.toString(); jaroslav@1646: } jaroslav@1646: private static String getName(Object obj) { jaroslav@1646: if (obj instanceof Class) jaroslav@1646: return ((Class)obj).getName(); jaroslav@1646: return String.valueOf(obj); jaroslav@1646: } jaroslav@1646: jaroslav@1646: public IllegalAccessException makeAccessException(String message, Object from) { jaroslav@1646: message = message + ": "+ toString(); jaroslav@1646: if (from != null) message += ", from " + from; jaroslav@1646: return new IllegalAccessException(message); jaroslav@1646: } jaroslav@1646: private String message() { jaroslav@1646: if (isResolved()) jaroslav@1646: return "no access"; jaroslav@1646: else if (isConstructor()) jaroslav@1646: return "no such constructor"; jaroslav@1646: else if (isMethod()) jaroslav@1646: return "no such method"; jaroslav@1646: else jaroslav@1646: return "no such field"; jaroslav@1646: } jaroslav@1646: public ReflectiveOperationException makeAccessException() { jaroslav@1646: String message = message() + ": "+ toString(); jaroslav@1646: ReflectiveOperationException ex; jaroslav@1646: if (isResolved() || !(resolution instanceof NoSuchMethodError || jaroslav@1646: resolution instanceof NoSuchFieldError)) jaroslav@1646: ex = new IllegalAccessException(message); jaroslav@1646: else if (isConstructor()) jaroslav@1646: ex = new NoSuchMethodException(message); jaroslav@1646: else if (isMethod()) jaroslav@1646: ex = new NoSuchMethodException(message); jaroslav@1646: else jaroslav@1646: ex = new NoSuchFieldException(message); jaroslav@1646: if (resolution instanceof Throwable) jaroslav@1646: ex.initCause((Throwable) resolution); jaroslav@1646: return ex; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Actually making a query requires an access check. */ jaroslav@1646: /*non-public*/ static Factory getFactory() { jaroslav@1646: return Factory.INSTANCE; jaroslav@1646: } jaroslav@1646: /** A factory type for resolving member names with the help of the VM. jaroslav@1646: * TBD: Define access-safe public constructors for this factory. jaroslav@1646: */ jaroslav@1646: /*non-public*/ static class Factory { jaroslav@1646: private Factory() { } // singleton pattern jaroslav@1646: static Factory INSTANCE = new Factory(); jaroslav@1646: jaroslav@1646: private static int ALLOWED_FLAGS = ALL_KINDS; jaroslav@1646: jaroslav@1646: /// Queries jaroslav@1646: List getMembers(Class defc, jaroslav@1646: String matchName, Object matchType, jaroslav@1646: int matchFlags, Class lookupClass) { jaroslav@1646: matchFlags &= ALLOWED_FLAGS; jaroslav@1646: String matchSig = null; jaroslav@1646: if (matchType != null) { jaroslav@1646: matchSig = BytecodeDescriptor.unparse(matchType); jaroslav@1646: if (matchSig.startsWith("(")) jaroslav@1646: matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE); jaroslav@1646: else jaroslav@1646: matchFlags &= ~(ALL_KINDS & ~IS_FIELD); jaroslav@1646: } jaroslav@1646: final int BUF_MAX = 0x2000; jaroslav@1646: int len1 = matchName == null ? 10 : matchType == null ? 4 : 1; jaroslav@1646: MemberName[] buf = newMemberBuffer(len1); jaroslav@1646: int totalCount = 0; jaroslav@1646: ArrayList bufs = null; jaroslav@1646: int bufCount = 0; jaroslav@1646: for (;;) { jaroslav@1646: bufCount = MethodHandleNatives.getMembers(defc, jaroslav@1646: matchName, matchSig, matchFlags, jaroslav@1646: lookupClass, jaroslav@1646: totalCount, buf); jaroslav@1646: if (bufCount <= buf.length) { jaroslav@1646: if (bufCount < 0) bufCount = 0; jaroslav@1646: totalCount += bufCount; jaroslav@1646: break; jaroslav@1646: } jaroslav@1646: // JVM returned to us with an intentional overflow! jaroslav@1646: totalCount += buf.length; jaroslav@1646: int excess = bufCount - buf.length; jaroslav@1646: if (bufs == null) bufs = new ArrayList<>(1); jaroslav@1646: bufs.add(buf); jaroslav@1646: int len2 = buf.length; jaroslav@1646: len2 = Math.max(len2, excess); jaroslav@1646: len2 = Math.max(len2, totalCount / 4); jaroslav@1646: buf = newMemberBuffer(Math.min(BUF_MAX, len2)); jaroslav@1646: } jaroslav@1646: ArrayList result = new ArrayList<>(totalCount); jaroslav@1646: if (bufs != null) { jaroslav@1646: for (MemberName[] buf0 : bufs) { jaroslav@1646: Collections.addAll(result, buf0); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: result.addAll(Arrays.asList(buf).subList(0, bufCount)); jaroslav@1646: // Signature matching is not the same as type matching, since jaroslav@1646: // one signature might correspond to several types. jaroslav@1646: // So if matchType is a Class or MethodType, refilter the results. jaroslav@1646: if (matchType != null && matchType != matchSig) { jaroslav@1646: for (Iterator it = result.iterator(); it.hasNext();) { jaroslav@1646: MemberName m = it.next(); jaroslav@1646: if (!matchType.equals(m.getType())) jaroslav@1646: it.remove(); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: return result; jaroslav@1646: } jaroslav@1646: /** Produce a resolved version of the given member. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * If lookup fails or access is not permitted, null is returned. jaroslav@1646: * Otherwise a fresh copy of the given member is returned, with modifier bits filled in. jaroslav@1646: */ jaroslav@1646: private MemberName resolve(byte refKind, MemberName ref, Class lookupClass) { jaroslav@1646: MemberName m = ref.clone(); // JVM will side-effect the ref jaroslav@1646: assert(refKind == m.getReferenceKind()); jaroslav@1646: try { jaroslav@1646: m = MethodHandleNatives.resolve(m, lookupClass); jaroslav@1646: m.checkForTypeAlias(); jaroslav@1646: m.resolution = null; jaroslav@1646: } catch (LinkageError ex) { jaroslav@1646: // JVM reports that the "bytecode behavior" would get an error jaroslav@1646: assert(!m.isResolved()); jaroslav@1646: m.resolution = ex; jaroslav@1646: return m; jaroslav@1646: } jaroslav@1646: assert(m.referenceKindIsConsistent()); jaroslav@1646: m.initResolved(true); jaroslav@1646: assert(m.vminfoIsConsistent()); jaroslav@1646: return m; jaroslav@1646: } jaroslav@1646: /** Produce a resolved version of the given member. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown. jaroslav@1646: * Otherwise a fresh copy of the given member is returned, with modifier bits filled in. jaroslav@1646: */ jaroslav@1646: public jaroslav@1646: jaroslav@1646: MemberName resolveOrFail(byte refKind, MemberName m, Class lookupClass, jaroslav@1646: Class nsmClass) jaroslav@1646: throws IllegalAccessException, NoSuchMemberException { jaroslav@1646: MemberName result = resolve(refKind, m, lookupClass); jaroslav@1646: if (result.isResolved()) jaroslav@1646: return result; jaroslav@1646: ReflectiveOperationException ex = result.makeAccessException(); jaroslav@1646: if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex; jaroslav@1646: throw nsmClass.cast(ex); jaroslav@1646: } jaroslav@1646: /** Produce a resolved version of the given member. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * If lookup fails or access is not permitted, return null. jaroslav@1646: * Otherwise a fresh copy of the given member is returned, with modifier bits filled in. jaroslav@1646: */ jaroslav@1646: public jaroslav@1646: MemberName resolveOrNull(byte refKind, MemberName m, Class lookupClass) { jaroslav@1646: MemberName result = resolve(refKind, m, lookupClass); jaroslav@1646: if (result.isResolved()) jaroslav@1646: return result; jaroslav@1646: return null; jaroslav@1646: } jaroslav@1646: /** Return a list of all methods defined by the given class. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * Inaccessible members are not added to the last. jaroslav@1646: */ jaroslav@1646: public List getMethods(Class defc, boolean searchSupers, jaroslav@1646: Class lookupClass) { jaroslav@1646: return getMethods(defc, searchSupers, null, null, lookupClass); jaroslav@1646: } jaroslav@1646: /** Return a list of matching methods defined by the given class. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Returned methods will match the name (if not null) and the type (if not null). jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * Inaccessible members are not added to the last. jaroslav@1646: */ jaroslav@1646: public List getMethods(Class defc, boolean searchSupers, jaroslav@1646: String name, MethodType type, Class lookupClass) { jaroslav@1646: int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0); jaroslav@1646: return getMembers(defc, name, type, matchFlags, lookupClass); jaroslav@1646: } jaroslav@1646: /** Return a list of all constructors defined by the given class. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * Inaccessible members are not added to the last. jaroslav@1646: */ jaroslav@1646: public List getConstructors(Class defc, Class lookupClass) { jaroslav@1646: return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass); jaroslav@1646: } jaroslav@1646: /** Return a list of all fields defined by the given class. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * Inaccessible members are not added to the last. jaroslav@1646: */ jaroslav@1646: public List getFields(Class defc, boolean searchSupers, jaroslav@1646: Class lookupClass) { jaroslav@1646: return getFields(defc, searchSupers, null, null, lookupClass); jaroslav@1646: } jaroslav@1646: /** Return a list of all fields defined by the given class. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Returned fields will match the name (if not null) and the type (if not null). jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * Inaccessible members are not added to the last. jaroslav@1646: */ jaroslav@1646: public List getFields(Class defc, boolean searchSupers, jaroslav@1646: String name, Class type, Class lookupClass) { jaroslav@1646: int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0); jaroslav@1646: return getMembers(defc, name, type, matchFlags, lookupClass); jaroslav@1646: } jaroslav@1646: /** Return a list of all nested types defined by the given class. jaroslav@1646: * Super types are searched (for inherited members) if {@code searchSupers} is true. jaroslav@1646: * Access checking is performed on behalf of the given {@code lookupClass}. jaroslav@1646: * Inaccessible members are not added to the last. jaroslav@1646: */ jaroslav@1646: public List getNestedTypes(Class defc, boolean searchSupers, jaroslav@1646: Class lookupClass) { jaroslav@1646: int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0); jaroslav@1646: return getMembers(defc, null, null, matchFlags, lookupClass); jaroslav@1646: } jaroslav@1646: private static MemberName[] newMemberBuffer(int length) { jaroslav@1646: MemberName[] buf = new MemberName[length]; jaroslav@1646: // fill the buffer with dummy structs for the JVM to fill in jaroslav@1646: for (int i = 0; i < length; i++) jaroslav@1646: buf[i] = new MemberName(); jaroslav@1646: return buf; jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: // static { jaroslav@1646: // System.out.println("Hello world! My methods are:"); jaroslav@1646: // System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null)); jaroslav@1646: // } jaroslav@1646: }