--- /dev/null 2017-01-22 10:16:57.869617664 -0800
+++ new/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java 2017-02-15 16:56:08.123142256 -0800
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.vm.ci.meta;
+
+import java.lang.reflect.Array;
+
+//JaCoCo Exclude
+
+/**
+ * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example,
+ * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has
+ * a single character short name, a Java name, and a set of flags further describing its behavior.
+ */
+public enum JavaKind {
+ /** The primitive boolean kind, represented as an int on the stack. */
+ Boolean('Z', "boolean", 1, true, java.lang.Boolean.TYPE, java.lang.Boolean.class),
+
+ /** The primitive byte kind, represented as an int on the stack. */
+ Byte('B', "byte", 1, true, java.lang.Byte.TYPE, java.lang.Byte.class),
+
+ /** The primitive short kind, represented as an int on the stack. */
+ Short('S', "short", 1, true, java.lang.Short.TYPE, java.lang.Short.class),
+
+ /** The primitive char kind, represented as an int on the stack. */
+ Char('C', "char", 1, true, java.lang.Character.TYPE, java.lang.Character.class),
+
+ /** The primitive int kind, represented as an int on the stack. */
+ Int('I', "int", 1, true, java.lang.Integer.TYPE, java.lang.Integer.class),
+
+ /** The primitive float kind. */
+ Float('F', "float", 1, false, java.lang.Float.TYPE, java.lang.Float.class),
+
+ /** The primitive long kind. */
+ Long('J', "long", 2, false, java.lang.Long.TYPE, java.lang.Long.class),
+
+ /** The primitive double kind. */
+ Double('D', "double", 2, false, java.lang.Double.TYPE, java.lang.Double.class),
+
+ /** The Object kind, also used for arrays. */
+ Object('A', "Object", 1, false, null, null),
+
+ /** The void kind. */
+ Void('V', "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class),
+
+ /** The non-type. */
+ Illegal('-', "illegal", 0, false, null, null);
+
+ private final char typeChar;
+ private final String javaName;
+ private final boolean isStackInt;
+ private final Class> primitiveJavaClass;
+ private final Class> boxedJavaClass;
+ private final int slotCount;
+
+ JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class> primitiveJavaClass, Class> boxedJavaClass) {
+ this.typeChar = typeChar;
+ this.javaName = javaName;
+ this.slotCount = slotCount;
+ this.isStackInt = isStackInt;
+ this.primitiveJavaClass = primitiveJavaClass;
+ this.boxedJavaClass = boxedJavaClass;
+ assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName());
+ }
+
+ /**
+ * Returns the number of stack slots occupied by this kind according to the Java bytecodes
+ * specification.
+ */
+ public int getSlotCount() {
+ return this.slotCount;
+ }
+
+ /**
+ * Returns whether this kind occupied two stack slots.
+ */
+ public boolean needsTwoSlots() {
+ return this.slotCount == 2;
+ }
+
+ /**
+ * Returns the name of the kind as a single upper case character. For the void and primitive
+ * kinds, this is the FieldType term in
+ *
+ * table 4.3-A of the JVM Specification. For {@link #Object}, the character {@code 'A'} is
+ * returned and for {@link #Illegal}, {@code '-'} is returned.
+ */
+ public char getTypeChar() {
+ return typeChar;
+ }
+
+ /**
+ * Returns the name of this kind which will also be it Java programming language name if it is
+ * {@linkplain #isPrimitive() primitive} or {@code void}.
+ */
+ public String getJavaName() {
+ return javaName;
+ }
+
+ /**
+ * Checks whether this type is a Java primitive type.
+ *
+ * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char},
+ * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or
+ * {@link #Void}.
+ */
+ public boolean isPrimitive() {
+ return primitiveJavaClass != null;
+ }
+
+ /**
+ * Returns the kind that represents this kind when on the Java operand stack.
+ *
+ * @return the kind used on the operand stack
+ */
+ public JavaKind getStackKind() {
+ if (isStackInt) {
+ return Int;
+ }
+ return this;
+ }
+
+ /**
+ * Checks whether this type is a Java primitive type representing an integer number.
+ *
+ * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}.
+ */
+ public boolean isNumericInteger() {
+ return isStackInt || this == JavaKind.Long;
+ }
+
+ /**
+ * Checks whether this type is a Java primitive type representing an unsigned number.
+ *
+ * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}.
+ */
+ public boolean isUnsigned() {
+ return this == JavaKind.Boolean || this == JavaKind.Char;
+ }
+
+ /**
+ * Checks whether this type is a Java primitive type representing a floating point number.
+ *
+ * @return {@code true} if this is {@link #Float} or {@link #Double}.
+ */
+ public boolean isNumericFloat() {
+ return this == JavaKind.Float || this == JavaKind.Double;
+ }
+
+ /**
+ * Checks whether this represent an Object of some sort.
+ *
+ * @return {@code true} if this is {@link #Object}.
+ */
+ public boolean isObject() {
+ return this == JavaKind.Object;
+ }
+
+ /**
+ * Returns the kind corresponding to the Java type string.
+ *
+ * @param typeString the Java type string
+ * @return the kind
+ */
+ public static JavaKind fromTypeString(String typeString) {
+ assert typeString.length() > 0;
+ final char first = typeString.charAt(0);
+ if (first == '[' || first == 'L') {
+ return JavaKind.Object;
+ }
+ return JavaKind.fromPrimitiveOrVoidTypeChar(first);
+ }
+
+ /**
+ * Returns the kind of a word given the size of a word in bytes.
+ *
+ * @param wordSizeInBytes the size of a word in bytes
+ * @return the kind representing a word value
+ */
+ public static JavaKind fromWordSize(int wordSizeInBytes) {
+ if (wordSizeInBytes == 8) {
+ return JavaKind.Long;
+ } else {
+ assert wordSizeInBytes == 4 : "Unsupported word size!";
+ return JavaKind.Int;
+ }
+ }
+
+ /**
+ * Returns the kind from the character describing a primitive or void.
+ *
+ * @param ch the character for a void or primitive kind as returned by {@link #getTypeChar()}
+ * @return the kind
+ */
+ public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) {
+ switch (ch) {
+ case 'Z':
+ return Boolean;
+ case 'C':
+ return Char;
+ case 'F':
+ return Float;
+ case 'D':
+ return Double;
+ case 'B':
+ return Byte;
+ case 'S':
+ return Short;
+ case 'I':
+ return Int;
+ case 'J':
+ return Long;
+ case 'V':
+ return Void;
+ }
+ throw new IllegalArgumentException("unknown primitive or void type character: " + ch);
+ }
+
+ /**
+ * Returns the Kind representing the given Java class.
+ *
+ * @param klass the class
+ * @return the kind
+ */
+ public static JavaKind fromJavaClass(Class> klass) {
+ if (klass == Boolean.primitiveJavaClass) {
+ return Boolean;
+ } else if (klass == Byte.primitiveJavaClass) {
+ return Byte;
+ } else if (klass == Short.primitiveJavaClass) {
+ return Short;
+ } else if (klass == Char.primitiveJavaClass) {
+ return Char;
+ } else if (klass == Int.primitiveJavaClass) {
+ return Int;
+ } else if (klass == Long.primitiveJavaClass) {
+ return Long;
+ } else if (klass == Float.primitiveJavaClass) {
+ return Float;
+ } else if (klass == Double.primitiveJavaClass) {
+ return Double;
+ } else if (klass == Void.primitiveJavaClass) {
+ return Void;
+ } else {
+ return Object;
+ }
+ }
+
+ /**
+ * Returns the Java class representing this kind.
+ *
+ * @return the Java class
+ */
+ public Class> toJavaClass() {
+ return primitiveJavaClass;
+ }
+
+ /**
+ * Returns the Java class for instances of boxed values of this kind.
+ *
+ * @return the Java class
+ */
+ public Class> toBoxedJavaClass() {
+ return boxedJavaClass;
+ }
+
+ /**
+ * Converts this value type to a string.
+ */
+ @Override
+ public String toString() {
+ return javaName;
+ }
+
+ /**
+ * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with
+ * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects
+ * poses a security risk because it can potentially call user code.
+ */
+ public interface FormatWithToString {
+ }
+
+ /**
+ * Classes for which invoking {@link Object#toString()} does not run user code.
+ */
+ private static boolean isToStringSafe(Class> c) {
+ 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;
+ }
+
+ /**
+ * Gets a formatted string for a given value of this kind.
+ *
+ * @param value a value of this kind
+ * @return a formatted string for {@code value} based on this kind
+ */
+ public String format(Object value) {
+ if (isPrimitive()) {
+ assert isToStringSafe(value.getClass());
+ return value.toString();
+ } else {
+ if (value == null) {
+ return "null";
+ } else {
+ if (value instanceof String) {
+ String s = (String) value;
+ if (s.length() > 50) {
+ return "String:\"" + s.substring(0, 30) + "...\"";
+ } else {
+ return "String:\"" + s + '"';
+ }
+ } else if (value instanceof JavaType) {
+ return "JavaType:" + ((JavaType) value).toJavaName();
+ } else if (value instanceof Enum) {
+ return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum>) value).name();
+ } else if (value instanceof FormatWithToString) {
+ return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value);
+ } else if (value instanceof Class>) {
+ return "Class:" + ((Class>) value).getName();
+ } else if (isToStringSafe(value.getClass())) {
+ return value.toString();
+ } else if (value.getClass().isArray()) {
+ return formatArray(value);
+ } else {
+ return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value);
+ }
+ }
+ }
+ }
+
+ private static final int MAX_FORMAT_ARRAY_LENGTH = 5;
+
+ private static String formatArray(Object array) {
+ Class> componentType = array.getClass().getComponentType();
+ assert componentType != null;
+ int arrayLength = Array.getLength(array);
+ StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{");
+ int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength);
+ boolean primitive = componentType.isPrimitive();
+ for (int i = 0; i < length; i++) {
+ if (primitive) {
+ buf.append(Array.get(array, i));
+ } else {
+ Object o = ((Object[]) array)[i];
+ buf.append(JavaKind.Object.format(o));
+ }
+ if (i != length - 1) {
+ buf.append(", ");
+ }
+ }
+ if (arrayLength != length) {
+ buf.append(", ...");
+ }
+ return buf.append('}').toString();
+ }
+
+ /**
+ * Gets the minimum value that can be represented as a value of this kind.
+ *
+ * @return the minimum value represented as a {@code long}
+ */
+ public long getMinValue() {
+ switch (this) {
+ case Boolean:
+ return 0;
+ case Byte:
+ return java.lang.Byte.MIN_VALUE;
+ case Char:
+ return java.lang.Character.MIN_VALUE;
+ case Short:
+ return java.lang.Short.MIN_VALUE;
+ case Int:
+ return java.lang.Integer.MIN_VALUE;
+ case Long:
+ return java.lang.Long.MIN_VALUE;
+ case Float:
+ return java.lang.Float.floatToRawIntBits(java.lang.Float.MIN_VALUE);
+ case Double:
+ return java.lang.Double.doubleToRawLongBits(java.lang.Double.MIN_VALUE);
+ default:
+ throw new IllegalArgumentException("illegal call to minValue on " + this);
+ }
+ }
+
+ /**
+ * Gets the maximum value that can be represented as a value of this kind.
+ *
+ * @return the maximum value represented as a {@code long}
+ */
+ public long getMaxValue() {
+ switch (this) {
+ case Boolean:
+ return 1;
+ case Byte:
+ return java.lang.Byte.MAX_VALUE;
+ case Char:
+ return java.lang.Character.MAX_VALUE;
+ case Short:
+ return java.lang.Short.MAX_VALUE;
+ case Int:
+ return java.lang.Integer.MAX_VALUE;
+ case Long:
+ return java.lang.Long.MAX_VALUE;
+ case Float:
+ return java.lang.Float.floatToRawIntBits(java.lang.Float.MAX_VALUE);
+ case Double:
+ return java.lang.Double.doubleToRawLongBits(java.lang.Double.MAX_VALUE);
+ default:
+ throw new IllegalArgumentException("illegal call to maxValue on " + this);
+ }
+ }
+
+ /**
+ * Number of bytes that are necessary to represent a value of this kind.
+ *
+ * @return the number of bytes
+ */
+ public int getByteCount() {
+ if (this == Boolean) {
+ return 1;
+ } else {
+ return getBitCount() >> 3;
+ }
+ }
+
+ /**
+ * Number of bits that are necessary to represent a value of this kind.
+ *
+ * @return the number of bits
+ */
+ public int getBitCount() {
+ switch (this) {
+ case Boolean:
+ return 1;
+ case Byte:
+ return 8;
+ case Char:
+ case Short:
+ return 16;
+ case Float:
+ return 32;
+ case Int:
+ return 32;
+ case Double:
+ return 64;
+ case Long:
+ return 64;
+ default:
+ throw new IllegalArgumentException("illegal call to bits on " + this);
+ }
+ }
+}