1 /* 2 * Copyright (C) 2007 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 17 package com.android.dx.rop.cst; 18 19 import com.android.dx.rop.type.Type; 20 import java.util.concurrent.ConcurrentHashMap; 21 import java.util.concurrent.ConcurrentMap; 22 23 /** 24 * Constants that represent an arbitrary type (reference or primitive). 25 */ 26 public final class CstType extends TypedConstant { 27 28 /** 29 * Intern table for instances. 30 * 31 * <p>The initial capacity is based on a medium-size project. 32 */ 33 private static final ConcurrentMap<Type, CstType> interns = 34 new ConcurrentHashMap<>(1_000, 0.75f); 35 36 /** {@code non-null;} instance corresponding to the class {@code Object} */ 37 public static final CstType OBJECT = new CstType(Type.OBJECT); 38 39 /** {@code non-null;} instance corresponding to the class {@code Boolean} */ 40 public static final CstType BOOLEAN = new CstType(Type.BOOLEAN_CLASS); 41 42 /** {@code non-null;} instance corresponding to the class {@code Byte} */ 43 public static final CstType BYTE = new CstType(Type.BYTE_CLASS); 44 45 /** {@code non-null;} instance corresponding to the class {@code Character} */ 46 public static final CstType CHARACTER = new CstType(Type.CHARACTER_CLASS); 47 48 /** {@code non-null;} instance corresponding to the class {@code Double} */ 49 public static final CstType DOUBLE = new CstType(Type.DOUBLE_CLASS); 50 51 /** {@code non-null;} instance corresponding to the class {@code Float} */ 52 public static final CstType FLOAT = new CstType(Type.FLOAT_CLASS); 53 54 /** {@code non-null;} instance corresponding to the class {@code Long} */ 55 public static final CstType LONG = new CstType(Type.LONG_CLASS); 56 57 /** {@code non-null;} instance corresponding to the class {@code Integer} */ 58 public static final CstType INTEGER = new CstType(Type.INTEGER_CLASS); 59 60 /** {@code non-null;} instance corresponding to the class {@code Short} */ 61 public static final CstType SHORT = new CstType(Type.SHORT_CLASS); 62 63 /** {@code non-null;} instance corresponding to the class {@code Void} */ 64 public static final CstType VOID = new CstType(Type.VOID_CLASS); 65 66 /** {@code non-null;} instance corresponding to the type {@code boolean[]} */ 67 public static final CstType BOOLEAN_ARRAY = new CstType(Type.BOOLEAN_ARRAY); 68 69 /** {@code non-null;} instance corresponding to the type {@code byte[]} */ 70 public static final CstType BYTE_ARRAY = new CstType(Type.BYTE_ARRAY); 71 72 /** {@code non-null;} instance corresponding to the type {@code char[]} */ 73 public static final CstType CHAR_ARRAY = new CstType(Type.CHAR_ARRAY); 74 75 /** {@code non-null;} instance corresponding to the type {@code double[]} */ 76 public static final CstType DOUBLE_ARRAY = new CstType(Type.DOUBLE_ARRAY); 77 78 /** {@code non-null;} instance corresponding to the type {@code float[]} */ 79 public static final CstType FLOAT_ARRAY = new CstType(Type.FLOAT_ARRAY); 80 81 /** {@code non-null;} instance corresponding to the type {@code long[]} */ 82 public static final CstType LONG_ARRAY = new CstType(Type.LONG_ARRAY); 83 84 /** {@code non-null;} instance corresponding to the type {@code int[]} */ 85 public static final CstType INT_ARRAY = new CstType(Type.INT_ARRAY); 86 87 /** {@code non-null;} instance corresponding to the type {@code short[]} */ 88 public static final CstType SHORT_ARRAY = new CstType(Type.SHORT_ARRAY); 89 90 /** 91 * {@code non-null;} instance corresponding to the type {@code java.lang.invoke.MethodHandle} 92 */ 93 public static final CstType METHOD_HANDLE = new CstType(Type.METHOD_HANDLE); 94 95 /** 96 * {@code non-null;} instance corresponding to the type {@code java.lang.invoke.VarHandle} 97 */ 98 public static final CstType VAR_HANDLE = new CstType(Type.VAR_HANDLE); 99 100 static { 101 initInterns(); 102 } 103 104 private static void initInterns() { 105 internInitial(OBJECT); 106 internInitial(BOOLEAN); 107 internInitial(BYTE); 108 internInitial(CHARACTER); 109 internInitial(DOUBLE); 110 internInitial(FLOAT); 111 internInitial(LONG); 112 internInitial(INTEGER); 113 internInitial(SHORT); 114 internInitial(VOID); 115 internInitial(BOOLEAN_ARRAY); 116 internInitial(BYTE_ARRAY); 117 internInitial(CHAR_ARRAY); 118 internInitial(DOUBLE_ARRAY); 119 internInitial(FLOAT_ARRAY); 120 internInitial(LONG_ARRAY); 121 internInitial(INT_ARRAY); 122 internInitial(SHORT_ARRAY); 123 internInitial(METHOD_HANDLE); 124 } 125 126 private static void internInitial(CstType cst) { 127 if (interns.putIfAbsent(cst.getClassType(), cst) != null) { 128 throw new IllegalStateException("Attempted re-init of " + cst); 129 } 130 } 131 132 133 /** {@code non-null;} the underlying type */ 134 private final Type type; 135 136 /** 137 * {@code null-ok;} the type descriptor corresponding to this instance, if 138 * calculated 139 */ 140 private CstString descriptor; 141 142 /** 143 * Returns an instance of this class that represents the wrapper 144 * class corresponding to a given primitive type. For example, if 145 * given {@link Type#INT}, this method returns the class reference 146 * {@code java.lang.Integer}. 147 * 148 * @param primitiveType {@code non-null;} the primitive type 149 * @return {@code non-null;} the corresponding wrapper class 150 */ 151 public static CstType forBoxedPrimitiveType(Type primitiveType) { 152 switch (primitiveType.getBasicType()) { 153 case Type.BT_BOOLEAN: return BOOLEAN; 154 case Type.BT_BYTE: return BYTE; 155 case Type.BT_CHAR: return CHARACTER; 156 case Type.BT_DOUBLE: return DOUBLE; 157 case Type.BT_FLOAT: return FLOAT; 158 case Type.BT_INT: return INTEGER; 159 case Type.BT_LONG: return LONG; 160 case Type.BT_SHORT: return SHORT; 161 case Type.BT_VOID: return VOID; 162 } 163 164 throw new IllegalArgumentException("not primitive: " + primitiveType); 165 } 166 167 /** 168 * Returns an interned instance of this class for the given type. 169 * 170 * @param type {@code non-null;} the underlying type 171 * @return {@code non-null;} an appropriately-constructed instance 172 */ 173 public static CstType intern(Type type) { 174 CstType cst = new CstType(type); 175 CstType result = interns.putIfAbsent(type, cst); 176 return result != null ? result : cst; 177 } 178 179 /** 180 * Constructs an instance. 181 * 182 * @param type {@code non-null;} the underlying type 183 */ 184 public CstType(Type type) { 185 if (type == null) { 186 throw new NullPointerException("type == null"); 187 } 188 189 if (type == Type.KNOWN_NULL) { 190 throw new UnsupportedOperationException( 191 "KNOWN_NULL is not representable"); 192 } 193 194 this.type = type; 195 this.descriptor = null; 196 } 197 198 /** {@inheritDoc} */ 199 @Override 200 public boolean equals(Object other) { 201 if (!(other instanceof CstType)) { 202 return false; 203 } 204 205 return type == ((CstType) other).type; 206 } 207 208 /** {@inheritDoc} */ 209 @Override 210 public int hashCode() { 211 return type.hashCode(); 212 } 213 214 /** {@inheritDoc} */ 215 @Override 216 protected int compareTo0(Constant other) { 217 String thisDescriptor = type.getDescriptor(); 218 String otherDescriptor = ((CstType) other).type.getDescriptor(); 219 return thisDescriptor.compareTo(otherDescriptor); 220 } 221 222 /** {@inheritDoc} */ 223 @Override 224 public String toString() { 225 return "type{" + toHuman() + '}'; 226 } 227 228 /** {@inheritDoc} */ 229 @Override 230 public Type getType() { 231 return Type.CLASS; 232 } 233 234 /** {@inheritDoc} */ 235 @Override 236 public String typeName() { 237 return "type"; 238 } 239 240 /** {@inheritDoc} */ 241 @Override 242 public boolean isCategory2() { 243 return false; 244 } 245 246 /** {@inheritDoc} */ 247 @Override 248 public String toHuman() { 249 return type.toHuman(); 250 } 251 252 /** 253 * Gets the underlying type (as opposed to the type corresponding 254 * to this instance as a constant, which is always 255 * {@code Class}). 256 * 257 * @return {@code non-null;} the type corresponding to the name 258 */ 259 public Type getClassType() { 260 return type; 261 } 262 263 /** 264 * Gets the type descriptor for this instance. 265 * 266 * @return {@code non-null;} the descriptor 267 */ 268 public CstString getDescriptor() { 269 if (descriptor == null) { 270 descriptor = new CstString(type.getDescriptor()); 271 } 272 273 return descriptor; 274 } 275 276 /** 277 * Returns a human readable package name for this type, like "java.util". 278 * If this is an array type, this returns the package name of the array's 279 * component type. If this is a primitive type, this returns "default". 280 */ 281 public String getPackageName() { 282 // descriptor is a string like "[[Ljava/util/String;" 283 String descriptor = getDescriptor().getString(); 284 int lastSlash = descriptor.lastIndexOf('/'); 285 int lastLeftSquare = descriptor.lastIndexOf('['); // -1 unless this is an array 286 if (lastSlash == -1) { 287 return "default"; 288 } else { 289 // +2 to skip the '[' and the 'L' prefix 290 return descriptor.substring(lastLeftSquare + 2, lastSlash).replace('/', '.'); 291 } 292 } 293 294 public static void clearInternTable() { 295 interns.clear(); 296 initInterns(); 297 } 298 299 } 300