blob: 6c39dae9f718a938c897fa26dcec9f6964ac3011 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.rop.cst;
import com.android.dx.rop.type.Type;
/**
* Constants of type {@code MethodHandle}.
*/
public final class CstMethodHandle extends TypedConstant {
public static final int METHOD_HANDLE_TYPE_STATIC_PUT = 0;
public static final int METHOD_HANDLE_TYPE_STATIC_GET = 1;
public static final int METHOD_HANDLE_TYPE_INSTANCE_PUT = 2;
public static final int METHOD_HANDLE_TYPE_INSTANCE_GET = 3;
public static final int METHOD_HANDLE_TYPE_INVOKE_STATIC = 4;
public static final int METHOD_HANDLE_TYPE_INVOKE_INSTANCE = 5;
public static final int METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR = 6;
public static final int METHOD_HANDLE_TYPE_INVOKE_DIRECT = 7;
public static final int METHOD_HANDLE_TYPE_INVOKE_INTERFACE = 8;
private static final String [] TYPE_NAMES = {
"static-put", "static-get", "instance-put", "instance-get",
"invoke-static", "invoke-instance", "invoke-constructor", "invoke-direct",
"invoke-interface"
};
/** The type of MethodHandle */
private final int type;
/** {@code non-null;} the referenced constant */
private final Constant ref;
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
*
* @param type the type of this handle
* @param ref {@code non-null;} the referenced field or method constant
* @return {@code non-null;} the appropriate instance
*/
public static CstMethodHandle make(int type, Constant ref) {
if (isAccessor(type)) {
if (!(ref instanceof CstFieldRef)) {
throw new IllegalArgumentException("ref has wrong type: " + ref.getClass());
}
} else if (isInvocation(type)) {
if (!(ref instanceof CstBaseMethodRef)) {
throw new IllegalArgumentException("ref has wrong type: " + ref.getClass());
}
} else {
throw new IllegalArgumentException("type is out of range: " + type);
}
return new CstMethodHandle(type, ref);
}
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
* @param type the type of this handle
* @param ref the actual referenced constant
*/
private CstMethodHandle(int type, Constant ref) {
this.type = type;
this.ref = ref;
}
/**
* Gets the actual constant.
*
* @return the value
*/
public Constant getRef() {
return ref;
}
/**
* Gets the type of this method handle.
*
* @return the type
*/
public int getMethodHandleType() {
return type;
}
/**
* Reports whether the method handle type is a field accessor.
*
* @param type the method handle type
* @return true if the method handle type is a field accessor, false otherwise
*/
public static boolean isAccessor(int type) {
switch (type) {
case METHOD_HANDLE_TYPE_STATIC_PUT:
case METHOD_HANDLE_TYPE_STATIC_GET:
case METHOD_HANDLE_TYPE_INSTANCE_PUT:
case METHOD_HANDLE_TYPE_INSTANCE_GET:
return true;
default:
return false;
}
}
/**
* Reports whether the method handle is a field accessor.
*
* @return true if the method handle is a field accessor, false otherwise
*/
public boolean isAccessor() {
return isAccessor(type);
}
/**
* Reports whether the method handle type is a method invocation.
*
* @param type the method handle type
* @return true if the method handle type is a method invocation, false otherwise
*/
public static boolean isInvocation(int type) {
switch (type) {
case METHOD_HANDLE_TYPE_INVOKE_STATIC:
case METHOD_HANDLE_TYPE_INVOKE_INSTANCE:
case METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR:
case METHOD_HANDLE_TYPE_INVOKE_DIRECT:
case METHOD_HANDLE_TYPE_INVOKE_INTERFACE:
return true;
default:
return false;
}
}
/**
* Reports whether the method handle is a method invocation.
*
* @return true if the method handle is a method invocation, false otherwise
*/
public boolean isInvocation() {
return isInvocation(type);
}
/**
* Gets a human readable name for a method handle type.
*
* @param type the method handle type
* @return the string representation of the type
*/
private static String getTypeName(final int type) {
return TYPE_NAMES[type];
}
/** {@inheritDoc} */
@Override
public boolean isCategory2() {
return false;
}
/** {@inheritDoc} */
@Override
protected int compareTo0(Constant other) {
CstMethodHandle otherHandle = (CstMethodHandle) other;
if (getMethodHandleType() == otherHandle.getMethodHandleType()) {
return getRef().compareTo(otherHandle.getRef());
} else {
return Integer.compare(getMethodHandleType(), otherHandle.getMethodHandleType());
}
}
/** {@inheritDoc} */
@Override
public String toString() {
return "method-handle{" + toHuman() + "}";
}
/** {@inheritDoc} */
@Override
public String typeName() {
return "method handle";
}
/** {@inheritDoc} */
@Override
public String toHuman() {
return getTypeName(type)+ "," + ref.toString();
}
@Override
public Type getType() {
return Type.METHOD_HANDLE;
}
}