1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2003-2009 JNode.org
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful, but 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this library; If not, write to the Free Software Foundation, Inc., 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
package org.jnode.vm;
22
23
/**
24
 * This class provides helper methods for dealing with JVM types in various forms.
25
 */
26
public final class JvmType {
27
28
    public static final int UNKNOWN = 0;
29
30
    public static final int BOOLEAN = 1;
31
32
    public static final int BYTE = 2;
33
34
    public static final int SHORT = 3;
35
36
    public static final int CHAR = 4;
37
38
    public static final int INT = 5;
39
40
    public static final int LONG = 6;
41
42
    public static final int FLOAT = 7;
43
44
    public static final int DOUBLE = 8;
45
46
    public static final int REFERENCE = 9;
47
48
    public static final int RETURN_ADDRESS = REFERENCE;
49
50
    public static final int VOID = 10;
51
52
    private static final String[] names = {
53
        "UNKONWN", "BOOLEAN", "BYTE", "SHORT", "CHAR", "INT", "LONG", "FLOAT", "DOUBLE", "REF", "VOID"
54
    };
55
56
    /**
57
     * Categorize a type according to the number of words it occupies.
58
     * @param type an type value
59
     * @return the number of words required to hold it.
60
     */
61
    public static int getCategory(int type) {
62
        if ((type == LONG) || (type == DOUBLE)) {
63
            return 2;
64
        } else if (type == VOID) {
65
            return 0;
66
        } else {
67
            return 1;
68
        }
69
    }
70
71
    /**
72
     * Converts the given type to the smallest type that can contain it. E.g.
73
     * BYTE to INT FLOAT to FLOAT
74
     *
75
     * @param type an internal type value
76
     * @return the type value for the smallest type that JNode will use to
77
     * hold an instance of the type.
78
     */
79
    public static int TypeToContainingType(int type) {
80
        switch (type) {
81
            case BOOLEAN:
82
            case BYTE:
83
            case CHAR:
84
            case SHORT:
85
            case INT:
86
                return INT;
87
            default:
88
                return type;
89
        }
90
    }
91
92
    /**
93
     * Map a JVM type character to the corresponding internal type value
94
     * @param type a JVM type character
95
     * @return the corresponding internal type value
96
     */
97
    public static int SignatureToType(char type) {
98
        int res;
99
        switch (type) {
100
            case 'Z':
101
                // Boolean
102
            case 'B':
103
                // Byte
104
            case 'C':
105
                // Character
106
            case 'S':
107
                // Short
108
            case 'I':
109
                // Integer
110
                res = JvmType.INT;
111
                break;
112
            case 'F':
113
                // Float
114
                res = JvmType.FLOAT;
115
                break;
116
            case 'L':
117
                // Object
118
            case ';':
119
                // Object
120
            case '[':
121
                // Array
122
                res = JvmType.REFERENCE;
123
                break;
124
            case 'J':
125
                // Long
126
                res = JvmType.LONG;
127
                break;
128
            case 'D':
129
                // Double
130
                res = JvmType.DOUBLE;
131
                break;
132
            default:
133
                throw new IllegalArgumentException("Unknown type" + type);
134
        }
135
        return res;
136
    }
137
138
    /**
139
     * Map a JVM type signature string to the corresponding internal type value.
140
     * 
141
     * @param signature
142
     * @return the internal type value
143
     */
144
    public static int SignatureToType(String signature) {
145
        return SignatureToType(signature.charAt(0));
146
    }
147
148
    /**
149
     * Gets the number of arguments present in a method signature.
150
     *
151
     * @param signature
152
     * @return The number of arguments.
153
     */
154
    public static int getArgumentCount(String signature) {
155
        final int len = signature.length();
156
        int cnt = 0;
157
        for (int i = 1; i < len; i++) {
158
            switch (signature.charAt(i)) {
159
                case 'Z':
160
                case 'B':
161
                case 'C':
162
                case 'S':
163
                case 'I':
164
                case 'F':
165
                case 'J':
166
                case 'D':
167
                    break;
168
                case 'L':
169
                    while (signature.charAt(i) != ';') {
170
                        i++;
171
                    }
172
                    break;
173
                    // Object
174
                case '[':
175
                    while (signature.charAt(i) == '[') {
176
                        i++;
177
                    }
178
                    if (signature.charAt(i) == 'L') {
179
                        while (signature.charAt(i) != ';') {
180
                            i++;
181
                        }
182
                    }
183
                    break;
184
                case ')':
185
                    // the end
186
                    i = len;
187
                    break;
188
                default:
189
                    throw new IllegalArgumentException("Unknown type"
190
                        + signature.substring(i));
191
            }
192
            if (i != len) {
193
                cnt++;
194
            }
195
        }
196
        return cnt;
197
    }
198
199
    /**
200
     * Gets the argument types for a method signature.
201
     *
202
     * @param signature
203
     * @return the argument types as an array of internal type values
204
     */
205
    public static int[] getArgumentTypes(String signature) {
206
        final int len = signature.length();
207
        final int[] types = new int[getArgumentCount(signature)];
208
        int cnt = 0;
209
        for (int i = 1; i < len; i++) {
210
            final int t;
211
            switch (signature.charAt(i)) {
212
                case 'Z':
213
                case 'B':
214
                case 'C':
215
                case 'S':
216
                case 'I':
217
                    t = JvmType.INT;
218
                    break;
219
                case 'F':
220
                    t = JvmType.FLOAT;
221
                    break;
222
                case 'L':
223
                    while (signature.charAt(i) != ';') {
224
                        i++;
225
                    }
226
                    t = JvmType.REFERENCE;
227
                    break;
228
                    // Object
229
                case '[':
230
                    while (signature.charAt(i) == '[') {
231
                        i++;
232
                    }
233
                    if (signature.charAt(i) == 'L') {
234
                        while (signature.charAt(i) != ';') {
235
                            i++;
236
                        }
237
                    }
238
                    t = JvmType.REFERENCE;
239
                    break;
240
                case 'J':
241
                    t = JvmType.LONG;
242
                    break;
243
                case 'D':
244
                    t = JvmType.DOUBLE;
245
                    break;
246
                case ')':
247
                    // the end
248
                    i = len;
249
                    t = JvmType.VOID;
250
                    break;
251
                default:
252
                    throw new IllegalArgumentException("Unknown type"
253
                        + signature.substring(i));
254
            }
255
            if (t != VOID) {
256
                types[cnt++] = t;
257
            }
258
        }
259
        return types;
260
    }
261
262
    /**
263
     * Gets the return type of a method signature.
264
     *
265
     * @param signature
266
     * @return the return type as an internal type value
267
     */
268
    public static int getReturnType(String signature) {
269
        final int endIdx = signature.indexOf(')');
270
        final char ch = signature.charAt(endIdx + 1);
271
        if (ch == 'V') {
272
            return VOID;
273
        } else {
274
            return SignatureToType(ch);
275
        }
276
    }
277
278
    /**
279
     * Test if the given internal type value a floating point type.
280
     *
281
     * @param type the type value
282
     * @return True if type is FLOAT or DOUBLE, false otherwise.
283
     */
284
    public static final boolean isFloat(int type) {
285
        return ((type == FLOAT) || (type == DOUBLE));
286
    }
287
288
    /**
289
     * Gets a human readable name of a given internal type value.
290
     *
291
     * @param type the type value
292
     * @return a human readable rendering of the type value
293
     */
294
    public static final String toString(int type) {
295
        return names[type];
296
    }
297
}