/* * $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; import org.jnode.annotation.LoadStatics; import org.jnode.annotation.MagicPermission; import org.jnode.annotation.PrivilegedActionPragma; import org.jnode.annotation.Uninterruptible; import org.jnode.vm.classmgr.TIBLayout; import org.jnode.vm.classmgr.VmArrayClass; import org.jnode.vm.classmgr.VmClassLoader; import org.jnode.vm.classmgr.VmConstClass; import org.jnode.vm.classmgr.VmConstFieldRef; import org.jnode.vm.classmgr.VmConstMethodRef; import org.jnode.vm.classmgr.VmField; import org.jnode.vm.classmgr.VmMethod; import org.jnode.vm.classmgr.VmType; import org.jnode.vm.facade.VmHeapManager; import org.jnode.vm.facade.VmUtils; /** * Class with software implementations of "difficult" java bytecodes. * * @author epr */ @Uninterruptible @MagicPermission public final class SoftByteCodes { private static VmHeapManager heapManager; /** * Is the given object instance of the given class. * * @param object * @param T * @return boolean */ public static boolean isInstanceof(Object object, VmType T) { if (object == null) { return false; } else { final VmType[] superClasses = Unsafe.getSuperClasses(object); final int length = superClasses.length; for (int i = 0; i < length; i++) { if (superClasses[i] == T) { return true; } } return false; } } /** * Resolve a const reference to a field to the actual field, in the context * of the given current method. * * @param currentMethod * @param fieldRef * @param isStatic * @return VmField */ public static VmField resolveField(VmMethod currentMethod, VmConstFieldRef fieldRef, boolean isStatic) { if (!fieldRef.getConstClass().isResolved()) { resolveClass(fieldRef.getConstClass()); } VmField result; if (fieldRef.isResolved()) { result = fieldRef.getResolvedVmField(); } else { VmType<?> vmClass = fieldRef.getConstClass().getResolvedVmClass(); vmClass.link(); VmField field = vmClass.getField(fieldRef); if (field == null) { throw new NoSuchFieldError(); } fieldRef.setResolvedVmField(field); result = field; } VmType<?> declClass = result.getDeclaringClass(); if ((isStatic) && (!declClass.isAlwaysInitialized())) { if (!(result.isPrimitive() && result.isFinal())) { declClass.initialize(); } } return result; } /** * Resolve a const reference to a method to the actual method, in the * context of the given current method. * * @param currentMethod * @param methodRef * @return VmMethod */ public static VmMethod resolveMethod(VmMethod currentMethod, VmConstMethodRef methodRef) { if (!methodRef.getConstClass().isResolved()) { resolveClass(methodRef.getConstClass()); } if (methodRef.isResolved()) { return methodRef.getResolvedVmMethod(); } else { VmType<?> vmClass = methodRef.getConstClass() .getResolvedVmClass(); vmClass.link(); // NEW VmClassLoader curLoader = currentMethod.getDeclaringClass() .getLoader(); methodRef.resolve(curLoader); return methodRef.getResolvedVmMethod(); // END NEW /* * VmMethod method = vmClass.getMethod(methodRef); if (method == * null) { String mname = methodRef.getName(); String cname = * methodRef.getClassName(); Screen.debug("method not found "); * Screen.debug(mname); Screen.debug(" in "); Screen.debug(cname); * throw new NoSuchMethodError(cname); } * * methodRef.setResolvedVmMethod(method); */ } } /** * Resolve a const reference to a class to the actual class, in the context * of the given current method. * * @param classRef * @return VmClass */ @PrivilegedActionPragma public static VmType resolveClass(VmConstClass classRef) { if (classRef.isResolved()) { return classRef.getResolvedVmClass(); } else { VmClassLoader curLoader = VmSystem.getContextClassLoader(); String cname = classRef.getClassName(); try { Class<?> cls = curLoader.asClassLoader().loadClass(cname); VmType<?> vmClass = VmType.fromClass(cls); /* * VmClass vmClass = curLoader.loadClass(cname, true); //VmClass * vmClass = Main.getBootClass(classRef); if (vmClass == null) { * throw new NoClassDefFoundError(cname); */ classRef.setResolvedVmClass(vmClass); return vmClass; } catch (ClassNotFoundException ex) { // ex.printStackTrace(); // Unsafe.debug("resolve::CLASSNOTFOUND"); throw new NoClassDefFoundError(cname); } } } /** * Allocate a new object with a given class and a given size in bytes. If * size < 0, the objectsize from the given class is used. The given size * does not include the length of the object header. * * @param vmClass * @param size * @return Object The new object */ public static Object allocObject(VmType<?> vmClass, int size) { VmHeapManager hm = heapManager; if (hm == null) { heapManager = hm = VmUtils.getVm().getHeapManager(); } final Object result; if (size < 0) { result = hm.newInstance(vmClass); } else { result = hm.newInstance(vmClass, size); } return result; } /** * Allocate a multi dimensional array * * @param vmClass * @param dimensions * @return The allocated array */ public static Object allocMultiArray(VmType vmClass, int[] dimensions) { // Syslog.debug("allocMultiArray "); // + vmClass); return multinewarray_helper(dimensions, dimensions.length - 1, (VmArrayClass) vmClass); } /** * Allocates a multidimensional array of type a, with dimensions given in * dims[ind] to dims[dims.length-1]. a must be of dimensionality at least * dims.length-ind. * * @param dims array of dimensions in reverse order * @param ind start index in array dims * @param a array type * @return allocated array object * @throws NegativeArraySizeException if one of the array sizes in dims is negative * @throws OutOfMemoryError if there is not enough memory to perform operation */ public static Object multinewarray_helper(int[] dims, int ind, VmArrayClass<?> a) throws OutOfMemoryError, NegativeArraySizeException { // Syslog.debug("multinewarray_helper "); //+ " cls=" + a); a.initialize(); final int length = dims[ind]; final Object o = allocArray(a, length); if (ind == 0) { return o; } final Object[] o2 = (Object[]) o; final VmArrayClass<?> a2 = (VmArrayClass<?>) a.getComponentType(); a2.initialize(); for (int i = 0; i < length; ++i) { o2[i] = multinewarray_helper(dims, ind - 1, a2); } return o2; } /** * Allocate a new array with a given class as component type and a given * number of elements. * * @param vmClass * @param elements * @return Object The new array */ public static Object anewarray(VmType<?> vmClass, int elements) { final VmArrayClass<?> arrCls = vmClass.getArrayClass(); VmHeapManager hm = heapManager; if (hm == null) { heapManager = hm = VmUtils.getVm().getHeapManager(); } final Object result = hm.newArray(arrCls, elements); // Screen.debug("}"); return result; } /** * Allocate a new primivite array with a given arraytype and a given number * of elements. * * @param currentClass * @param atype * @param elements * @return Object The new array */ public static Object allocPrimitiveArray(VmType<?> currentClass, int atype, int elements) { VmHeapManager hm = heapManager; if (hm == null) { heapManager = hm = VmUtils.getVm().getHeapManager(); } if (false) { if (atype == 5) { if (VmSystem.isInitialized()) { // Trace new char[] VmUtils.getVm().getCounter(currentClass.getName()).add(elements); } } } final Object result = hm.newArray(VmType.getPrimitiveArrayClass(atype), elements); return result; } /** * Allocate a new array with a given class and a given number of elements. * * @param vmClass * @param elements * @return Object The new array */ public static Object allocArray(VmType vmClass, int elements) { VmHeapManager hm = heapManager; if (hm == null) { heapManager = hm = VmUtils.getVm().getHeapManager(); } final Object result = hm.newArray((VmArrayClass) vmClass, elements); return result; } /** * Throw a classcast exception. * * @param object * @param expected */ public static void classCastFailed(Object object, VmType<?> expected) { if (object == null) { throw new ClassCastException("Object is null"); } else if (true) { final Object[] tib = VmMagic.getTIB(object); if (tib == null) { throw new ClassCastException(object.getClass().getName() + " tib==null"); } final Object[] superClasses = (Object[]) tib[TIBLayout.SUPERCLASSES_INDEX]; if (superClasses == null) { throw new ClassCastException(object.getClass().getName() + " superClasses==null"); } final StringBuilder sb = new StringBuilder("expected : "); sb.append(expected.getName()); sb.append(" actual class : "); sb.append(object.getClass().getName()); sb.append(" superClasses : "); for (Object sc : superClasses) { sb.append(','); sb.append(sc); if (sc == expected) { sb.append(" FOUND IT !!!! "); } } throw new ClassCastException(sb.toString()); } else { throw new ClassCastException(object.getClass().getName()); } } /** * Gets the Class that corresponds to the given VmType. * * @param <T> * @param type * @return the Class that corresponds to the given VmType */ public static <T> Class<T> getClassForVmType(VmType<T> type) { return type.asClass(); } /** * Throw an array index out of bounds exception. * * @param array * @param index */ public static void throwArrayOutOfBounds(Object array, int index) { throw new ArrayIndexOutOfBoundsException(index); } /** * An unknown CPU opcode is execute. * * @param opcode * @param pc */ @LoadStatics @PrivilegedActionPragma public static void unknownOpcode(int opcode, int pc) { throw new Error("Unknown opcode " + opcode + " at pc " + pc); } }