1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 package org.apache.bcel.generic; 19 20 import java.util.ArrayList; 21 import java.util.List; 22 23 import org.apache.bcel.Const; 24 import org.apache.bcel.classfile.ClassFormatException; 25 import org.apache.bcel.classfile.Utility; 26 27 /** 28 * Abstract super class for all possible java types, namely basic types 29 * such as int, object types like String and array types, e.g. int[] 30 * 31 * @version $Id$ 32 */ 33 public abstract class Type { 34 35 /** 36 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 37 */ 38 @Deprecated 39 protected byte type; // TODO should be final (and private) 40 41 /** 42 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 43 */ 44 @Deprecated 45 protected String signature; // signature for the type TODO should be private 46 /** Predefined constants 47 */ 48 public static final BasicType VOID = new BasicType(Const.T_VOID); 49 public static final BasicType BOOLEAN = new BasicType(Const.T_BOOLEAN); 50 public static final BasicType INT = new BasicType(Const.T_INT); 51 public static final BasicType SHORT = new BasicType(Const.T_SHORT); 52 public static final BasicType BYTE = new BasicType(Const.T_BYTE); 53 public static final BasicType LONG = new BasicType(Const.T_LONG); 54 public static final BasicType DOUBLE = new BasicType(Const.T_DOUBLE); 55 public static final BasicType FLOAT = new BasicType(Const.T_FLOAT); 56 public static final BasicType CHAR = new BasicType(Const.T_CHAR); 57 public static final ObjectType OBJECT = new ObjectType("java.lang.Object"); 58 public static final ObjectType CLASS = new ObjectType("java.lang.Class"); 59 public static final ObjectType STRING = new ObjectType("java.lang.String"); 60 public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer"); 61 public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable"); 62 public static final Type[] NO_ARGS = new Type[0]; // EMPTY, so immutable 63 public static final ReferenceType NULL = new ReferenceType() { 64 }; 65 public static final Type UNKNOWN = new Type(Const.T_UNKNOWN, "<unknown object>") { 66 }; 67 68 Type(final byte t, final String s)69 protected Type(final byte t, final String s) { 70 type = t; 71 signature = s; 72 } 73 74 75 /** 76 * @return hashcode of Type 77 */ 78 @Override hashCode()79 public int hashCode() { 80 return type ^ signature.hashCode(); 81 } 82 83 84 /** 85 * @return whether the Types are equal 86 */ 87 @Override equals(final Object o)88 public boolean equals(final Object o) { 89 if (o instanceof Type) { 90 final Type t = (Type)o; 91 return (type == t.type) && signature.equals(t.signature); 92 } 93 return false; 94 } 95 96 97 /** 98 * @return signature for given type. 99 */ getSignature()100 public String getSignature() { 101 return signature; 102 } 103 104 105 /** 106 * @return type as defined in Constants 107 */ getType()108 public byte getType() { 109 return type; 110 } 111 112 /** 113 * boolean, short and char variable are considered as int in the stack or local variable area. 114 * Returns {@link Type#INT} for {@link Type#BOOLEAN}, {@link Type#SHORT} or {@link Type#CHAR}, otherwise 115 * returns the given type. 116 * @since 6.0 117 */ normalizeForStackOrLocal()118 public Type normalizeForStackOrLocal() { 119 if (this == Type.BOOLEAN || this == Type.BYTE || this == Type.SHORT || this == Type.CHAR) { 120 return Type.INT; 121 } 122 return this; 123 } 124 125 /** 126 * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise) 127 */ getSize()128 public int getSize() { 129 switch (type) { 130 case Const.T_DOUBLE: 131 case Const.T_LONG: 132 return 2; 133 case Const.T_VOID: 134 return 0; 135 default: 136 return 1; 137 } 138 } 139 140 141 /** 142 * @return Type string, e.g. `int[]' 143 */ 144 @Override toString()145 public String toString() { 146 return ((this.equals(Type.NULL) || (type >= Const.T_UNKNOWN))) ? signature : Utility 147 .signatureToString(signature, false); 148 } 149 150 151 /** 152 * Convert type to Java method signature, e.g. int[] f(java.lang.String x) 153 * becomes (Ljava/lang/String;)[I 154 * 155 * @param return_type what the method returns 156 * @param arg_types what are the argument types 157 * @return method signature for given type(s). 158 */ getMethodSignature( final Type return_type, final Type[] arg_types )159 public static String getMethodSignature( final Type return_type, final Type[] arg_types ) { 160 final StringBuilder buf = new StringBuilder("("); 161 if (arg_types != null) { 162 for (final Type arg_type : arg_types) { 163 buf.append(arg_type.getSignature()); 164 } 165 } 166 buf.append(')'); 167 buf.append(return_type.getSignature()); 168 return buf.toString(); 169 } 170 171 private static final ThreadLocal<Integer> consumed_chars = new ThreadLocal<Integer>() { 172 173 @Override 174 protected Integer initialValue() { 175 return Integer.valueOf(0); 176 } 177 };//int consumed_chars=0; // Remember position in string, see getArgumentTypes 178 179 unwrap( final ThreadLocal<Integer> tl )180 private static int unwrap( final ThreadLocal<Integer> tl ) { 181 return tl.get().intValue(); 182 } 183 184 wrap( final ThreadLocal<Integer> tl, final int value )185 private static void wrap( final ThreadLocal<Integer> tl, final int value ) { 186 tl.set(Integer.valueOf(value)); 187 } 188 189 190 /** 191 * Convert signature to a Type object. 192 * @param signature signature string such as Ljava/lang/String; 193 * @return type object 194 */ 195 // @since 6.0 no longer final getType( final String signature )196 public static Type getType( final String signature ) throws StringIndexOutOfBoundsException { 197 final byte type = Utility.typeOfSignature(signature); 198 if (type <= Const.T_VOID) { 199 //corrected concurrent private static field acess 200 wrap(consumed_chars, 1); 201 return BasicType.getType(type); 202 } else if (type == Const.T_ARRAY) { 203 int dim = 0; 204 do { // Count dimensions 205 dim++; 206 } while (signature.charAt(dim) == '['); 207 // Recurse, but just once, if the signature is ok 208 final Type t = getType(signature.substring(dim)); 209 //corrected concurrent private static field acess 210 // consumed_chars += dim; // update counter - is replaced by 211 final int _temp = unwrap(consumed_chars) + dim; 212 wrap(consumed_chars, _temp); 213 return new ArrayType(t, dim); 214 } else { // type == T_REFERENCE 215 // Utility.signatureToString understands how to parse 216 // generic types. 217 final String parsedSignature = Utility.signatureToString(signature, false); 218 wrap(consumed_chars, parsedSignature.length() + 2); // "Lblabla;" `L' and `;' are removed 219 return ObjectType.getInstance(parsedSignature.replace('/', '.')); 220 } 221 } 222 223 224 /** 225 * Convert return value of a method (signature) to a Type object. 226 * 227 * @param signature signature string such as (Ljava/lang/String;)V 228 * @return return type 229 */ getReturnType( final String signature )230 public static Type getReturnType( final String signature ) { 231 try { 232 // Read return type after `)' 233 final int index = signature.lastIndexOf(')') + 1; 234 return getType(signature.substring(index)); 235 } catch (final StringIndexOutOfBoundsException e) { // Should never occur 236 throw new ClassFormatException("Invalid method signature: " + signature, e); 237 } 238 } 239 240 241 /** 242 * Convert arguments of a method (signature) to an array of Type objects. 243 * @param signature signature string such as (Ljava/lang/String;)V 244 * @return array of argument types 245 */ getArgumentTypes( final String signature )246 public static Type[] getArgumentTypes( final String signature ) { 247 final List<Type> vec = new ArrayList<>(); 248 int index; 249 Type[] types; 250 try { // Read all declarations between for `(' and `)' 251 if (signature.charAt(0) != '(') { 252 throw new ClassFormatException("Invalid method signature: " + signature); 253 } 254 index = 1; // current string position 255 while (signature.charAt(index) != ')') { 256 vec.add(getType(signature.substring(index))); 257 //corrected concurrent private static field acess 258 index += unwrap(consumed_chars); // update position 259 } 260 } catch (final StringIndexOutOfBoundsException e) { // Should never occur 261 throw new ClassFormatException("Invalid method signature: " + signature, e); 262 } 263 types = new Type[vec.size()]; 264 vec.toArray(types); 265 return types; 266 } 267 268 269 /** Convert runtime java.lang.Class to BCEL Type object. 270 * @param cl Java class 271 * @return corresponding Type object 272 */ getType( final java.lang.Class<?> cl )273 public static Type getType( final java.lang.Class<?> cl ) { 274 if (cl == null) { 275 throw new IllegalArgumentException("Class must not be null"); 276 } 277 /* That's an amzingly easy case, because getName() returns 278 * the signature. That's what we would have liked anyway. 279 */ 280 if (cl.isArray()) { 281 return getType(cl.getName()); 282 } else if (cl.isPrimitive()) { 283 if (cl == Integer.TYPE) { 284 return INT; 285 } else if (cl == Void.TYPE) { 286 return VOID; 287 } else if (cl == Double.TYPE) { 288 return DOUBLE; 289 } else if (cl == Float.TYPE) { 290 return FLOAT; 291 } else if (cl == Boolean.TYPE) { 292 return BOOLEAN; 293 } else if (cl == Byte.TYPE) { 294 return BYTE; 295 } else if (cl == Short.TYPE) { 296 return SHORT; 297 } else if (cl == Byte.TYPE) { 298 return BYTE; 299 } else if (cl == Long.TYPE) { 300 return LONG; 301 } else if (cl == Character.TYPE) { 302 return CHAR; 303 } else { 304 throw new IllegalStateException("Ooops, what primitive type is " + cl); 305 } 306 } else { // "Real" class 307 return ObjectType.getInstance(cl.getName()); 308 } 309 } 310 311 312 /** 313 * Convert runtime java.lang.Class[] to BCEL Type objects. 314 * @param classes an array of runtime class objects 315 * @return array of corresponding Type objects 316 */ getTypes( final java.lang.Class<?>[] classes )317 public static Type[] getTypes( final java.lang.Class<?>[] classes ) { 318 final Type[] ret = new Type[classes.length]; 319 for (int i = 0; i < ret.length; i++) { 320 ret[i] = getType(classes[i]); 321 } 322 return ret; 323 } 324 325 getSignature( final java.lang.reflect.Method meth )326 public static String getSignature( final java.lang.reflect.Method meth ) { 327 final StringBuilder sb = new StringBuilder("("); 328 final Class<?>[] params = meth.getParameterTypes(); // avoid clone 329 for (final Class<?> param : params) { 330 sb.append(getType(param).getSignature()); 331 } 332 sb.append(")"); 333 sb.append(getType(meth.getReturnType()).getSignature()); 334 return sb.toString(); 335 } 336 size(final int coded)337 static int size(final int coded) { 338 return coded & 3; 339 } 340 consumed(final int coded)341 static int consumed(final int coded) { 342 return coded >> 2; 343 } 344 encode(final int size, final int consumed)345 static int encode(final int size, final int consumed) { 346 return consumed << 2 | size; 347 } 348 getArgumentTypesSize( final String signature )349 static int getArgumentTypesSize( final String signature ) { 350 int res = 0; 351 int index; 352 try { // Read all declarations between for `(' and `)' 353 if (signature.charAt(0) != '(') { 354 throw new ClassFormatException("Invalid method signature: " + signature); 355 } 356 index = 1; // current string position 357 while (signature.charAt(index) != ')') { 358 final int coded = getTypeSize(signature.substring(index)); 359 res += size(coded); 360 index += consumed(coded); 361 } 362 } catch (final StringIndexOutOfBoundsException e) { // Should never occur 363 throw new ClassFormatException("Invalid method signature: " + signature, e); 364 } 365 return res; 366 } 367 getTypeSize( final String signature )368 static int getTypeSize( final String signature ) throws StringIndexOutOfBoundsException { 369 final byte type = Utility.typeOfSignature(signature); 370 if (type <= Const.T_VOID) { 371 return encode(BasicType.getType(type).getSize(), 1); 372 } else if (type == Const.T_ARRAY) { 373 int dim = 0; 374 do { // Count dimensions 375 dim++; 376 } while (signature.charAt(dim) == '['); 377 // Recurse, but just once, if the signature is ok 378 final int consumed = consumed(getTypeSize(signature.substring(dim))); 379 return encode(1, dim + consumed); 380 } else { // type == T_REFERENCE 381 final int index = signature.indexOf(';'); // Look for closing `;' 382 if (index < 0) { 383 throw new ClassFormatException("Invalid signature: " + signature); 384 } 385 return encode(1, index + 1); 386 } 387 } 388 389 getReturnTypeSize(final String signature)390 static int getReturnTypeSize(final String signature) { 391 final int index = signature.lastIndexOf(')') + 1; 392 return Type.size(getTypeSize(signature.substring(index))); 393 } 394 395 396 /* 397 * Currently only used by the ArrayType constructor. 398 * The signature has a complicated dependency on other parameter 399 * so it's tricky to do it in a call to the super ctor. 400 */ setSignature(final String signature)401 void setSignature(final String signature) { 402 this.signature = signature; 403 } 404 } 405