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