comparison graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/Kind.java @ 21556:48c1ebd24120

renamed com.oracle.graal.api[meta|code] modules to com.oracle.jvmci.[meta|code] (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 00:36:16 +0200
parents graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java@51680f58e681
children
comparison
equal deleted inserted replaced
21555:d12eaef9af72 21556:48c1ebd24120
1 /*
2 * Copyright (c) 2009, 2014, 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 com.oracle.jvmci.meta;
24
25 import java.lang.reflect.*;
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 Kind#Int} for {@code int} and {@link Kind#Object} for all object types. A kind has a
32 * single character short name, a Java name, and a set of flags further describing its behavior.
33 */
34 public enum Kind implements PlatformKind {
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 EnumKey key = new EnumKey(this);
74 private final int slotCount;
75
76 private Kind(char typeChar, 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 assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName());
84 }
85
86 /**
87 * Returns the number of stack slots occupied by this kind according to the Java bytecodes
88 * specification.
89 */
90 public int getSlotCount() {
91 return this.slotCount;
92 }
93
94 /**
95 * Returns whether this kind occupied two stack slots.
96 */
97 public boolean needsTwoSlots() {
98 return this.slotCount == 2;
99 }
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 }