1 /* 2 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.vm.ci.meta; 24 25 import java.lang.reflect.Array; 26 27 //JaCoCo Exclude 28 29 /** 30 * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, 31 * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has 32 * a single character short name, a Java name, and a set of flags further describing its behavior. 33 */ 34 public enum JavaKind { 35 /** The primitive boolean kind, represented as an int on the stack. */ 36 Boolean('z', "boolean", 1, true, java.lang.Boolean.TYPE, java.lang.Boolean.class), 37 38 /** The primitive byte kind, represented as an int on the stack. */ 39 Byte('b', "byte", 1, true, java.lang.Byte.TYPE, java.lang.Byte.class), 40 41 /** The primitive short kind, represented as an int on the stack. */ 42 Short('s', "short", 1, true, java.lang.Short.TYPE, java.lang.Short.class), 43 44 /** The primitive char kind, represented as an int on the stack. */ 45 Char('c', "char", 1, true, java.lang.Character.TYPE, java.lang.Character.class), 46 47 /** The primitive int kind, represented as an int on the stack. */ 48 Int('i', "int", 1, true, java.lang.Integer.TYPE, java.lang.Integer.class), 49 50 /** The primitive float kind. */ 51 Float('f', "float", 1, false, java.lang.Float.TYPE, java.lang.Float.class), 52 53 /** The primitive long kind. */ 54 Long('j', "long", 2, false, java.lang.Long.TYPE, java.lang.Long.class), 55 56 /** The primitive double kind. */ 57 Double('d', "double", 2, false, java.lang.Double.TYPE, java.lang.Double.class), 58 59 /** The Object kind, also used for arrays. */ 60 Object('a', "Object", 1, false, null, null), 61 62 /** The void float kind. */ 63 Void('v', "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), 64 65 /** The non-type. */ 66 Illegal('-', "illegal", 0, false, null, null); 67 68 private final char typeChar; 69 private final String javaName; 70 private final boolean isStackInt; 71 private final Class<?> primitiveJavaClass; 72 private final Class<?> boxedJavaClass; 73 private final int slotCount; 74 75 JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class<?> primitiveJavaClass, Class<?> boxedJavaClass) { 76 this.typeChar = typeChar; 77 this.javaName = javaName; 78 this.slotCount = slotCount; 79 this.isStackInt = isStackInt; 80 this.primitiveJavaClass = primitiveJavaClass; 81 this.boxedJavaClass = boxedJavaClass; 82 assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName()); 83 } 84 85 /** 86 * Returns the number of stack slots occupied by this kind according to the Java bytecodes 87 * specification. 88 */ 89 public int getSlotCount() { 90 return this.slotCount; 91 } 92 93 /** 94 * Returns whether this kind occupied two stack slots. 95 */ 96 public boolean needsTwoSlots() { 97 return this.slotCount == 2; 98 } 99 100 /** 101 * Returns the name of the kind as a single character. 102 */ 103 public char getTypeChar() { 104 return typeChar; 105 } 106 107 /** 108 * Returns the name of this kind which will also be it Java programming language name if it is 109 * {@linkplain #isPrimitive() primitive} or {@code void}. 110 */ 111 public String getJavaName() { 112 return javaName; 113 } 114 115 /** 116 * Checks whether this type is a Java primitive type. 117 * 118 * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char}, 119 * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or 120 * {@link #Void}. 121 */ 122 public boolean isPrimitive() { 123 return primitiveJavaClass != null; 124 } 125 126 /** 127 * Returns the kind that represents this kind when on the Java operand stack. 128 * 129 * @return the kind used on the operand stack 130 */ 131 public JavaKind getStackKind() { 132 if (isStackInt) { 133 return Int; 134 } 135 return this; 136 } 137 138 /** 139 * Checks whether this type is a Java primitive type representing an integer number. 140 * 141 * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. 142 */ 143 public boolean isNumericInteger() { 144 return isStackInt || this == JavaKind.Long; 145 } 146 147 /** 148 * Checks whether this type is a Java primitive type representing an unsigned number. 149 * 150 * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. 151 */ 152 public boolean isUnsigned() { 153 return this == JavaKind.Boolean || this == JavaKind.Char; 154 } 155 156 /** 157 * Checks whether this type is a Java primitive type representing a floating point number. 158 * 159 * @return {@code true} if this is {@link #Float} or {@link #Double}. 160 */ 161 public boolean isNumericFloat() { 162 return this == JavaKind.Float || this == JavaKind.Double; 163 } 164 165 /** 166 * Checks whether this represent an Object of some sort. 167 * 168 * @return {@code true} if this is {@link #Object}. 169 */ 170 public boolean isObject() { 171 return this == JavaKind.Object; 172 } 173 174 /** 175 * Returns the kind corresponding to the Java type string. 176 * 177 * @param typeString the Java type string 178 * @return the kind 179 */ 180 public static JavaKind fromTypeString(String typeString) { 181 assert typeString.length() > 0; 182 final char first = typeString.charAt(0); 183 if (first == '[' || first == 'L') { 184 return JavaKind.Object; 185 } 186 return JavaKind.fromPrimitiveOrVoidTypeChar(first); 187 } 188 189 /** 190 * Returns the kind of a word given the size of a word in bytes. 191 * 192 * @param wordSizeInBytes the size of a word in bytes 193 * @return the kind representing a word value 194 */ 195 public static JavaKind fromWordSize(int wordSizeInBytes) { 196 if (wordSizeInBytes == 8) { 197 return JavaKind.Long; 198 } else { 199 assert wordSizeInBytes == 4 : "Unsupported word size!"; 200 return JavaKind.Int; 201 } 202 } 203 204 /** 205 * Returns the kind from the character describing a primitive or void. 206 * 207 * @param ch the character 208 * @return the kind 209 */ 210 public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { 211 switch (ch) { 212 case 'Z': 213 return Boolean; 214 case 'C': 215 return Char; 216 case 'F': 217 return Float; 218 case 'D': 219 return Double; 220 case 'B': 221 return Byte; 222 case 'S': 223 return Short; 224 case 'I': 225 return Int; 226 case 'J': 227 return Long; 228 case 'V': 229 return Void; 230 } 231 throw new IllegalArgumentException("unknown primitive or void type character: " + ch); 232 } 233 234 /** 235 * Returns the Kind representing the given Java class. 236 * 237 * @param klass the class 238 * @return the kind 239 */ 240 public static JavaKind fromJavaClass(Class<?> klass) { 241 if (klass == Boolean.primitiveJavaClass) { 242 return Boolean; 243 } else if (klass == Byte.primitiveJavaClass) { 244 return Byte; 245 } else if (klass == Short.primitiveJavaClass) { 246 return Short; 247 } else if (klass == Char.primitiveJavaClass) { 248 return Char; 249 } else if (klass == Int.primitiveJavaClass) { 250 return Int; 251 } else if (klass == Long.primitiveJavaClass) { 252 return Long; 253 } else if (klass == Float.primitiveJavaClass) { 254 return Float; 255 } else if (klass == Double.primitiveJavaClass) { 256 return Double; 257 } else if (klass == Void.primitiveJavaClass) { 258 return Void; 259 } else { 260 return Object; 261 } 262 } 263 264 /** 265 * Returns the Java class representing this kind. 266 * 267 * @return the Java class 268 */ 269 public Class<?> toJavaClass() { 270 return primitiveJavaClass; 271 } 272 273 /** 274 * Returns the Java class for instances of boxed values of this kind. 275 * 276 * @return the Java class 277 */ 278 public Class<?> toBoxedJavaClass() { 279 return boxedJavaClass; 280 } 281 282 /** 283 * Converts this value type to a string. 284 */ 285 @Override 286 public String toString() { 287 return javaName; 288 } 289 290 /** 291 * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with 292 * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects 293 * poses a security risk because it can potentially call user code. 294 */ 295 public interface FormatWithToString { 296 } 297 298 /** 299 * Classes for which invoking {@link Object#toString()} does not run user code. 300 */ 301 private static boolean isToStringSafe(Class<?> c) { 302 return c == Boolean.class || c == Byte.class || c == Character.class || c == Short.class || c == Integer.class || c == Float.class || c == Long.class || c == Double.class; 303 } 304 305 /** 306 * Gets a formatted string for a given value of this kind. 307 * 308 * @param value a value of this kind 309 * @return a formatted string for {@code value} based on this kind 310 */ 311 public String format(Object value) { 312 if (isPrimitive()) { 313 assert isToStringSafe(value.getClass()); 314 return value.toString(); 315 } else { 316 if (value == null) { 317 return "null"; 318 } else { 319 if (value instanceof String) { 320 String s = (String) value; 321 if (s.length() > 50) { 322 return "String:\"" + s.substring(0, 30) + "...\""; 323 } else { 324 return "String:\"" + s + '"'; 325 } 326 } else if (value instanceof JavaType) { 327 return "JavaType:" + ((JavaType) value).toJavaName(); 328 } else if (value instanceof Enum) { 329 return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum<?>) value).name(); 330 } else if (value instanceof FormatWithToString) { 331 return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); 332 } else if (value instanceof Class<?>) { 333 return "Class:" + ((Class<?>) value).getName(); 334 } else if (isToStringSafe(value.getClass())) { 335 return value.toString(); 336 } else if (value.getClass().isArray()) { 337 return formatArray(value); 338 } else { 339 return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); 340 } 341 } 342 } 343 } 344 345 private static final int MAX_FORMAT_ARRAY_LENGTH = 5; 346 347 private static String formatArray(Object array) { 348 Class<?> componentType = array.getClass().getComponentType(); 349 assert componentType != null; 350 int arrayLength = Array.getLength(array); 351 StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); 352 int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); 353 boolean primitive = componentType.isPrimitive(); 354 for (int i = 0; i < length; i++) { 355 if (primitive) { 356 buf.append(Array.get(array, i)); 357 } else { 358 Object o = ((Object[]) array)[i]; 359 buf.append(JavaKind.Object.format(o)); 360 } 361 if (i != length - 1) { 362 buf.append(", "); 363 } 364 } 365 if (arrayLength != length) { 366 buf.append(", ..."); 367 } 368 return buf.append('}').toString(); 369 } 370 371 /** 372 * The minimum value that can be represented as a value of this kind. 373 * 374 * @return the minimum value 375 */ 376 public long getMinValue() { 377 switch (this) { 378 case Boolean: 379 return 0; 380 case Byte: 381 return java.lang.Byte.MIN_VALUE; 382 case Char: 383 return java.lang.Character.MIN_VALUE; 384 case Short: 385 return java.lang.Short.MIN_VALUE; 386 case Int: 387 return java.lang.Integer.MIN_VALUE; 388 case Long: 389 return java.lang.Long.MIN_VALUE; 390 default: 391 throw new IllegalArgumentException("illegal call to minValue on " + this); 392 } 393 } 394 395 /** 396 * The maximum value that can be represented as a value of this kind. 397 * 398 * @return the maximum value 399 */ 400 public long getMaxValue() { 401 switch (this) { 402 case Boolean: 403 return 1; 404 case Byte: 405 return java.lang.Byte.MAX_VALUE; 406 case Char: 407 return java.lang.Character.MAX_VALUE; 408 case Short: 409 return java.lang.Short.MAX_VALUE; 410 case Int: 411 return java.lang.Integer.MAX_VALUE; 412 case Long: 413 return java.lang.Long.MAX_VALUE; 414 default: 415 throw new IllegalArgumentException("illegal call to maxValue on " + this); 416 } 417 } 418 419 /** 420 * Number of bytes that are necessary to represent a value of this kind. 421 * 422 * @return the number of bytes 423 */ 424 public int getByteCount() { 425 if (this == Boolean) { 426 return 1; 427 } else { 428 return getBitCount() >> 3; 429 } 430 } 431 432 /** 433 * Number of bits that are necessary to represent a value of this kind. 434 * 435 * @return the number of bits 436 */ 437 public int getBitCount() { 438 switch (this) { 439 case Boolean: 440 return 1; 441 case Byte: 442 return 8; 443 case Char: 444 case Short: 445 return 16; 446 case Float: 447 return 32; 448 case Int: 449 return 32; 450 case Double: 451 return 64; 452 case Long: 453 return 64; 454 default: 455 throw new IllegalArgumentException("illegal call to bits on " + this); 456 } 457 } 458 }