200 lines
7.3 KiB
Java
200 lines
7.3 KiB
Java
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. The Android Open Source
|
|
* Project designates this particular file as subject to the "Classpath"
|
|
* exception as provided by The Android Open Source Project in the LICENSE
|
|
* file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
package java.lang.invoke;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.Member;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Modifier;
|
|
|
|
// Android-changed: Android specific implementation.
|
|
// The whole class was implemented from scratch for the Android runtime based
|
|
// on the specification of the MethodHandle class.
|
|
// The code does not originate from upstream OpenJDK.
|
|
/**
|
|
* A method handle that's directly associated with an ArtField or an ArtMethod and
|
|
* specifies no additional transformations.
|
|
*
|
|
* @hide
|
|
*/
|
|
public class MethodHandleImpl extends MethodHandle implements Cloneable {
|
|
private HandleInfo info;
|
|
|
|
MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
|
|
super(artFieldOrMethod, handleKind, type);
|
|
}
|
|
|
|
@Override
|
|
public Object clone() throws CloneNotSupportedException {
|
|
return super.clone();
|
|
}
|
|
|
|
MethodHandleInfo reveal() {
|
|
if (info == null) {
|
|
final Member member = getMemberInternal();
|
|
info = new HandleInfo(member, this);
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
/**
|
|
* Materialize a member from this method handle's ArtField or ArtMethod pointer.
|
|
*/
|
|
public native Member getMemberInternal();
|
|
|
|
/**
|
|
* Implementation of {@code MethodHandleInfo} in terms of the handle being cracked
|
|
* and its corresponding {@code java.lang.reflect.Member}.
|
|
*/
|
|
static class HandleInfo implements MethodHandleInfo {
|
|
private final Member member;
|
|
private final MethodHandle handle;
|
|
|
|
HandleInfo(Member member, MethodHandle handle) {
|
|
this.member = member;
|
|
this.handle = handle;
|
|
}
|
|
|
|
@Override
|
|
public int getReferenceKind() {
|
|
switch (handle.getHandleKind()) {
|
|
case INVOKE_VIRTUAL: {
|
|
if (member.getDeclaringClass().isInterface()) {
|
|
return REF_invokeInterface;
|
|
} else {
|
|
return REF_invokeVirtual;
|
|
}
|
|
}
|
|
|
|
case INVOKE_DIRECT: {
|
|
if (member instanceof Constructor) {
|
|
return REF_newInvokeSpecial;
|
|
} else {
|
|
return REF_invokeSpecial;
|
|
}
|
|
}
|
|
|
|
case INVOKE_SUPER:
|
|
return MethodHandleInfo.REF_invokeSpecial;
|
|
case INVOKE_STATIC:
|
|
return MethodHandleInfo.REF_invokeStatic;
|
|
case IGET:
|
|
return MethodHandleInfo.REF_getField;
|
|
case IPUT:
|
|
return MethodHandleInfo.REF_putField;
|
|
case SGET:
|
|
return MethodHandleInfo.REF_getStatic;
|
|
case SPUT:
|
|
return MethodHandleInfo.REF_putStatic;
|
|
default:
|
|
throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Class<?> getDeclaringClass() {
|
|
return member.getDeclaringClass();
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
if (member instanceof Constructor) {
|
|
return "<init>";
|
|
}
|
|
|
|
return member.getName();
|
|
}
|
|
|
|
@Override
|
|
public MethodType getMethodType() {
|
|
// The "nominal" type of a cracked method handle is the same as the type
|
|
// of the handle itself, except in the cases enumerated below.
|
|
MethodType handleType = handle.type();
|
|
|
|
boolean omitLeadingParam = false;
|
|
|
|
// For constructs, the return type is always void.class, and not the type of
|
|
// the object returned. We also need to omit the leading reference, which is
|
|
// nominally the type of the object being constructed.
|
|
if (member instanceof Constructor) {
|
|
handleType = handleType.changeReturnType(void.class);
|
|
omitLeadingParam = true;
|
|
}
|
|
|
|
// For instance field gets/puts and instance method gets/puts, we omit the
|
|
// leading reference parameter to |this|.
|
|
switch (handle.getHandleKind()) {
|
|
case IGET:
|
|
case IPUT:
|
|
case INVOKE_INTERFACE:
|
|
case INVOKE_DIRECT:
|
|
case INVOKE_VIRTUAL:
|
|
case INVOKE_SUPER:
|
|
omitLeadingParam = true;
|
|
}
|
|
|
|
return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType;
|
|
}
|
|
|
|
@Override
|
|
public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) {
|
|
try {
|
|
final Class declaringClass = member.getDeclaringClass();
|
|
if (Modifier.isNative(getModifiers()) &&
|
|
(MethodHandle.class.isAssignableFrom(declaringClass)
|
|
|| VarHandle.class.isAssignableFrom(declaringClass))) {
|
|
if (member instanceof Method) {
|
|
Method m = (Method) member;
|
|
if (m.isVarArgs()) {
|
|
// Signature-polymorphic methods should not be reflected as there
|
|
// is no support for invoking them via reflection.
|
|
//
|
|
// We've identified this method as signature-polymorphic due to
|
|
// its flags (var-args and native) and its class.
|
|
throw new IllegalArgumentException(
|
|
"Reflecting signature polymorphic method");
|
|
}
|
|
}
|
|
}
|
|
lookup.checkAccess(
|
|
declaringClass, declaringClass, member.getModifiers(), member.getName());
|
|
} catch (IllegalAccessException exception) {
|
|
throw new IllegalArgumentException("Unable to access member.", exception);
|
|
}
|
|
|
|
return (T) member;
|
|
}
|
|
|
|
@Override
|
|
public int getModifiers() {
|
|
return member.getModifiers();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return MethodHandleInfo.toString(
|
|
getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
|
|
}
|
|
}
|
|
}
|