< prev index next > src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Print this page
*/
package java.lang.invoke;
import jdk.internal.access.SharedSecrets;
+ import jdk.internal.value.PrimitiveClass;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.org.objectweb.asm.ClassReader;
* the current class. Again, this requirement is enforced by narrowing the
* type of the leading parameter to the resulting method handle.
* (See the Java Virtual Machine Specification, section {@jvms 4.10.1.9}.)
* <p>
* The JVM represents constructors and static initializer blocks as internal methods
! * with special names ({@value ConstantDescs#INIT_NAME} and {@value
! * ConstantDescs#CLASS_INIT_NAME}).
* The internal syntax of invocation instructions allows them to refer to such internal
* methods as if they were normal methods, but the JVM bytecode verifier rejects them.
* A lookup of such an internal method will produce a {@code NoSuchMethodException}.
* <p>
* If the relationship between nested types is expressed directly through the
* the current class. Again, this requirement is enforced by narrowing the
* type of the leading parameter to the resulting method handle.
* (See the Java Virtual Machine Specification, section {@jvms 4.10.1.9}.)
* <p>
* The JVM represents constructors and static initializer blocks as internal methods
! * with special names ({@value ConstantDescs#INIT_NAME},
! * {@value ConstantDescs#VNEW_NAME} and {@value ConstantDescs#CLASS_INIT_NAME}).
* The internal syntax of invocation instructions allows them to refer to such internal
* methods as if they were normal methods, but the JVM bytecode verifier rejects them.
* A lookup of such an internal method will produce a {@code NoSuchMethodException}.
* <p>
* If the relationship between nested types is expressed directly through the
Lookup(Class<?> lookupClass) {
this(lookupClass, null, FULL_POWER_MODES);
}
private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
+ assert PrimitiveClass.isPrimaryType(lookupClass);
assert prevLookupClass == null || ((allowedModes & MODULE) == 0
&& prevLookupClass.getModule() != lookupClass.getModule());
assert !lookupClass.isArray() && !lookupClass.isPrimitive();
this.lookupClass = lookupClass;
this.prevLookupClass = prevLookupClass;
ProcessBuilder.class, methodType(void.class, String[].class));
ProcessBuilder pb = (ProcessBuilder)
MH_newProcessBuilder.invoke("x", "y", "z");
assertEquals("[x, y, z]", pb.command().toString());
* }
+ *
+ *
* @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle
* @throws NoSuchMethodException if the constructor does not exist
* @throws IllegalAccessException if access checking fails
*/
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
if (refc.isArray()) {
throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
}
+ if (type.returnType() != void.class) {
+ throw new NoSuchMethodException("Constructors must have void return type: " + refc.getName());
+ }
String name = ConstantDescs.INIT_NAME;
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
return getDirectConstructor(refc, ctor);
}
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
MemberName ctor = new MemberName(c);
! assert(ctor.isConstructor());
@SuppressWarnings("deprecation")
Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
! return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
}
/**
* Produces a method handle giving read access to a reflected field.
* The type of the method handle will have a return type of the field's
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
MemberName ctor = new MemberName(c);
! assert(ctor.isObjectConstructor() || ctor.isStaticValueFactoryMethod());
@SuppressWarnings("deprecation")
Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
! Class<?> defc = c.getDeclaringClass();
+ if (ctor.isObjectConstructor()) {
+ assert(ctor.getMethodType().returnType() == void.class);
+ return lookup.getDirectConstructorNoSecurityManager(defc, ctor);
+ } else {
+ // static init factory is a static method
+ assert(ctor.isMethod() && ctor.getMethodType().returnType() == defc && ctor.getReferenceKind() == REF_invokeStatic) : ctor.toString();
+ assert(!MethodHandleNatives.isCallerSensitive(ctor)); // must not be caller-sensitive
+ return lookup.getDirectMethodNoSecurityManager(ctor.getReferenceKind(), defc, ctor, lookup);
+ }
}
/**
* Produces a method handle giving read access to a reflected field.
* The type of the method handle will have a return type of the field's
if (!isClassAccessible(refc)) {
return null;
}
Objects.requireNonNull(type);
// implicit null-check of name
! if (name.startsWith("<") && refKind != REF_newInvokeSpecial) {
return null;
}
return IMPL_NAMES.resolveOrNull(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes);
}
void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
if (!isClassAccessible(refc)) {
if (!isClassAccessible(refc)) {
return null;
}
Objects.requireNonNull(type);
// implicit null-check of name
! if (isIllegalMethodName(refKind, name)) {
return null;
}
+
return IMPL_NAMES.resolveOrNull(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes);
}
void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
if (!isClassAccessible(refc)) {
type = type.getComponentType();
}
return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
}
/** Check name for an illegal leading "<" character. */
void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
! if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
! throw new NoSuchMethodException("illegal method name: "+name);
}
/**
* Find my trustable caller class if m is a caller sensitive method.
* If this lookup object has original full privilege access, then the caller class is the lookupClass.
type = type.getComponentType();
}
return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
}
+ /*
+ * "<init>" can only be invoked via invokespecial
+ * "<vnew>" factory can only invoked via invokestatic
+ */
+ boolean isIllegalMethodName(byte refKind, String name) {
+ if (name.startsWith("<")) {
+ return MemberName.VALUE_FACTORY_NAME.equals(name) ? refKind != REF_invokeStatic
+ : refKind != REF_newInvokeSpecial;
+ }
+ return false;
+ }
+
/** Check name for an illegal leading "<" character. */
void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
! if (isIllegalMethodName(refKind, name)) {
! throw new NoSuchMethodException("illegal method name: " + name + " " + refKind);
+ }
}
/**
* Find my trustable caller class if m is a caller sensitive method.
* If this lookup object has original full privilege access, then the caller class is the lookupClass.
smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
// Step 3:
Class<?> defc = m.getDeclaringClass();
! if (!fullPrivilegeLookup && defc != refc) {
ReflectUtil.checkPackageAccess(defc);
}
}
void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
boolean wantStatic = (refKind == REF_invokeStatic);
String message;
! if (m.isConstructor())
message = "expected a method, not a constructor";
else if (!m.isMethod())
message = "expected a method";
else if (wantStatic != m.isStatic())
message = wantStatic ? "expected a static method" : "expected a non-static method";
smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
// Step 3:
Class<?> defc = m.getDeclaringClass();
! if (!fullPrivilegeLookup && PrimitiveClass.asPrimaryType(defc) != PrimitiveClass.asPrimaryType(refc)) {
ReflectUtil.checkPackageAccess(defc);
}
}
void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
boolean wantStatic = (refKind == REF_invokeStatic);
String message;
! if (m.isObjectConstructor())
message = "expected a method, not a constructor";
else if (!m.isMethod())
message = "expected a method";
else if (wantStatic != m.isStatic())
message = wantStatic ? "expected a static method" : "expected a non-static method";
String accessFailedMessage(Class<?> refc, MemberName m) {
Class<?> defc = m.getDeclaringClass();
int mods = m.getModifiers();
// check the class first:
boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
! (defc == refc ||
Modifier.isPublic(refc.getModifiers())));
if (!classOK && (allowedModes & PACKAGE) != 0) {
// ignore previous lookup class to check if default package access
classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
! (defc == refc ||
VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
}
if (!classOK)
return "class is not public";
if (Modifier.isPublic(mods))
String accessFailedMessage(Class<?> refc, MemberName m) {
Class<?> defc = m.getDeclaringClass();
int mods = m.getModifiers();
// check the class first:
boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
! (PrimitiveClass.asPrimaryType(defc) == PrimitiveClass.asPrimaryType(refc) ||
Modifier.isPublic(refc.getModifiers())));
if (!classOK && (allowedModes & PACKAGE) != 0) {
// ignore previous lookup class to check if default package access
classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
! (PrimitiveClass.asPrimaryType(defc) == PrimitiveClass.asPrimaryType(refc) ||
VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
}
if (!classOK)
return "class is not public";
if (Modifier.isPublic(mods))
checkMethod(refKind, refc, method);
// Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity)
checkSecurityManager(refc, method);
assert(!method.isMethodHandleInvoke());
-
if (refKind == REF_invokeSpecial &&
refc != lookupClass() &&
!refc.isInterface() && !lookupClass().isInterface() &&
refc != lookupClass().getSuperclass() &&
refc.isAssignableFrom(lookupClass())) {
return getDirectConstructorCommon(refc, ctor, checkSecurity);
}
/** Common code for all constructors; do not call directly except from immediately above. */
private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
boolean checkSecurity) throws IllegalAccessException {
! assert(ctor.isConstructor());
checkAccess(REF_newInvokeSpecial, refc, ctor);
// Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity)
checkSecurityManager(refc, ctor);
assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here
return getDirectConstructorCommon(refc, ctor, checkSecurity);
}
/** Common code for all constructors; do not call directly except from immediately above. */
private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
boolean checkSecurity) throws IllegalAccessException {
! assert(ctor.isObjectConstructor());
checkAccess(REF_newInvokeSpecial, refc, ctor);
// Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity)
checkSecurityManager(refc, ctor);
assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here
value = w.convert(value, type);
if (w.zero().equals(value))
return zero(w, type);
return insertArguments(identity(type), 0, value);
} else {
! if (value == null)
return zero(Wrapper.OBJECT, type);
return identity(type).bindTo(value);
}
}
value = w.convert(value, type);
if (w.zero().equals(value))
return zero(w, type);
return insertArguments(identity(type), 0, value);
} else {
! if (!PrimitiveClass.isPrimitiveValueType(type) && value == null)
return zero(Wrapper.OBJECT, type);
return identity(type).bindTo(value);
}
}
* @see MethodHandles#explicitCastArguments
* @since 9
*/
public static MethodHandle zero(Class<?> type) {
Objects.requireNonNull(type);
! return type.isPrimitive() ? zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
}
private static MethodHandle identityOrVoid(Class<?> type) {
return type == void.class ? zero(type) : identity(type);
}
* @see MethodHandles#explicitCastArguments
* @since 9
*/
public static MethodHandle zero(Class<?> type) {
Objects.requireNonNull(type);
! if (type.isPrimitive()) {
+ return zero(Wrapper.forPrimitiveType(type), type);
+ } else if (PrimitiveClass.isPrimitiveValueType(type)) {
+ // singleton default value
+ Object value = UNSAFE.uninitializedDefaultValue(type);
+ return identity(type).bindTo(value);
+ } else {
+ return zero(Wrapper.OBJECT, type);
+ }
}
private static MethodHandle identityOrVoid(Class<?> type) {
return type == void.class ? zero(type) : identity(type);
}
return dropArgumentsTrusted(zero(type.returnType()), 0, type.ptypes());
}
private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
private static MethodHandle makeIdentity(Class<?> ptype) {
! MethodType mtype = methodType(ptype, ptype);
LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
}
private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
return dropArgumentsTrusted(zero(type.returnType()), 0, type.ptypes());
}
private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
private static MethodHandle makeIdentity(Class<?> ptype) {
! MethodType mtype = MethodType.methodType(ptype, ptype);
LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
}
private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
< prev index next >