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