1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dx.rop.cst; 18 19import com.android.dx.rop.type.Type; 20 21/** 22 * Constants of type {@code MethodHandle}. 23 */ 24public final class CstMethodHandle extends TypedConstant { 25 26 public static final int METHOD_HANDLE_TYPE_STATIC_PUT = 0; 27 public static final int METHOD_HANDLE_TYPE_STATIC_GET = 1; 28 public static final int METHOD_HANDLE_TYPE_INSTANCE_PUT = 2; 29 public static final int METHOD_HANDLE_TYPE_INSTANCE_GET = 3; 30 31 public static final int METHOD_HANDLE_TYPE_INVOKE_STATIC = 4; 32 public static final int METHOD_HANDLE_TYPE_INVOKE_INSTANCE = 5; 33 public static final int METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR = 6; 34 public static final int METHOD_HANDLE_TYPE_INVOKE_DIRECT = 7; 35 public static final int METHOD_HANDLE_TYPE_INVOKE_INTERFACE = 8; 36 37 private static final String [] TYPE_NAMES = { 38 "static-put", "static-get", "instance-put", "instance-get", 39 "invoke-static", "invoke-instance", "invoke-constructor", "invoke-direct", 40 "invoke-interface" 41 }; 42 43 /** The type of MethodHandle */ 44 private final int type; 45 46 /** {@code non-null;} the referenced constant */ 47 private final Constant ref; 48 49 /** 50 * Makes an instance for the given value. This may (but does not 51 * necessarily) return an already-allocated instance. 52 * 53 * @param type the type of this handle 54 * @param ref {@code non-null;} the referenced field or method constant 55 * @return {@code non-null;} the appropriate instance 56 */ 57 public static CstMethodHandle make(int type, Constant ref) { 58 if (isAccessor(type)) { 59 if (!(ref instanceof CstFieldRef)) { 60 throw new IllegalArgumentException("ref has wrong type: " + ref.getClass()); 61 } 62 } else if (isInvocation(type)) { 63 if (!(ref instanceof CstBaseMethodRef)) { 64 throw new IllegalArgumentException("ref has wrong type: " + ref.getClass()); 65 } 66 } else { 67 throw new IllegalArgumentException("type is out of range: " + type); 68 } 69 return new CstMethodHandle(type, ref); 70 } 71 72 /** 73 * Constructs an instance. This constructor is private; use {@link #make}. 74 * 75 * @param type the type of this handle 76 * @param ref the actual referenced constant 77 */ 78 private CstMethodHandle(int type, Constant ref) { 79 this.type = type; 80 this.ref = ref; 81 } 82 83 /** 84 * Gets the actual constant. 85 * 86 * @return the value 87 */ 88 public Constant getRef() { 89 return ref; 90 } 91 92 /** 93 * Gets the type of this method handle. 94 * 95 * @return the type 96 */ 97 public int getMethodHandleType() { 98 return type; 99 } 100 101 /** 102 * Reports whether the method handle type is a field accessor. 103 * 104 * @param type the method handle type 105 * @return true if the method handle type is a field accessor, false otherwise 106 */ 107 public static boolean isAccessor(int type) { 108 switch (type) { 109 case METHOD_HANDLE_TYPE_STATIC_PUT: 110 case METHOD_HANDLE_TYPE_STATIC_GET: 111 case METHOD_HANDLE_TYPE_INSTANCE_PUT: 112 case METHOD_HANDLE_TYPE_INSTANCE_GET: 113 return true; 114 default: 115 return false; 116 } 117 } 118 119 /** 120 * Reports whether the method handle is a field accessor. 121 * 122 * @return true if the method handle is a field accessor, false otherwise 123 */ 124 public boolean isAccessor() { 125 return isAccessor(type); 126 } 127 128 /** 129 * Reports whether the method handle type is a method invocation. 130 * 131 * @param type the method handle type 132 * @return true if the method handle type is a method invocation, false otherwise 133 */ 134 public static boolean isInvocation(int type) { 135 switch (type) { 136 case METHOD_HANDLE_TYPE_INVOKE_STATIC: 137 case METHOD_HANDLE_TYPE_INVOKE_INSTANCE: 138 case METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR: 139 case METHOD_HANDLE_TYPE_INVOKE_DIRECT: 140 case METHOD_HANDLE_TYPE_INVOKE_INTERFACE: 141 return true; 142 default: 143 return false; 144 } 145 } 146 147 /** 148 * Reports whether the method handle is a method invocation. 149 * 150 * @return true if the method handle is a method invocation, false otherwise 151 */ 152 public boolean isInvocation() { 153 return isInvocation(type); 154 } 155 156 /** 157 * Gets a human readable name for a method handle type. 158 * 159 * @param type the method handle type 160 * @return the string representation of the type 161 */ 162 public static String getMethodHandleTypeName(final int type) { 163 return TYPE_NAMES[type]; 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 public boolean isCategory2() { 169 return false; 170 } 171 172 /** {@inheritDoc} */ 173 @Override 174 protected int compareTo0(Constant other) { 175 CstMethodHandle otherHandle = (CstMethodHandle) other; 176 if (getMethodHandleType() == otherHandle.getMethodHandleType()) { 177 return getRef().compareTo(otherHandle.getRef()); 178 } else { 179 return Integer.compare(getMethodHandleType(), otherHandle.getMethodHandleType()); 180 } 181 } 182 183 /** {@inheritDoc} */ 184 @Override 185 public String toString() { 186 return "method-handle{" + toHuman() + "}"; 187 } 188 189 /** {@inheritDoc} */ 190 @Override 191 public String typeName() { 192 return "method handle"; 193 } 194 195 /** {@inheritDoc} */ 196 @Override 197 public String toHuman() { 198 return getMethodHandleTypeName(type)+ "," + ref.toString(); 199 } 200 201 @Override 202 public Type getType() { 203 return Type.METHOD_HANDLE; 204 } 205} 206