comparison jvmci/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java @ 22672:1bbd4a7c274b

Rename jdk.internal.jvmci to jdk.vm.ci
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Thu, 08 Oct 2015 17:28:41 -0700
parents jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaKind.java@976555bdc7c6
children 4b58c92e939b
comparison
equal deleted inserted replaced
22671:97f30e4d0e95 22672:1bbd4a7c274b
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 private 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 }