001/* 002 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.meta; 024 025import java.lang.reflect.*; 026 027//JaCoCo Exclude 028 029/** 030 * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, 031 * {@link Kind#Int} for {@code int} and {@link Kind#Object} for all object types. A kind has a 032 * single character short name, a Java name, and a set of flags further describing its behavior. 033 */ 034public enum Kind implements PlatformKind { 035 /** The primitive boolean kind, represented as an int on the stack. */ 036 Boolean('z', "boolean", 1, true, java.lang.Boolean.TYPE, java.lang.Boolean.class), 037 038 /** The primitive byte kind, represented as an int on the stack. */ 039 Byte('b', "byte", 1, true, java.lang.Byte.TYPE, java.lang.Byte.class), 040 041 /** The primitive short kind, represented as an int on the stack. */ 042 Short('s', "short", 1, true, java.lang.Short.TYPE, java.lang.Short.class), 043 044 /** The primitive char kind, represented as an int on the stack. */ 045 Char('c', "char", 1, true, java.lang.Character.TYPE, java.lang.Character.class), 046 047 /** The primitive int kind, represented as an int on the stack. */ 048 Int('i', "int", 1, true, java.lang.Integer.TYPE, java.lang.Integer.class), 049 050 /** The primitive float kind. */ 051 Float('f', "float", 1, false, java.lang.Float.TYPE, java.lang.Float.class), 052 053 /** The primitive long kind. */ 054 Long('j', "long", 2, false, java.lang.Long.TYPE, java.lang.Long.class), 055 056 /** The primitive double kind. */ 057 Double('d', "double", 2, false, java.lang.Double.TYPE, java.lang.Double.class), 058 059 /** The Object kind, also used for arrays. */ 060 Object('a', "Object", 1, false, null, null), 061 062 /** The void float kind. */ 063 Void('v', "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), 064 065 /** The non-type. */ 066 Illegal('-', "illegal", 0, false, null, null); 067 068 private final char typeChar; 069 private final String javaName; 070 private final boolean isStackInt; 071 private final Class<?> primitiveJavaClass; 072 private final Class<?> boxedJavaClass; 073 private final EnumKey key = new EnumKey(this); 074 private final int slotCount; 075 076 private Kind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class<?> primitiveJavaClass, Class<?> boxedJavaClass) { 077 this.typeChar = typeChar; 078 this.javaName = javaName; 079 this.slotCount = slotCount; 080 this.isStackInt = isStackInt; 081 this.primitiveJavaClass = primitiveJavaClass; 082 this.boxedJavaClass = boxedJavaClass; 083 assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName()); 084 } 085 086 /** 087 * Returns the number of stack slots occupied by this kind according to the Java bytecodes 088 * specification. 089 */ 090 public int getSlotCount() { 091 return this.slotCount; 092 } 093 094 /** 095 * Returns whether this kind occupied two stack slots. 096 */ 097 public boolean needsTwoSlots() { 098 return this.slotCount == 2; 099 } 100 101 /** 102 * Returns the name of the kind as a single character. 103 */ 104 public char getTypeChar() { 105 return typeChar; 106 } 107 108 /** 109 * Returns the name of this kind which will also be it Java programming language name if it is 110 * {@linkplain #isPrimitive() primitive} or {@code void}. 111 */ 112 public String getJavaName() { 113 return javaName; 114 } 115 116 public Key getKey() { 117 return key; 118 } 119 120 /** 121 * Checks whether this type is a Java primitive type. 122 * 123 * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char}, 124 * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or 125 * {@link #Void}. 126 */ 127 public boolean isPrimitive() { 128 return primitiveJavaClass != null; 129 } 130 131 /** 132 * Returns the kind that represents this kind when on the Java operand stack. 133 * 134 * @return the kind used on the operand stack 135 */ 136 public Kind getStackKind() { 137 if (isStackInt) { 138 return Int; 139 } 140 return this; 141 } 142 143 /** 144 * Checks whether this type is a Java primitive type representing an integer number. 145 * 146 * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. 147 */ 148 public boolean isNumericInteger() { 149 return isStackInt || this == Kind.Long; 150 } 151 152 /** 153 * Checks whether this type is a Java primitive type representing an unsigned number. 154 * 155 * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. 156 */ 157 public boolean isUnsigned() { 158 return this == Kind.Boolean || this == Kind.Char; 159 } 160 161 /** 162 * Checks whether this type is a Java primitive type representing a floating point number. 163 * 164 * @return {@code true} if this is {@link #Float} or {@link #Double}. 165 */ 166 public boolean isNumericFloat() { 167 return this == Kind.Float || this == Kind.Double; 168 } 169 170 /** 171 * Checks whether this represent an Object of some sort. 172 * 173 * @return {@code true} if this is {@link #Object}. 174 */ 175 public boolean isObject() { 176 return this == Kind.Object; 177 } 178 179 /** 180 * Returns the kind corresponding to the Java type string. 181 * 182 * @param typeString the Java type string 183 * @return the kind 184 */ 185 public static Kind fromTypeString(String typeString) { 186 assert typeString.length() > 0; 187 final char first = typeString.charAt(0); 188 if (first == '[' || first == 'L') { 189 return Kind.Object; 190 } 191 return Kind.fromPrimitiveOrVoidTypeChar(first); 192 } 193 194 /** 195 * Returns the kind of a word given the size of a word in bytes. 196 * 197 * @param wordSizeInBytes the size of a word in bytes 198 * @return the kind representing a word value 199 */ 200 public static Kind fromWordSize(int wordSizeInBytes) { 201 if (wordSizeInBytes == 8) { 202 return Kind.Long; 203 } else { 204 assert wordSizeInBytes == 4 : "Unsupported word size!"; 205 return Kind.Int; 206 } 207 } 208 209 /** 210 * Returns the kind from the character describing a primitive or void. 211 * 212 * @param ch the character 213 * @return the kind 214 */ 215 public static Kind fromPrimitiveOrVoidTypeChar(char ch) { 216 switch (ch) { 217 case 'Z': 218 return Boolean; 219 case 'C': 220 return Char; 221 case 'F': 222 return Float; 223 case 'D': 224 return Double; 225 case 'B': 226 return Byte; 227 case 'S': 228 return Short; 229 case 'I': 230 return Int; 231 case 'J': 232 return Long; 233 case 'V': 234 return Void; 235 } 236 throw new IllegalArgumentException("unknown primitive or void type character: " + ch); 237 } 238 239 /** 240 * Returns the Kind representing the given Java class. 241 * 242 * @param klass the class 243 * @return the kind 244 */ 245 public static Kind fromJavaClass(Class<?> klass) { 246 if (klass == Boolean.primitiveJavaClass) { 247 return Boolean; 248 } else if (klass == Byte.primitiveJavaClass) { 249 return Byte; 250 } else if (klass == Short.primitiveJavaClass) { 251 return Short; 252 } else if (klass == Char.primitiveJavaClass) { 253 return Char; 254 } else if (klass == Int.primitiveJavaClass) { 255 return Int; 256 } else if (klass == Long.primitiveJavaClass) { 257 return Long; 258 } else if (klass == Float.primitiveJavaClass) { 259 return Float; 260 } else if (klass == Double.primitiveJavaClass) { 261 return Double; 262 } else if (klass == Void.primitiveJavaClass) { 263 return Void; 264 } else { 265 return Object; 266 } 267 } 268 269 /** 270 * Returns the Java class representing this kind. 271 * 272 * @return the Java class 273 */ 274 public Class<?> toJavaClass() { 275 return primitiveJavaClass; 276 } 277 278 /** 279 * Returns the Java class for instances of boxed values of this kind. 280 * 281 * @return the Java class 282 */ 283 public Class<?> toBoxedJavaClass() { 284 return boxedJavaClass; 285 } 286 287 /** 288 * Converts this value type to a string. 289 */ 290 @Override 291 public String toString() { 292 return javaName; 293 } 294 295 /** 296 * Marker interface for types that should be {@linkplain Kind#format(Object) formatted} with 297 * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects 298 * poses a security risk because it can potentially call user code. 299 */ 300 public interface FormatWithToString { 301 } 302 303 /** 304 * Classes for which invoking {@link Object#toString()} does not run user code. 305 */ 306 private static boolean isToStringSafe(Class<?> c) { 307 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; 308 } 309 310 /** 311 * Gets a formatted string for a given value of this kind. 312 * 313 * @param value a value of this kind 314 * @return a formatted string for {@code value} based on this kind 315 */ 316 public String format(Object value) { 317 if (isPrimitive()) { 318 assert isToStringSafe(value.getClass()); 319 return value.toString(); 320 } else { 321 if (value == null) { 322 return "null"; 323 } else { 324 if (value instanceof String) { 325 String s = (String) value; 326 if (s.length() > 50) { 327 return "String:\"" + s.substring(0, 30) + "...\""; 328 } else { 329 return "String:\"" + s + '"'; 330 } 331 } else if (value instanceof JavaType) { 332 return "JavaType:" + ((JavaType) value).toJavaName(); 333 } else if (value instanceof Enum) { 334 return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum<?>) value).name(); 335 } else if (value instanceof FormatWithToString) { 336 return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); 337 } else if (value instanceof Class<?>) { 338 return "Class:" + ((Class<?>) value).getName(); 339 } else if (isToStringSafe(value.getClass())) { 340 return value.toString(); 341 } else if (value.getClass().isArray()) { 342 return formatArray(value); 343 } else { 344 return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); 345 } 346 } 347 } 348 } 349 350 private static final int MAX_FORMAT_ARRAY_LENGTH = 5; 351 352 private static String formatArray(Object array) { 353 Class<?> componentType = array.getClass().getComponentType(); 354 assert componentType != null; 355 int arrayLength = Array.getLength(array); 356 StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); 357 int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); 358 boolean primitive = componentType.isPrimitive(); 359 for (int i = 0; i < length; i++) { 360 if (primitive) { 361 buf.append(Array.get(array, i)); 362 } else { 363 Object o = ((Object[]) array)[i]; 364 buf.append(Kind.Object.format(o)); 365 } 366 if (i != length - 1) { 367 buf.append(", "); 368 } 369 } 370 if (arrayLength != length) { 371 buf.append(", ..."); 372 } 373 return buf.append('}').toString(); 374 } 375 376 /** 377 * The minimum value that can be represented as a value of this kind. 378 * 379 * @return the minimum value 380 */ 381 public long getMinValue() { 382 switch (this) { 383 case Boolean: 384 return 0; 385 case Byte: 386 return java.lang.Byte.MIN_VALUE; 387 case Char: 388 return java.lang.Character.MIN_VALUE; 389 case Short: 390 return java.lang.Short.MIN_VALUE; 391 case Int: 392 return java.lang.Integer.MIN_VALUE; 393 case Long: 394 return java.lang.Long.MIN_VALUE; 395 default: 396 throw new IllegalArgumentException("illegal call to minValue on " + this); 397 } 398 } 399 400 /** 401 * The maximum value that can be represented as a value of this kind. 402 * 403 * @return the maximum value 404 */ 405 public long getMaxValue() { 406 switch (this) { 407 case Boolean: 408 return 1; 409 case Byte: 410 return java.lang.Byte.MAX_VALUE; 411 case Char: 412 return java.lang.Character.MAX_VALUE; 413 case Short: 414 return java.lang.Short.MAX_VALUE; 415 case Int: 416 return java.lang.Integer.MAX_VALUE; 417 case Long: 418 return java.lang.Long.MAX_VALUE; 419 default: 420 throw new IllegalArgumentException("illegal call to maxValue on " + this); 421 } 422 } 423 424 /** 425 * Number of bytes that are necessary to represent a value of this kind. 426 * 427 * @return the number of bytes 428 */ 429 public int getByteCount() { 430 if (this == Boolean) { 431 return 1; 432 } else { 433 return getBitCount() >> 3; 434 } 435 } 436 437 /** 438 * Number of bits that are necessary to represent a value of this kind. 439 * 440 * @return the number of bits 441 */ 442 public int getBitCount() { 443 switch (this) { 444 case Boolean: 445 return 1; 446 case Byte: 447 return 8; 448 case Char: 449 case Short: 450 return 16; 451 case Float: 452 return 32; 453 case Int: 454 return 32; 455 case Double: 456 return 64; 457 case Long: 458 return 64; 459 default: 460 throw new IllegalArgumentException("illegal call to bits on " + this); 461 } 462 } 463 464 public JavaConstant getDefaultValue() { 465 switch (this) { 466 case Boolean: 467 return JavaConstant.FALSE; 468 case Int: 469 return JavaConstant.INT_0; 470 case Long: 471 return JavaConstant.LONG_0; 472 case Float: 473 return JavaConstant.FLOAT_0; 474 case Double: 475 return JavaConstant.DOUBLE_0; 476 case Object: 477 return JavaConstant.NULL_POINTER; 478 case Byte: 479 case Char: 480 case Short: 481 return new PrimitiveConstant(this, 0); 482 default: 483 throw new IllegalArgumentException("illegal call to getDefaultValue on " + this); 484 } 485 } 486}