mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8298177: Various java.lang.invoke cleanups
8284363: Redundant imports in BoundMethodHandle Reviewed-by: jvernee
This commit is contained in:
parent
6ed36835ec
commit
3de775094d
11 changed files with 80 additions and 375 deletions
|
@ -25,7 +25,6 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import sun.invoke.util.BytecodeDescriptor;
|
||||
import sun.invoke.util.VerifyAccess;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
@ -33,10 +32,6 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
|
@ -74,7 +69,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
|||
final class ResolvedMethodName {
|
||||
//@Injected JVM_Method* vmtarget;
|
||||
//@Injected Class<?> vmholder;
|
||||
};
|
||||
}
|
||||
|
||||
/*non-public*/
|
||||
final class MemberName implements Member, Cloneable {
|
||||
|
@ -198,16 +193,6 @@ final class MemberName implements Member, Cloneable {
|
|||
return itype;
|
||||
}
|
||||
|
||||
/** Utility method producing the parameter types of the method type. */
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return getMethodType().parameterArray();
|
||||
}
|
||||
|
||||
/** Utility method producing the return type of the method type. */
|
||||
public Class<?> getReturnType() {
|
||||
return getMethodType().returnType();
|
||||
}
|
||||
|
||||
/** Return the declared type of this member, which
|
||||
* must be a field or type.
|
||||
* If it is a type member, that type itself is returned.
|
||||
|
@ -249,22 +234,6 @@ final class MemberName implements Member, Cloneable {
|
|||
return (isInvocable() ? getMethodType() : getFieldType());
|
||||
}
|
||||
|
||||
/** Utility method to produce the signature of this member,
|
||||
* used within the class file format to describe its type.
|
||||
*/
|
||||
public String getSignature() {
|
||||
if (type == null) {
|
||||
expandFromVM();
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (isInvocable())
|
||||
return BytecodeDescriptor.unparse(getMethodType());
|
||||
else
|
||||
return BytecodeDescriptor.unparse(getFieldType());
|
||||
}
|
||||
|
||||
/** Return the modifier flags of this member.
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
|
@ -356,20 +325,19 @@ final class MemberName implements Member, Cloneable {
|
|||
}
|
||||
|
||||
private MemberName changeReferenceKind(byte refKind, byte oldKind) {
|
||||
assert(getReferenceKind() == oldKind);
|
||||
assert(MethodHandleNatives.refKindIsValid(refKind));
|
||||
assert(getReferenceKind() == oldKind && MethodHandleNatives.refKindIsValid(refKind));
|
||||
flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean testFlags(int mask, int value) {
|
||||
return (flags & mask) == value;
|
||||
private boolean matchingFlagsSet(int mask, int flags) {
|
||||
return (this.flags & mask) == flags;
|
||||
}
|
||||
private boolean testAllFlags(int mask) {
|
||||
return testFlags(mask, mask);
|
||||
private boolean allFlagsSet(int flags) {
|
||||
return (this.flags & flags) == flags;
|
||||
}
|
||||
private boolean testAnyFlags(int mask) {
|
||||
return !testFlags(mask, 0);
|
||||
private boolean anyFlagSet(int flags) {
|
||||
return (this.flags & flags) != 0;
|
||||
}
|
||||
|
||||
/** Utility method to query if this member is a method handle invocation (invoke or invokeExact).
|
||||
|
@ -377,26 +345,21 @@ final class MemberName implements Member, Cloneable {
|
|||
public boolean isMethodHandleInvoke() {
|
||||
final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
|
||||
final int negs = Modifier.STATIC;
|
||||
if (testFlags(bits | negs, bits) &&
|
||||
clazz == MethodHandle.class) {
|
||||
if (matchingFlagsSet(bits | negs, bits) && clazz == MethodHandle.class) {
|
||||
return isMethodHandleInvokeName(name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static boolean isMethodHandleInvokeName(String name) {
|
||||
switch (name) {
|
||||
case "invoke":
|
||||
case "invokeExact":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return switch (name) {
|
||||
case "invoke", "invokeExact" -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
public boolean isVarHandleMethodInvoke() {
|
||||
final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
|
||||
final int negs = Modifier.STATIC;
|
||||
if (testFlags(bits | negs, bits) &&
|
||||
clazz == VarHandle.class) {
|
||||
if (matchingFlagsSet(bits | negs, bits) && clazz == VarHandle.class) {
|
||||
return isVarHandleMethodInvokeName(name);
|
||||
}
|
||||
return false;
|
||||
|
@ -457,15 +420,15 @@ final class MemberName implements Member, Cloneable {
|
|||
static final int ENUM = 0x00004000;
|
||||
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
|
||||
public boolean isBridge() {
|
||||
return testAllFlags(IS_METHOD | BRIDGE);
|
||||
return allFlagsSet(IS_METHOD | BRIDGE);
|
||||
}
|
||||
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
|
||||
public boolean isVarargs() {
|
||||
return testAllFlags(VARARGS) && isInvocable();
|
||||
return allFlagsSet(VARARGS) && isInvocable();
|
||||
}
|
||||
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
|
||||
public boolean isSynthetic() {
|
||||
return testAllFlags(SYNTHETIC);
|
||||
return allFlagsSet(SYNTHETIC);
|
||||
}
|
||||
|
||||
static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
|
||||
|
@ -485,49 +448,38 @@ final class MemberName implements Member, Cloneable {
|
|||
static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
|
||||
static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
|
||||
static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
|
||||
static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
|
||||
static final int SEARCH_ALL_SUPERS = MN_SEARCH_SUPERCLASSES | MN_SEARCH_INTERFACES;
|
||||
|
||||
/** Utility method to query whether this member is a method or constructor. */
|
||||
public boolean isInvocable() {
|
||||
return testAnyFlags(IS_INVOCABLE);
|
||||
}
|
||||
/** Utility method to query whether this member is a method, constructor, or field. */
|
||||
public boolean isFieldOrMethod() {
|
||||
return testAnyFlags(IS_FIELD_OR_METHOD);
|
||||
return anyFlagSet(IS_INVOCABLE);
|
||||
}
|
||||
/** Query whether this member is a method. */
|
||||
public boolean isMethod() {
|
||||
return testAllFlags(IS_METHOD);
|
||||
return allFlagsSet(IS_METHOD);
|
||||
}
|
||||
/** Query whether this member is a constructor. */
|
||||
public boolean isConstructor() {
|
||||
return testAllFlags(IS_CONSTRUCTOR);
|
||||
return allFlagsSet(IS_CONSTRUCTOR);
|
||||
}
|
||||
/** Query whether this member is a field. */
|
||||
public boolean isField() {
|
||||
return testAllFlags(IS_FIELD);
|
||||
return allFlagsSet(IS_FIELD);
|
||||
}
|
||||
/** Query whether this member is a type. */
|
||||
public boolean isType() {
|
||||
return testAllFlags(IS_TYPE);
|
||||
return allFlagsSet(IS_TYPE);
|
||||
}
|
||||
/** Utility method to query whether this member is neither public, private, nor protected. */
|
||||
public boolean isPackage() {
|
||||
return !testAnyFlags(ALL_ACCESS);
|
||||
return !anyFlagSet(ALL_ACCESS);
|
||||
}
|
||||
/** Query whether this member has a CallerSensitive annotation. */
|
||||
public boolean isCallerSensitive() {
|
||||
return testAllFlags(CALLER_SENSITIVE);
|
||||
return allFlagsSet(CALLER_SENSITIVE);
|
||||
}
|
||||
/** Query whether this member is a trusted final field. */
|
||||
public boolean isTrustedFinalField() { return testAllFlags(TRUSTED_FINAL|IS_FIELD); }
|
||||
|
||||
/** Utility method to query whether this member is accessible from a given lookup class. */
|
||||
public boolean isAccessibleFrom(Class<?> lookupClass) {
|
||||
int mode = (ALL_ACCESS|MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.MODULE);
|
||||
return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
|
||||
lookupClass, null, mode);
|
||||
public boolean isTrustedFinalField() {
|
||||
return allFlagsSet(TRUSTED_FINAL | IS_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -547,8 +499,7 @@ final class MemberName implements Member, Cloneable {
|
|||
this.name = name;
|
||||
this.type = type;
|
||||
this.flags = flags;
|
||||
assert(testAnyFlags(ALL_KINDS));
|
||||
assert(this.resolution == null); // nobody should have touched this yet
|
||||
assert(anyFlagSet(ALL_KINDS) && this.resolution == null); // nobody should have touched this yet
|
||||
//assert(referenceKindIsConsistent()); // do this after resolution
|
||||
}
|
||||
|
||||
|
@ -568,9 +519,9 @@ final class MemberName implements Member, Cloneable {
|
|||
|
||||
// Capturing information from the Core Reflection API:
|
||||
private static int flagsMods(int flags, int mods, byte refKind) {
|
||||
assert((flags & RECOGNIZED_MODIFIERS) == 0);
|
||||
assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
|
||||
assert((refKind & ~MN_REFERENCE_KIND_MASK) == 0);
|
||||
assert((flags & RECOGNIZED_MODIFIERS) == 0
|
||||
&& (mods & ~RECOGNIZED_MODIFIERS) == 0
|
||||
&& (refKind & ~MN_REFERENCE_KIND_MASK) == 0);
|
||||
return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
|
||||
}
|
||||
/** Create a name for the given reflected method. The resulting name will be in a resolved state. */
|
||||
|
@ -607,7 +558,7 @@ final class MemberName implements Member, Cloneable {
|
|||
}
|
||||
throw new LinkageError(m.toString());
|
||||
}
|
||||
assert(isResolved() && this.clazz != null);
|
||||
assert(isResolved());
|
||||
this.name = m.getName();
|
||||
if (this.type == null)
|
||||
this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
|
||||
|
@ -649,20 +600,16 @@ final class MemberName implements Member, Cloneable {
|
|||
* undoes that change under the assumption that it occurred.)
|
||||
*/
|
||||
public MemberName asNormalOriginal() {
|
||||
byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
|
||||
byte refKind = getReferenceKind();
|
||||
byte newRefKind = refKind;
|
||||
MemberName result = this;
|
||||
switch (refKind) {
|
||||
case REF_invokeInterface:
|
||||
case REF_invokeVirtual:
|
||||
case REF_invokeSpecial:
|
||||
newRefKind = normalVirtual;
|
||||
break;
|
||||
}
|
||||
byte newRefKind = switch (refKind) {
|
||||
case REF_invokeInterface,
|
||||
REF_invokeVirtual,
|
||||
REF_invokeSpecial -> clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
|
||||
default -> refKind;
|
||||
};
|
||||
if (newRefKind == refKind)
|
||||
return this;
|
||||
result = clone().changeReferenceKind(newRefKind, refKind);
|
||||
MemberName result = clone().changeReferenceKind(newRefKind, refKind);
|
||||
assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
|
||||
return result;
|
||||
}
|
||||
|
@ -682,6 +629,10 @@ final class MemberName implements Member, Cloneable {
|
|||
public MemberName(Field fld) {
|
||||
this(fld, false);
|
||||
}
|
||||
static {
|
||||
// the following MemberName constructor relies on these ranges matching up
|
||||
assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
|
||||
}
|
||||
@SuppressWarnings("LeakingThisInConstructor")
|
||||
public MemberName(Field fld, boolean makeSetter) {
|
||||
Objects.requireNonNull(fld);
|
||||
|
@ -690,7 +641,6 @@ final class MemberName implements Member, Cloneable {
|
|||
assert(isResolved() && this.clazz != null);
|
||||
this.name = fld.getName();
|
||||
this.type = fld.getType();
|
||||
assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
|
||||
byte refKind = this.getReferenceKind();
|
||||
assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
|
||||
if (makeSetter) {
|
||||
|
@ -703,13 +653,7 @@ final class MemberName implements Member, Cloneable {
|
|||
public boolean isSetter() {
|
||||
return MethodHandleNatives.refKindIsSetter(getReferenceKind());
|
||||
}
|
||||
public MemberName asSetter() {
|
||||
byte refKind = getReferenceKind();
|
||||
assert(MethodHandleNatives.refKindIsGetter(refKind));
|
||||
assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
|
||||
byte setterRefKind = (byte)(refKind + (REF_putField - REF_getField));
|
||||
return clone().changeReferenceKind(setterRefKind, refKind);
|
||||
}
|
||||
|
||||
/** Create a name for the given class. The resulting name will be in a resolved state. */
|
||||
public MemberName(Class<?> type) {
|
||||
init(type.getDeclaringClass(), type.getSimpleName(), type,
|
||||
|
@ -844,11 +788,6 @@ final class MemberName implements Member, Cloneable {
|
|||
init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
|
||||
initResolved(false);
|
||||
}
|
||||
/** Query whether this member name is resolved to a non-static, non-final method.
|
||||
*/
|
||||
public boolean hasReceiverTypeDispatch() {
|
||||
return MethodHandleNatives.refKindDoesDispatch(getReferenceKind());
|
||||
}
|
||||
|
||||
/** Query whether this member name is resolved.
|
||||
* A resolved member name is one for which the JVM has found
|
||||
|
@ -930,7 +869,7 @@ final class MemberName implements Member, Cloneable {
|
|||
}
|
||||
|
||||
public IllegalAccessException makeAccessException(String message, Object from) {
|
||||
message = message + ": "+ toString();
|
||||
message = message + ": " + this;
|
||||
if (from != null) {
|
||||
if (from == MethodHandles.publicLookup()) {
|
||||
message += ", from public Lookup";
|
||||
|
@ -965,7 +904,7 @@ final class MemberName implements Member, Cloneable {
|
|||
return "no such field";
|
||||
}
|
||||
public ReflectiveOperationException makeAccessException() {
|
||||
String message = message() + ": "+ toString();
|
||||
String message = message() + ": " + this;
|
||||
ReflectiveOperationException ex;
|
||||
if (isResolved() || !(resolution instanceof NoSuchMethodError ||
|
||||
resolution instanceof NoSuchFieldError))
|
||||
|
@ -992,70 +931,8 @@ final class MemberName implements Member, Cloneable {
|
|||
/*non-public*/
|
||||
static class Factory {
|
||||
private Factory() { } // singleton pattern
|
||||
static Factory INSTANCE = new Factory();
|
||||
static final Factory INSTANCE = new Factory();
|
||||
|
||||
private static int ALLOWED_FLAGS = ALL_KINDS;
|
||||
|
||||
/// Queries
|
||||
List<MemberName> getMembers(Class<?> defc,
|
||||
String matchName, Object matchType,
|
||||
int matchFlags, Class<?> lookupClass) {
|
||||
matchFlags &= ALLOWED_FLAGS;
|
||||
String matchSig = null;
|
||||
if (matchType != null) {
|
||||
matchSig = BytecodeDescriptor.unparse(matchType);
|
||||
if (matchSig.startsWith("("))
|
||||
matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
|
||||
else
|
||||
matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
|
||||
}
|
||||
final int BUF_MAX = 0x2000;
|
||||
int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
|
||||
MemberName[] buf = newMemberBuffer(len1);
|
||||
int totalCount = 0;
|
||||
ArrayList<MemberName[]> bufs = null;
|
||||
int bufCount = 0;
|
||||
for (;;) {
|
||||
bufCount = MethodHandleNatives.getMembers(defc,
|
||||
matchName, matchSig, matchFlags,
|
||||
lookupClass,
|
||||
totalCount, buf);
|
||||
if (bufCount <= buf.length) {
|
||||
if (bufCount < 0) bufCount = 0;
|
||||
totalCount += bufCount;
|
||||
break;
|
||||
}
|
||||
// JVM returned to us with an intentional overflow!
|
||||
totalCount += buf.length;
|
||||
int excess = bufCount - buf.length;
|
||||
if (bufs == null) bufs = new ArrayList<>(1);
|
||||
bufs.add(buf);
|
||||
int len2 = buf.length;
|
||||
len2 = Math.max(len2, excess);
|
||||
len2 = Math.max(len2, totalCount / 4);
|
||||
buf = newMemberBuffer(Math.min(BUF_MAX, len2));
|
||||
}
|
||||
ArrayList<MemberName> result = new ArrayList<>(totalCount);
|
||||
if (bufs != null) {
|
||||
for (MemberName[] buf0 : bufs) {
|
||||
Collections.addAll(result, buf0);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < bufCount; i++) {
|
||||
result.add(buf[i]);
|
||||
}
|
||||
// Signature matching is not the same as type matching, since
|
||||
// one signature might correspond to several types.
|
||||
// So if matchType is a Class or MethodType, refilter the results.
|
||||
if (matchType != null && matchType != matchSig) {
|
||||
for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
|
||||
MemberName m = it.next();
|
||||
if (!matchType.equals(m.getType()))
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/** Produce a resolved version of the given member.
|
||||
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
|
@ -1131,69 +1008,5 @@ final class MemberName implements Member, Cloneable {
|
|||
return result;
|
||||
return null;
|
||||
}
|
||||
/** Return a list of all methods defined by the given class.
|
||||
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
* Inaccessible members are not added to the last.
|
||||
*/
|
||||
public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
|
||||
Class<?> lookupClass) {
|
||||
return getMethods(defc, searchSupers, null, null, lookupClass);
|
||||
}
|
||||
/** Return a list of matching methods defined by the given class.
|
||||
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
||||
* Returned methods will match the name (if not null) and the type (if not null).
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
* Inaccessible members are not added to the last.
|
||||
*/
|
||||
public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
|
||||
String name, MethodType type, Class<?> lookupClass) {
|
||||
int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
|
||||
return getMembers(defc, name, type, matchFlags, lookupClass);
|
||||
}
|
||||
/** Return a list of all constructors defined by the given class.
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
* Inaccessible members are not added to the last.
|
||||
*/
|
||||
public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
|
||||
return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
|
||||
}
|
||||
/** Return a list of all fields defined by the given class.
|
||||
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
* Inaccessible members are not added to the last.
|
||||
*/
|
||||
public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
|
||||
Class<?> lookupClass) {
|
||||
return getFields(defc, searchSupers, null, null, lookupClass);
|
||||
}
|
||||
/** Return a list of all fields defined by the given class.
|
||||
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
||||
* Returned fields will match the name (if not null) and the type (if not null).
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
* Inaccessible members are not added to the last.
|
||||
*/
|
||||
public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
|
||||
String name, Class<?> type, Class<?> lookupClass) {
|
||||
int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
|
||||
return getMembers(defc, name, type, matchFlags, lookupClass);
|
||||
}
|
||||
/** Return a list of all nested types defined by the given class.
|
||||
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
||||
* Access checking is performed on behalf of the given {@code lookupClass}.
|
||||
* Inaccessible members are not added to the last.
|
||||
*/
|
||||
public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
|
||||
Class<?> lookupClass) {
|
||||
int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
|
||||
return getMembers(defc, null, null, matchFlags, lookupClass);
|
||||
}
|
||||
private static MemberName[] newMemberBuffer(int length) {
|
||||
MemberName[] buf = new MemberName[length];
|
||||
// fill the buffer with dummy structs for the JVM to fill in
|
||||
for (int i = 0; i < length; i++)
|
||||
buf[i] = new MemberName();
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue