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