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 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 upper case character. For the void and primitive 102 * kinds, this is the <i>FieldType</i> term in 103 * <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2-200"> 104 * table 4.3-A</a> of the JVM Specification. For {@link #Object}, the character {@code 'A'} is 105 * returned and for {@link #Illegal}, {@code '-'} is returned. 106 */ 107 public char getTypeChar() { 108 return typeChar; 109 } 110 111 /** 112 * Returns the name of this kind which will also be it Java programming language name if it is 113 * {@linkplain #isPrimitive() primitive} or {@code void}. 114 */ 115 public String getJavaName() { 116 return javaName; 117 } 118 119 /** 120 * Checks whether this type is a Java primitive type. 121 * 122 * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char}, 123 * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or 124 * {@link #Void}. 125 */ 126 public boolean isPrimitive() { 127 return primitiveJavaClass != null; 128 } 129 130 /** 131 * Returns the kind that represents this kind when on the Java operand stack. 132 * 133 * @return the kind used on the operand stack 134 */ 135 public JavaKind getStackKind() { 136 if (isStackInt) { 137 return Int; 138 } 139 return this; 140 } 141 142 /** 143 * Checks whether this type is a Java primitive type representing an integer number. 144 * 145 * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. 146 */ 147 public boolean isNumericInteger() { 148 return isStackInt || this == JavaKind.Long; 149 } 150 151 /** 152 * Checks whether this type is a Java primitive type representing an unsigned number. 153 * 154 * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. 155 */ 156 public boolean isUnsigned() { 157 return this == JavaKind.Boolean || this == JavaKind.Char; 158 } 159 160 /** 161 * Checks whether this type is a Java primitive type representing a floating point number. 162 * 163 * @return {@code true} if this is {@link #Float} or {@link #Double}. 164 */ 165 public boolean isNumericFloat() { 166 return this == JavaKind.Float || this == JavaKind.Double; 167 } 168 169 /** 170 * Checks whether this represent an Object of some sort. 171 * 172 * @return {@code true} if this is {@link #Object}. 173 */ 174 public boolean isObject() { 175 return this == JavaKind.Object; 176 } 177 178 /** 179 * Returns the kind corresponding to the Java type string. 180 * 181 * @param typeString the Java type string 182 * @return the kind 183 */ 184 public static JavaKind fromTypeString(String typeString) { 185 assert typeString.length() > 0; 186 final char first = typeString.charAt(0); 187 if (first == '[' || first == 'L') { 188 return JavaKind.Object; 189 } 190 return JavaKind.fromPrimitiveOrVoidTypeChar(first); 191 } 192 193 /** 194 * Returns the kind of a word given the size of a word in bytes. 195 * 196 * @param wordSizeInBytes the size of a word in bytes 197 * @return the kind representing a word value 198 */ 199 public static JavaKind fromWordSize(int wordSizeInBytes) { 200 if (wordSizeInBytes == 8) { 201 return JavaKind.Long; 202 } else { 203 assert wordSizeInBytes == 4 : "Unsupported word size!"; 204 return JavaKind.Int; 205 } 206 } 207 208 /** 209 * Returns the kind from the character describing a primitive or void. 210 * 211 * @param ch the character for a void or primitive kind as returned by {@link #getTypeChar()} 212 * @return the kind 213 */ 214 public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { 215 switch (ch) { 216 case 'Z': 217 return Boolean; 218 case 'C': 219 return Char; 220 case 'F': 221 return Float; 222 case 'D': 223 return Double; 224 case 'B': 225 return Byte; 226 case 'S': 227 return Short; 228 case 'I': 229 return Int; 230 case 'J': 231 return Long; 232 case 'V': 233 return Void; 234 } 235 throw new IllegalArgumentException("unknown primitive or void type character: " + ch); 236 } 237 238 /** 239 * Returns the Kind representing the given Java class. 240 * 241 * @param klass the class 242 * @return the kind 243 */ 244 public static JavaKind fromJavaClass(Class<?> klass) { 245 if (klass == Boolean.primitiveJavaClass) { 246 return Boolean; 247 } else if (klass == Byte.primitiveJavaClass) { 248 return Byte; 249 } else if (klass == Short.primitiveJavaClass) { 250 return Short; 251 } else if (klass == Char.primitiveJavaClass) { 252 return Char; 253 } else if (klass == Int.primitiveJavaClass) { 254 return Int; 255 } else if (klass == Long.primitiveJavaClass) { 256 return Long; 257 } else if (klass == Float.primitiveJavaClass) { 258 return Float; 259 } else if (klass == Double.primitiveJavaClass) { 260 return Double; 261 } else if (klass == Void.primitiveJavaClass) { 262 return Void; 263 } else { 264 return Object; 265 } 266 } 267 268 /** 269 * Returns the Java class representing this kind. 270 * 271 * @return the Java class 272 */ 273 public Class<?> toJavaClass() { 274 return primitiveJavaClass; 275 } 276 277 /** 278 * Returns the Java class for instances of boxed values of this kind. 279 * 280 * @return the Java class 281 */ 282 public Class<?> toBoxedJavaClass() { 283 return boxedJavaClass; 284 } 285 286 /** 287 * Converts this value type to a string. 288 */ 289 @Override 290 public String toString() { 291 return javaName; 292 } 293 294 /** 295 * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with 296 * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects 297 * poses a security risk because it can potentially call user code. 298 */ 299 public interface FormatWithToString { 300 } 301 302 /** 303 * Classes for which invoking {@link Object#toString()} does not run user code. 304 */ 305 private static boolean isToStringSafe(Class<?> c) { 306 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; 307 } 308 309 /** 310 * Gets a formatted string for a given value of this kind. 311 * 312 * @param value a value of this kind 313 * @return a formatted string for {@code value} based on this kind 314 */ 315 public String format(Object value) { 316 if (isPrimitive()) { 317 assert isToStringSafe(value.getClass()); 318 return value.toString(); 319 } else { 320 if (value == null) { 321 return "null"; 322 } else { 323 if (value instanceof String) { 324 String s = (String) value; 325 if (s.length() > 50) { 326 return "String:\"" + s.substring(0, 30) + "...\""; 327 } else { 328 return "String:\"" + s + '"'; 329 } 330 } else if (value instanceof JavaType) { 331 return "JavaType:" + ((JavaType) value).toJavaName(); 332 } else if (value instanceof Enum) { 333 return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum<?>) value).name(); 334 } else if (value instanceof FormatWithToString) { 335 return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); 336 } else if (value instanceof Class<?>) { 337 return "Class:" + ((Class<?>) value).getName(); 338 } else if (isToStringSafe(value.getClass())) { 339 return value.toString(); 340 } else if (value.getClass().isArray()) { 341 return formatArray(value); 342 } else { 343 return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); 344 } 345 } 346 } 347 } 348 349 private static final int MAX_FORMAT_ARRAY_LENGTH = 5; 350 351 private static String formatArray(Object array) { 352 Class<?> componentType = array.getClass().getComponentType(); 353 assert componentType != null; 354 int arrayLength = Array.getLength(array); 355 StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); 356 int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); 357 boolean primitive = componentType.isPrimitive(); 358 for (int i = 0; i < length; i++) { 359 if (primitive) { 360 buf.append(Array.get(array, i)); 361 } else { 362 Object o = ((Object[]) array)[i]; 363 buf.append(JavaKind.Object.format(o)); 364 } 365 if (i != length - 1) { 366 buf.append(", "); 367 } 368 } 369 if (arrayLength != length) { 370 buf.append(", ..."); 371 } 372 return buf.append('}').toString(); 373 } 374 375 /** 376 * Gets the minimum value that can be represented as a value of this kind. 377 * 378 * @return the minimum value represented as a {@code long} 379 */ 380 public long getMinValue() { 381 switch (this) { 382 case Boolean: 383 return 0; 384 case Byte: 385 return java.lang.Byte.MIN_VALUE; 386 case Char: 387 return java.lang.Character.MIN_VALUE; 388 case Short: 389 return java.lang.Short.MIN_VALUE; 390 case Int: 391 return java.lang.Integer.MIN_VALUE; 392 case Long: 393 return java.lang.Long.MIN_VALUE; 394 case Float: 395 return java.lang.Float.floatToRawIntBits(java.lang.Float.MIN_VALUE); 396 case Double: 397 return java.lang.Double.doubleToRawLongBits(java.lang.Double.MIN_VALUE); 398 default: 399 throw new IllegalArgumentException("illegal call to minValue on " + this); 400 } 401 } 402 403 /** 404 * Gets the maximum value that can be represented as a value of this kind. 405 * 406 * @return the maximum value represented as a {@code long} 407 */ 408 public long getMaxValue() { 409 switch (this) { 410 case Boolean: 411 return 1; 412 case Byte: 413 return java.lang.Byte.MAX_VALUE; 414 case Char: 415 return java.lang.Character.MAX_VALUE; 416 case Short: 417 return java.lang.Short.MAX_VALUE; 418 case Int: 419 return java.lang.Integer.MAX_VALUE; 420 case Long: 421 return java.lang.Long.MAX_VALUE; 422 case Float: 423 return java.lang.Float.floatToRawIntBits(java.lang.Float.MAX_VALUE); 424 case Double: 425 return java.lang.Double.doubleToRawLongBits(java.lang.Double.MAX_VALUE); 426 default: 427 throw new IllegalArgumentException("illegal call to maxValue on " + this); 428 } 429 } 430 431 /** 432 * Number of bytes that are necessary to represent a value of this kind. 433 * 434 * @return the number of bytes 435 */ 436 public int getByteCount() { 437 if (this == Boolean) { 438 return 1; 439 } else { 440 return getBitCount() >> 3; 441 } 442 } 443 444 /** 445 * Number of bits that are necessary to represent a value of this kind. 446 * 447 * @return the number of bits 448 */ 449 public int getBitCount() { 450 switch (this) { 451 case Boolean: 452 return 1; 453 case Byte: 454 return 8; 455 case Char: 456 case Short: 457 return 16; 458 case Float: 459 return 32; 460 case Int: 461 return 32; 462 case Double: 463 return 64; 464 case Long: 465 return 64; 466 default: 467 throw new IllegalArgumentException("illegal call to bits on " + this); 468 } 469 } 470 }