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
import org.jnode.annotation.LoadStatics;
24
import org.jnode.annotation.MagicPermission;
25
import org.jnode.annotation.PrivilegedActionPragma;
26
import org.jnode.annotation.Uninterruptible;
27
import org.jnode.vm.classmgr.TIBLayout;
28
import org.jnode.vm.classmgr.VmArrayClass;
29
import org.jnode.vm.classmgr.VmClassLoader;
30
import org.jnode.vm.classmgr.VmConstClass;
31
import org.jnode.vm.classmgr.VmConstFieldRef;
32
import org.jnode.vm.classmgr.VmConstMethodRef;
33
import org.jnode.vm.classmgr.VmField;
34
import org.jnode.vm.classmgr.VmMethod;
35
import org.jnode.vm.classmgr.VmType;
36
import org.jnode.vm.memmgr.VmHeapManager;
37
38
/**
39
 * Class with software implementations of "difficult" java bytecodes.
40
 *
41
 * @author epr
42
 */
43
@Uninterruptible
44
@MagicPermission
45
public final class SoftByteCodes {
46
47
    private static VmHeapManager heapManager;
48
49
    /**
50
     * Is the given object instance of the given class.
51
     *
52
     * @param object
53
     * @param T
54
     * @return boolean
55
     */
56
    public static boolean isInstanceof(Object object, VmType T) {
57
        if (object == null) {
58
            return false;
59
        } else {
60
            final VmType[] superClasses = Unsafe.getSuperClasses(object);
61
            final int length = superClasses.length;
62
            for (int i = 0; i < length; i++) {
63
                if (superClasses[i] == T) {
64
                    return true;
65
                }
66
            }
67
            return false;
68
        }
69
    }
70
71
    /**
72
     * Resolve a const reference to a field to the actual field, in the context
73
     * of the given current method.
74
     *
75
     * @param currentMethod
76
     * @param fieldRef
77
     * @param isStatic
78
     * @return VmField
79
     */
80
    public static VmField resolveField(VmMethod currentMethod,
81
                                       VmConstFieldRef fieldRef, boolean isStatic) {
82
        if (!fieldRef.getConstClass().isResolved()) {
83
            resolveClass(fieldRef.getConstClass());
84
        }
85
        VmField result;
86
        if (fieldRef.isResolved()) {
87
            result = fieldRef.getResolvedVmField();
88
        } else {
89
            VmType<?> vmClass = fieldRef.getConstClass().getResolvedVmClass();
90
            vmClass.link();
91
            VmField field = vmClass.getField(fieldRef);
92
            if (field == null) {
93
                throw new NoSuchFieldError();
94
            }
95
96
            fieldRef.setResolvedVmField(field);
97
            result = field;
98
        }
99
        VmType<?> declClass = result.getDeclaringClass();
100
        if ((isStatic) && (!declClass.isAlwaysInitialized())) {
101
            if (!(result.isPrimitive() && result.isFinal())) {
102
                declClass.initialize();
103
            }
104
        }
105
        return result;
106
    }
107
108
    /**
109
     * Resolve a const reference to a method to the actual method, in the
110
     * context of the given current method.
111
     *
112
     * @param currentMethod
113
     * @param methodRef
114
     * @return VmMethod
115
     */
116
    public static VmMethod resolveMethod(VmMethod currentMethod,
117
                                         VmConstMethodRef methodRef) {
118
        if (!methodRef.getConstClass().isResolved()) {
119
            resolveClass(methodRef.getConstClass());
120
        }
121
        if (methodRef.isResolved()) {
122
            return methodRef.getResolvedVmMethod();
123
        } else {
124
            VmType<?> vmClass = methodRef.getConstClass()
125
                .getResolvedVmClass();
126
            vmClass.link();
127
128
            // NEW
129
            VmClassLoader curLoader = currentMethod.getDeclaringClass()
130
                .getLoader();
131
            methodRef.resolve(curLoader);
132
            return methodRef.getResolvedVmMethod();
133
            // END NEW
134
            /*
135
             * VmMethod method = vmClass.getMethod(methodRef); if (method ==
136
             * null) { String mname = methodRef.getName(); String cname =
137
             * methodRef.getClassName(); Screen.debug("method not found ");
138
             * Screen.debug(mname); Screen.debug(" in "); Screen.debug(cname);
139
             * throw new NoSuchMethodError(cname); }
140
             * 
141
             * methodRef.setResolvedVmMethod(method);
142
             */
143
        }
144
    }
145
146
    /**
147
     * Resolve a const reference to a class to the actual class, in the context
148
     * of the given current method.
149
     *
150
     * @param classRef
151
     * @return VmClass
152
     */
153
    @PrivilegedActionPragma
154
    public static VmType resolveClass(VmConstClass classRef) {
155
        if (classRef.isResolved()) {
156
            return classRef.getResolvedVmClass();
157
        } else {
158
            VmClassLoader curLoader = VmSystem.getContextClassLoader();
159
            String cname = classRef.getClassName();
160
            try {
161
                Class<?> cls = curLoader.asClassLoader().loadClass(cname);
162
                VmType<?> vmClass = VmType.fromClass(cls);
163
164
                /*
165
                 * VmClass vmClass = curLoader.loadClass(cname, true); //VmClass
166
                 * vmClass = Main.getBootClass(classRef); if (vmClass == null) {
167
                 * throw new NoClassDefFoundError(cname);
168
                 */
169
                classRef.setResolvedVmClass(vmClass);
170
                return vmClass;
171
            } catch (ClassNotFoundException ex) {
172
                // ex.printStackTrace();
173
                // Unsafe.debug("resolve::CLASSNOTFOUND");
174
                throw new NoClassDefFoundError(cname);
175
            }
176
        }
177
    }
178
179
    /**
180
     * Allocate a new object with a given class and a given size in bytes. If
181
     * size &lt; 0, the objectsize from the given class is used. The given size
182
     * does not include the length of the object header.
183
     *
184
     * @param vmClass
185
     * @param size
186
     * @return Object The new object
187
     */
188
    public static Object allocObject(VmType<?> vmClass, int size) {
189
        VmHeapManager hm = heapManager;
190
        if (hm == null) {
191
            heapManager = hm = Vm.getHeapManager();
192
        }
193
        final Object result;
194
        if (size < 0) {
195
            result = hm.newInstance(vmClass);
196
        } else {
197
            result = hm.newInstance(vmClass, size);
198
        }
199
        return result;
200
    }
201
202
    /**
203
     * Allocate a multi dimensional array
204
     *
205
     * @param vmClass
206
     * @param dimensions
207
     * @return The allocated array
208
     */
209
    public static Object allocMultiArray(VmType vmClass, int[] dimensions) {
210
        // Syslog.debug("allocMultiArray "); // + vmClass);
211
        return multinewarray_helper(dimensions, dimensions.length - 1,
212
            (VmArrayClass) vmClass);
213
    }
214
215
    /**
216
     * Allocates a multidimensional array of type a, with dimensions given in
217
     * dims[ind] to dims[dims.length-1]. a must be of dimensionality at least
218
     * dims.length-ind.
219
     *
220
     * @param dims array of dimensions in reverse order
221
     * @param ind  start index in array dims
222
     * @param a    array type
223
     * @return allocated array object
224
     * @throws NegativeArraySizeException if one of the array sizes in dims is negative
225
     * @throws OutOfMemoryError           if there is not enough memory to perform operation
226
     */
227
    public static Object multinewarray_helper(int[] dims, int ind,
228
                                              VmArrayClass<?> a) throws OutOfMemoryError,
229
        NegativeArraySizeException {
230
        // Syslog.debug("multinewarray_helper "); //+ " cls=" + a);
231
        a.initialize();
232
        final int length = dims[ind];
233
        final Object o = allocArray(a, length);
234
        if (ind == 0) {
235
            return o;
236
        }
237
        final Object[] o2 = (Object[]) o;
238
        final VmArrayClass<?> a2 = (VmArrayClass<?>) a.getComponentType();
239
        a2.initialize();
240
        for (int i = 0; i < length; ++i) {
241
            o2[i] = multinewarray_helper(dims, ind - 1, a2);
242
        }
243
        return o2;
244
    }
245
246
    /**
247
     * Allocate a new array with a given class as component type and a given
248
     * number of elements.
249
     *
250
     * @param vmClass
251
     * @param elements
252
     * @return Object The new array
253
     */
254
    public static Object anewarray(VmType<?> vmClass, int elements) {
255
256
        final VmArrayClass<?> arrCls = vmClass.getArrayClass();
257
        VmHeapManager hm = heapManager;
258
        if (hm == null) {
259
            heapManager = hm = Vm.getHeapManager();
260
        }
261
        final Object result = hm.newArray(arrCls, elements);
262
263
        // Screen.debug("}");
264
        return result;
265
    }
266
267
    /**
268
     * Allocate a new primivite array with a given arraytype and a given number
269
     * of elements.
270
     *
271
     * @param currentClass
272
     * @param atype
273
     * @param elements
274
     * @return Object The new array
275
     */
276
    public static Object allocPrimitiveArray(VmType<?> currentClass,
277
                                             int atype, int elements) {
278
        VmHeapManager hm = heapManager;
279
        if (hm == null) {
280
            heapManager = hm = Vm.getHeapManager();
281
        }
282
        if (false) {
283
            if (atype == 5) {
284
                if (VmSystem.isInitialized()) {
285
                    // Trace new char[]
286
                    Vm.getVm().getCounter(currentClass.getName()).add(elements);
287
                }
288
            }
289
        }
290
        final Object result = hm.newArray(VmType.getPrimitiveArrayClass(atype),
291
            elements);
292
        return result;
293
    }
294
295
    /**
296
     * Allocate a new array with a given class and a given number of elements.
297
     *
298
     * @param vmClass
299
     * @param elements
300
     * @return Object The new array
301
     */
302
    public static Object allocArray(VmType vmClass, int elements) {
303
        VmHeapManager hm = heapManager;
304
        if (hm == null) {
305
            heapManager = hm = Vm.getHeapManager();
306
        }
307
        final Object result = hm.newArray((VmArrayClass) vmClass, elements);
308
        return result;
309
    }
310
311
    /**
312
     * Throw a classcast exception.
313
     *
314
     * @param object
315
     * @param expected
316
     */
317
    public static void classCastFailed(Object object, VmType<?> expected) {
318
        if (object == null) {
319
            throw new ClassCastException("Object is null");
320
        } else if (true) {
321
            final Object[] tib = VmMagic.getTIB(object);
322
            if (tib == null) {
323
                throw new ClassCastException(object.getClass().getName()
324
                    + " tib==null");
325
            }
326
            final Object[] superClasses = (Object[]) tib[TIBLayout.SUPERCLASSES_INDEX];
327
            if (superClasses == null) {
328
                throw new ClassCastException(object.getClass().getName()
329
                    + " superClasses==null");
330
            }
331
            
332
            final StringBuilder sb = new StringBuilder("expected : ");
333
            sb.append(expected.getName());
334
            
335
            sb.append(" actual class : ");            
336
            sb.append(object.getClass().getName());
337
            
338
            sb.append(" superClasses : ");
339
            for (Object sc : superClasses) {
340
                sb.append(',');
341
                sb.append(sc);
342
                if (sc == expected) {
343
                    sb.append(" FOUND IT !!!! ");
344
                }
345
            }
346
            throw new ClassCastException(sb.toString());
347
        } else {
348
            throw new ClassCastException(object.getClass().getName());
349
        }
350
    }
351
352
    /**
353
     * Gets the Class that corresponds to the given VmType.
354
     *
355
     * @param <T>
356
     * @param type
357
     * @return the Class that corresponds to the given VmType
358
     */
359
    public static <T> Class<T> getClassForVmType(VmType<T> type) {
360
        return type.asClass();
361
    }
362
363
    /**
364
     * Throw an array index out of bounds exception.
365
     *
366
     * @param array
367
     * @param index
368
     */
369
    public static void throwArrayOutOfBounds(Object array, int index) {
370
        throw new ArrayIndexOutOfBoundsException(index);
371
    }
372
373
    /**
374
     * An unknown CPU opcode is execute.
375
     *
376
     * @param opcode
377
     * @param pc
378
     */
379
    @LoadStatics
380
    @PrivilegedActionPragma
381
    public static void unknownOpcode(int opcode, int pc) {
382
        throw new Error("Unknown opcode " + opcode + " at pc " + pc);
383
    }
384
}