/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm; /** * This class provides helper methods for dealing with JVM types in various forms. */ public final class JvmType { public static final int UNKNOWN = 0; public static final int BOOLEAN = 1; public static final int BYTE = 2; public static final int SHORT = 3; public static final int CHAR = 4; public static final int INT = 5; public static final int LONG = 6; public static final int FLOAT = 7; public static final int DOUBLE = 8; public static final int REFERENCE = 9; public static final int RETURN_ADDRESS = REFERENCE; public static final int VOID = 10; private static final String[] names = { "UNKONWN", "BOOLEAN", "BYTE", "SHORT", "CHAR", "INT", "LONG", "FLOAT", "DOUBLE", "REF", "VOID" }; /** * Categorize a type according to the number of words it occupies. * @param type an type value * @return the number of words required to hold it. */ public static int getCategory(int type) { if ((type == LONG) || (type == DOUBLE)) { return 2; } else if (type == VOID) { return 0; } else { return 1; } } /** * Converts the given type to the smallest type that can contain it. E.g. * BYTE to INT FLOAT to FLOAT * * @param type an internal type value * @return the type value for the smallest type that JNode will use to * hold an instance of the type. */ public static int TypeToContainingType(int type) { switch (type) { case BOOLEAN: case BYTE: case CHAR: case SHORT: case INT: return INT; default: return type; } } /** * Map a JVM type character to the corresponding internal type value * @param type a JVM type character * @return the corresponding internal type value */ public static int SignatureToType(char type) { int res; switch (type) { case 'Z': // Boolean case 'B': // Byte case 'C': // Character case 'S': // Short case 'I': // Integer res = JvmType.INT; break; case 'F': // Float res = JvmType.FLOAT; break; case 'L': // Object case ';': // Object case '[': // Array res = JvmType.REFERENCE; break; case 'J': // Long res = JvmType.LONG; break; case 'D': // Double res = JvmType.DOUBLE; break; default: throw new IllegalArgumentException("Unknown type" + type); } return res; } /** * Map a JVM type signature string to the corresponding internal type value. * * @param signature * @return the internal type value */ public static int SignatureToType(String signature) { return SignatureToType(signature.charAt(0)); } /** * Gets the number of arguments present in a method signature. * * @param signature * @return The number of arguments. */ public static int getArgumentCount(String signature) { final int len = signature.length(); int cnt = 0; for (int i = 1; i < len; i++) { switch (signature.charAt(i)) { case 'Z': case 'B': case 'C': case 'S': case 'I': case 'F': case 'J': case 'D': break; case 'L': while (signature.charAt(i) != ';') { i++; } break; // Object case '[': while (signature.charAt(i) == '[') { i++; } if (signature.charAt(i) == 'L') { while (signature.charAt(i) != ';') { i++; } } break; case ')': // the end i = len; break; default: throw new IllegalArgumentException("Unknown type" + signature.substring(i)); } if (i != len) { cnt++; } } return cnt; } /** * Gets the argument types for a method signature. * * @param signature * @return the argument types as an array of internal type values */ public static int[] getArgumentTypes(String signature) { final int len = signature.length(); final int[] types = new int[getArgumentCount(signature)]; int cnt = 0; for (int i = 1; i < len; i++) { final int t; switch (signature.charAt(i)) { case 'Z': case 'B': case 'C': case 'S': case 'I': t = JvmType.INT; break; case 'F': t = JvmType.FLOAT; break; case 'L': while (signature.charAt(i) != ';') { i++; } t = JvmType.REFERENCE; break; // Object case '[': while (signature.charAt(i) == '[') { i++; } if (signature.charAt(i) == 'L') { while (signature.charAt(i) != ';') { i++; } } t = JvmType.REFERENCE; break; case 'J': t = JvmType.LONG; break; case 'D': t = JvmType.DOUBLE; break; case ')': // the end i = len; t = JvmType.VOID; break; default: throw new IllegalArgumentException("Unknown type" + signature.substring(i)); } if (t != VOID) { types[cnt++] = t; } } return types; } /** * Gets the return type of a method signature. * * @param signature * @return the return type as an internal type value */ public static int getReturnType(String signature) { final int endIdx = signature.indexOf(')'); final char ch = signature.charAt(endIdx + 1); if (ch == 'V') { return VOID; } else { return SignatureToType(ch); } } /** * Test if the given internal type value a floating point type. * * @param type the type value * @return True if type is FLOAT or DOUBLE, false otherwise. */ public static final boolean isFloat(int type) { return ((type == FLOAT) || (type == DOUBLE)); } /** * Gets a human readable name of a given internal type value. * * @param type the type value * @return a human readable rendering of the type value */ public static final String toString(int type) { return names[type]; } }