Package org.jnode.vm

Source Code of org.jnode.vm.VmReflection

/*
* $Id$
*
* Copyright (C) 2003-2014 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 java.lang.reflect.InvocationTargetException;

import org.jnode.annotation.MagicPermission;
import org.jnode.annotation.PrivilegedActionPragma;
import org.jnode.vm.classmgr.VmConstString;
import org.jnode.vm.classmgr.VmField;
import org.jnode.vm.classmgr.VmInstanceField;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmStaticField;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.facade.VmHeapManager;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.facade.VmWriteBarrier;
import org.jnode.vm.scheduler.VmProcessor;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;

/**
* <description>
*
* @author epr
*/
@MagicPermission
public final class VmReflection {

    public static Object getObject(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            Object obj = getStaticFieldAddress(sf).loadObjectReference().toObject();
            //handles the reflective access to static final String fields, which didn't work.
            if (obj != null && sf.isFinal() && field.getSignature().equals("Ljava/lang/String;")) {
                if (obj instanceof VmConstString) {
                    VmConstString cs = (VmConstString) obj;
                    obj = VmUtils.getVm().getSharedStatics().getStringEntry(cs.getSharedStaticsIndex());
                }
            }
            return obj;
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadObjectReference().toObject();
        }
    }

    public static boolean getBoolean(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return (getStaticFieldAddress(sf).loadInt() != 0);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return (getInstanceFieldAddress(o, inf).loadByte() != 0);
        }
    }

    public static byte getByte(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return (byte) getStaticFieldAddress(sf).loadInt();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadByte();
        }
    }

    public static char getChar(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return (char) getStaticFieldAddress(sf).loadInt();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadChar();
        }
    }

    public static short getShort(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return (short) getStaticFieldAddress(sf).loadInt();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadShort();
        }
    }

    public static int getInt(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return getStaticFieldAddress(sf).loadInt();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadInt();
        }
    }

    public static float getFloat(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return getStaticFieldAddress(sf).loadFloat();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadFloat();
        }
    }

    public static long getLong(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return getStaticFieldAddress(sf).loadLong();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadLong();
        }
    }

    public static double getDouble(VmField field, Object o) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            return getStaticFieldAddress(sf).loadDouble();
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            return getInstanceFieldAddress(o, inf).loadDouble();
        }
    }

    public static void setObject(VmField field, Object o, Object value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store(ObjectReference.fromObject(value));
            final VmWriteBarrier wb = VmUtils.getVm().getHeapManager().getWriteBarrier();
            if (wb != null) {
                if (sf.isShared()) {
                    wb.putstaticWriteBarrier(true, sf.getSharedStaticsIndex(), value);
                } else {
                    wb.putstaticWriteBarrier(true, sf.getIsolatedStaticsIndex(), value);
                }
            }
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            final int offset = inf.getOffset();
            getInstanceFieldAddress(o, inf).store(ObjectReference.fromObject(value));
            final VmWriteBarrier wb = VmUtils.getVm().getHeapManager().getWriteBarrier();
            if (wb != null) {
                wb.putfieldWriteBarrier(o, offset, value);
            }
        }
    }

    public static void setBoolean(VmField field, Object o, boolean value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store((int) (value ? 1 : 0));
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store((byte) (value ? 1 : 0));
        }
    }

    public static void setByte(VmField field, Object o, byte value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store((int) value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store((byte) value);
        }
    }

    public static void setChar(VmField field, Object o, char value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store((int) value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store((char) value);
        }
    }

    public static void setShort(VmField field, Object o, short value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store((int) value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store((short) value);
        }
    }

    public static void setInt(VmField field, Object o, int value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store(value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store(value);
        }
    }

    public static void setFloat(VmField field, Object o, float value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store(value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store(value);
        }
    }

    public static void setLong(VmField field, Object o, long value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store(value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store(value);
        }
    }

    public static void setDouble(VmField field, Object o, double value) {
        if (field.isStatic()) {
            final VmStaticField sf = (VmStaticField) field;
            initialize(sf);
            getStaticFieldAddress(sf).store(value);
        } else {
            final VmInstanceField inf = (VmInstanceField) field;
            getInstanceFieldAddress(o, inf).store(value);
        }
    }

    /**
     * Gets the address of the static field data (in the statics table)
     *
     * @param sf
     * @return The address of the static field data
     */
    private static final Address getStaticFieldAddress(VmStaticField sf) {
        final VmProcessor proc = VmProcessor.current();
        final Address tablePtr;
        final int offset;
        if (sf.isShared()) {
            offset = sf.getSharedStaticsIndex() << 2;
            tablePtr = VmMagic.getArrayData(proc.getSharedStaticsTable());
        } else {
            offset = sf.getIsolatedStaticsIndex() << 2;
            tablePtr = VmMagic.getArrayData(proc.getIsolatedStaticsTable());
        }
        return tablePtr.add(offset);
    }

    /**
     * Gets the address of the instance field data (in the given object)
     *
     * @param f
     * @return The address of the instance field data in the given object.
     */
    private static final Address getInstanceFieldAddress(Object object, VmInstanceField f) {
        final Address objectPtr = ObjectReference.fromObject(object).toAddress();
        return objectPtr.add(f.getOffset());
    }

    /**
     * Invoke the given method, which must be static and have no arguments
     *
     * @param method
     * @throws InvocationTargetException
     */
    public static void invokeStatic(VmMethod method)
        throws InvocationTargetException {
        try {
            Unsafe.invokeVoid(method);
        } catch (Throwable ex) {
            throw new InvocationTargetException(ex);
        }
    }

    /**
     * Invoke the given method on the given object with the given arguments.
     *
     * @param method
     * @param o
     * @param args
     * @return Object
     * @throws InvocationTargetException
     */
    @PrivilegedActionPragma
    //todo verify this wrt. security implications
    public static Object invoke(VmMethod method, Object o, Object[] args)
        throws InvocationTargetException {
        int argCount = method.getNoArguments();
        int argsLength = (args == null) ? 0 : args.length;
        if (argCount != argsLength) {
            throw new IllegalArgumentException("Invalid number of arguments");
        }

        if (!method.isStatic()) {
            if (o == null) {
                throw new NullPointerException();
            }

            //todo should we make this check here or on a higher level?
            Class declaringClass = method.getDeclaringClass().asClass();
            if (!declaringClass.isInstance(o)) {
                throw new IllegalArgumentException("Target object arg is not an instance of " +
                    declaringClass.getName());
            }

            Unsafe.pushObject(o);
            if (!method.isConstructor()) {
                //todo implement dynamic method lookup according to JLS 15.12.4.4
                if (method.isAbstract())
                    method = VmType.fromClass(o.getClass()).getMethod(method.getName(), method.getSignature());
                else if (java.lang.reflect.Proxy.isProxyClass(o.getClass())) {
                    method = VmType.fromClass(o.getClass()).getMethod(method.getName(), method.getSignature());
                }
            }
        } else {
            method.getDeclaringClass().initialize();
        }

        for (int i = 0; i < argCount; i++) {
            final VmType<?> argType = method.getArgumentType(i);
            final Object arg = args[i];
            if (argType.isPrimitive()) {
                if (arg == null)
                    throw new IllegalArgumentException();

                int v = 0;
                long lv = 0;
                boolean wide = false;
                switch (argType.getJvmType()) {
                    case JvmType.BOOLEAN: {
                        if (arg instanceof Boolean) {
                            v = (Boolean) arg ? 1 : 0;
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.INT: {
                        if (arg instanceof Integer) {
                            v = (Integer) arg;
                        } else if (arg instanceof Byte) {
                            v = (Byte) arg;
                        } else if (arg instanceof Character) {
                            v = (Character) arg;
                        } else if (arg instanceof Short) {
                            v = (Short) arg;
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.CHAR: {
                        if (arg instanceof Character) {
                            v = (Character) arg;
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.BYTE: {
                        if (arg instanceof Byte) {
                            v = (Byte) arg;
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.SHORT: {
                        if (arg instanceof Short) {
                            v = (Short) arg;
                        } else if (arg instanceof Byte) {
                            v = (Byte) arg;
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.FLOAT: {
                        if (arg instanceof Float) {
                            v = Float.floatToRawIntBits((Float) arg);
                        } else if (arg instanceof Byte) {
                            v = Float.floatToRawIntBits((Byte) arg);
                        } else if (arg instanceof Short) {
                            v = Float.floatToRawIntBits((Short) arg);
                        } else if (arg instanceof Integer) {
                            v = Float.floatToRawIntBits((Integer) arg);
                        } else if (arg instanceof Character) {
                            v = Float.floatToRawIntBits((Character) arg);
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.LONG: {
                        wide = true;
                        if (arg instanceof Long) {
                            lv = (Long) arg;
                        } else if (arg instanceof Integer) {
                            lv = (Integer) arg;
                        } else if (arg instanceof Byte) {
                            lv = (Byte) arg;
                        } else if (arg instanceof Short) {
                            lv = (Short) arg;
                        } else if (arg instanceof Character) {
                            lv = (Character) arg;
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    case JvmType.DOUBLE: {
                        wide = true;
                        if (arg instanceof Double) {
                            lv = Double.doubleToRawLongBits((Double) arg);
                        } else if (arg instanceof Integer) {
                            lv = Double.doubleToRawLongBits((Integer) arg);
                        } else if (arg instanceof Byte) {
                            lv = Double.doubleToRawLongBits((Byte) arg);
                        } else if (arg instanceof Short) {
                            lv = Double.doubleToRawLongBits((Short) arg);
                        } else if (arg instanceof Character) {
                            lv = Double.doubleToRawLongBits((Character) arg);
                        } else if (arg instanceof Float) {
                            lv = Double.doubleToRawLongBits((Float) arg);
                        } else if (arg instanceof Long) {
                            lv = Double.doubleToRawLongBits((Long) arg);
                        } else {
                            throw new IllegalArgumentException("argument type mismatch");
                        }
                        break;
                    }
                    default: {
                        throw new RuntimeException("invalid argument type: " + argType);
                    }
                }

                final Class argClass = argType.asClass();
                if ((argClass == Long.TYPE) || (argClass == Double.TYPE)) {
                    // Wide argument
                    if (wide) {
                        Unsafe.pushLong(lv);
                    } else {
                        Unsafe.pushLong(v);
                    }
                } else {
                    // Normal argument
                    if (wide) {
                        Unsafe.pushInt((int) lv);
                    } else {
                        Unsafe.pushInt(v);
                    }
                }
            } else {
                if (arg != null) {
                    if (!argType.isAssignableFrom(VmType.fromClass(arg.getClass()))) {
                        throw new IllegalArgumentException("argument type mismatch");
                    }
                }
                // Non-primitive argument
                Unsafe.pushObject(arg);
            }
        }

        try {
            if (method.isReturnVoid()) {
                Unsafe.invokeVoid(method);
                return null;
            } else if (method.isReturnObject()) {
                return Unsafe.invokeObject(method);
            } else if (method.isReturnWide()) {
                long rc = Unsafe.invokeLong(method);
                final Class<?> retType = method.getReturnType().asClass();
                if (Long.TYPE == retType) {
                    return rc;
                } else {
                    return Double.longBitsToDouble(rc);
                }
            } else {
                int rc = Unsafe.invokeInt(method);
                final Class retType = method.getReturnType().asClass();
                if (Byte.TYPE == retType) {
                    return (byte) rc;
                } else if (Boolean.TYPE == retType) {
                    return rc != 0;
                } else if (Character.TYPE == retType) {
                    return (char) rc;
                } else if (Short.TYPE == retType) {
                    return (short) rc;
                } else if (Float.TYPE == retType) {
                    return Float.intBitsToFloat(rc);
                } else {
                    return rc;
                }
            }
        } catch (Throwable ex) {
            throw new InvocationTargetException(ex);
        }
    }

    /**
     * Create and return a new object using the given constructor and arguments
     *
     * @param constructor
     * @param args
     * @return Object
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static Object newInstance(VmMethod constructor, Object[] args)
        throws InstantiationException, IllegalAccessException,
        InvocationTargetException {
        final VmHeapManager hm = VmUtils.getVm().getHeapManager();
        final Object obj = hm.newInstance(constructor.getDeclaringClass());
        invoke(constructor, obj, args);
        return obj;
    }

    /**
     * Create and return a new object using the given constructor no arguments
     *
     * @param constructor
     * @return Object
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static Object newInstance(VmMethod constructor)
        throws InstantiationException, IllegalAccessException,
        InvocationTargetException {
        final VmHeapManager hm = VmUtils.getVm().getHeapManager();
        final Object obj = hm.newInstance(constructor.getDeclaringClass());
        Unsafe.pushObject(obj);
        Unsafe.invokeVoid(constructor);
        return obj;
    }

    /**
     * Initialize the class that declared this field if needed.
     *
     * @param sf
     */
    private static final void initialize(VmStaticField sf) {
        final VmType<?> declClass = sf.getDeclaringClass();
        if (!declClass.isAlwaysInitialized()) {
            if (!(sf.isPrimitive() && sf.isFinal())) {
                sf.getDeclaringClass().initialize();
            }
        }
    }
}
TOP

Related Classes of org.jnode.vm.VmReflection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.