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.dexgen.rop.cst; 18 19 import com.android.dexgen.rop.type.Type; 20 21 import java.util.HashMap; 22 23 /** 24 * Constants that represent an arbitrary type (reference or primitive). 25 */ 26 public final class CstType extends TypedConstant { 27 /** {@code non-null;} map of interned types */ 28 private static final HashMap<Type, CstType> interns = 29 new HashMap<Type, CstType>(100); 30 31 /** {@code non-null;} instance corresponding to the class {@code Object} */ 32 public static final CstType OBJECT = intern(Type.OBJECT); 33 34 /** {@code non-null;} instance corresponding to the class {@code Boolean} */ 35 public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS); 36 37 /** {@code non-null;} instance corresponding to the class {@code Byte} */ 38 public static final CstType BYTE = intern(Type.BYTE_CLASS); 39 40 /** {@code non-null;} instance corresponding to the class {@code Character} */ 41 public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS); 42 43 /** {@code non-null;} instance corresponding to the class {@code Double} */ 44 public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS); 45 46 /** {@code non-null;} instance corresponding to the class {@code Float} */ 47 public static final CstType FLOAT = intern(Type.FLOAT_CLASS); 48 49 /** {@code non-null;} instance corresponding to the class {@code Long} */ 50 public static final CstType LONG = intern(Type.LONG_CLASS); 51 52 /** {@code non-null;} instance corresponding to the class {@code Integer} */ 53 public static final CstType INTEGER = intern(Type.INTEGER_CLASS); 54 55 /** {@code non-null;} instance corresponding to the class {@code Short} */ 56 public static final CstType SHORT = intern(Type.SHORT_CLASS); 57 58 /** {@code non-null;} instance corresponding to the class {@code Void} */ 59 public static final CstType VOID = intern(Type.VOID_CLASS); 60 61 /** {@code non-null;} instance corresponding to the type {@code boolean[]} */ 62 public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY); 63 64 /** {@code non-null;} instance corresponding to the type {@code byte[]} */ 65 public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY); 66 67 /** {@code non-null;} instance corresponding to the type {@code char[]} */ 68 public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY); 69 70 /** {@code non-null;} instance corresponding to the type {@code double[]} */ 71 public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY); 72 73 /** {@code non-null;} instance corresponding to the type {@code float[]} */ 74 public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY); 75 76 /** {@code non-null;} instance corresponding to the type {@code long[]} */ 77 public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY); 78 79 /** {@code non-null;} instance corresponding to the type {@code int[]} */ 80 public static final CstType INT_ARRAY = intern(Type.INT_ARRAY); 81 82 /** {@code non-null;} instance corresponding to the type {@code short[]} */ 83 public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY); 84 85 /** {@code non-null;} the underlying type */ 86 private final Type type; 87 88 /** 89 * {@code null-ok;} the type descriptor corresponding to this instance, if 90 * calculated 91 */ 92 private CstUtf8 descriptor; 93 94 /** 95 * Returns an instance of this class that represents the wrapper 96 * class corresponding to a given primitive type. For example, if 97 * given {@link Type#INT}, this method returns the class reference 98 * {@code java.lang.Integer}. 99 * 100 * @param primitiveType {@code non-null;} the primitive type 101 * @return {@code non-null;} the corresponding wrapper class 102 */ 103 public static CstType forBoxedPrimitiveType(Type primitiveType) { 104 switch (primitiveType.getBasicType()) { 105 case Type.BT_BOOLEAN: return BOOLEAN; 106 case Type.BT_BYTE: return BYTE; 107 case Type.BT_CHAR: return CHARACTER; 108 case Type.BT_DOUBLE: return DOUBLE; 109 case Type.BT_FLOAT: return FLOAT; 110 case Type.BT_INT: return INTEGER; 111 case Type.BT_LONG: return LONG; 112 case Type.BT_SHORT: return SHORT; 113 case Type.BT_VOID: return VOID; 114 } 115 116 throw new IllegalArgumentException("not primitive: " + primitiveType); 117 } 118 119 /** 120 * Returns an interned instance of this class for the given type. 121 * 122 * @param type {@code non-null;} the underlying type 123 * @return {@code non-null;} an appropriately-constructed instance 124 */ 125 public static CstType intern(Type type) { 126 CstType cst = interns.get(type); 127 128 if (cst == null) { 129 cst = new CstType(type); 130 interns.put(type, cst); 131 } 132 133 return cst; 134 } 135 136 /** 137 * Returns an interned instance of this class for the given 138 * {@code Class} instance. 139 * 140 * @param clazz {@code non-null;} the underlying {@code Class} object 141 * @return {@code non-null;} an appropriately-constructed instance 142 */ 143 public static CstType intern(Class clazz) { 144 return intern(Type.intern(clazz)); 145 } 146 147 /** 148 * Constructs an instance. 149 * 150 * @param type {@code non-null;} the underlying type 151 */ 152 public CstType(Type type) { 153 if (type == null) { 154 throw new NullPointerException("type == null"); 155 } 156 157 if (type == type.KNOWN_NULL) { 158 throw new UnsupportedOperationException( 159 "KNOWN_NULL is not representable"); 160 } 161 162 this.type = type; 163 this.descriptor = null; 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 public boolean equals(Object other) { 169 if (!(other instanceof CstType)) { 170 return false; 171 } 172 173 return type == ((CstType) other).type; 174 } 175 176 /** {@inheritDoc} */ 177 @Override 178 public int hashCode() { 179 return type.hashCode(); 180 } 181 182 /** {@inheritDoc} */ 183 @Override 184 protected int compareTo0(Constant other) { 185 String thisDescriptor = type.getDescriptor(); 186 String otherDescriptor = ((CstType) other).type.getDescriptor(); 187 return thisDescriptor.compareTo(otherDescriptor); 188 } 189 190 /** {@inheritDoc} */ 191 @Override 192 public String toString() { 193 return "type{" + toHuman() + '}'; 194 } 195 196 /** {@inheritDoc} */ 197 public Type getType() { 198 return Type.CLASS; 199 } 200 201 /** {@inheritDoc} */ 202 @Override 203 public String typeName() { 204 return "type"; 205 } 206 207 /** {@inheritDoc} */ 208 @Override 209 public boolean isCategory2() { 210 return false; 211 } 212 213 /** {@inheritDoc} */ 214 public String toHuman() { 215 return type.toHuman(); 216 } 217 218 /** 219 * Gets the underlying type (as opposed to the type corresponding 220 * to this instance as a constant, which is always 221 * {@code Class}). 222 * 223 * @return {@code non-null;} the type corresponding to the name 224 */ 225 public Type getClassType() { 226 return type; 227 } 228 229 /** 230 * Gets the type descriptor for this instance. 231 * 232 * @return {@code non-null;} the descriptor 233 */ 234 public CstUtf8 getDescriptor() { 235 if (descriptor == null) { 236 descriptor = new CstUtf8(type.getDescriptor()); 237 } 238 239 return descriptor; 240 } 241 }