/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.runtime; import org.jikesrvm.classloader.RVMMethod; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.NoInline; /** * Base class for all reflective method invoker classes, contains utility * methods that are invoked to unwrap the reflective arguments. Also contains * {@link #invoke(RVMMethod, Object, Object[])} that is called to perform the reflective * method call. */ public abstract class ReflectionBase { @NoInline private static void throwIllegalArgumentException() throws IllegalArgumentException { throw new IllegalArgumentException(); } @Inline protected static boolean unboxAsBoolean(Object obj) { if ((obj == null) || !(obj instanceof Boolean)) { throwIllegalArgumentException(); } return ((Boolean)obj).booleanValue(); } @Inline protected static Object boxAsBoolean(boolean b) { return b; } @Inline protected static byte unboxAsByte(Object obj) { if ((obj == null) || !(obj instanceof Byte)) { throwIllegalArgumentException(); } return ((Byte)obj).byteValue(); } @Inline protected static Object boxAsByte(byte b) { return b; } @Inline protected static short unboxAsShort(Object obj) { if ((obj == null) || (!(obj instanceof Short) && !(obj instanceof Byte))) { throwIllegalArgumentException(); } return ((Number)obj).shortValue(); } @Inline protected static Object boxAsShort(short s) { return s; } @Inline protected static char unboxAsChar(Object obj) { if ((obj == null) || !(obj instanceof Character)) { throwIllegalArgumentException(); } return ((Character)obj).charValue(); } @Inline protected static Object boxAsChar(char c) { return c; } @Inline protected static int unboxAsInt(Object obj) { if ((obj == null) || (!(obj instanceof Integer) && !(obj instanceof Character) && !(obj instanceof Short) && !(obj instanceof Byte))) { throwIllegalArgumentException(); } return ((Number)obj).intValue(); } @Inline protected static Object boxAsInt(int i) { return i; } @Inline protected static long unboxAsLong(Object obj) { if ((obj == null) || (!(obj instanceof Long) && !(obj instanceof Integer) && !(obj instanceof Character) && !(obj instanceof Short) && !(obj instanceof Byte))) { throwIllegalArgumentException(); } return ((Number)obj).longValue(); } @Inline protected static Object boxAsLong(long l) { return l; } @Inline protected static float unboxAsFloat(Object obj) { if ((obj == null) || !(obj instanceof Float)) { throwIllegalArgumentException(); } return ((Float)obj).floatValue(); } @Inline protected static Object boxAsFloat(float f) { return f; } @Inline protected static double unboxAsDouble(Object obj) { if ((obj == null) || (!(obj instanceof Double) && !(obj instanceof Float))) { throwIllegalArgumentException(); } return ((Number)obj).doubleValue(); } @Inline protected static Object boxAsDouble(double d) { return d; } /** * Invoke reflective method being wrapped by this object, internal method * specific part. * @param obj object for virtual method invocation * @param args arguments to method call * @return the object that is the result of the invoke */ public abstract Object invokeInternal(Object obj, Object[] args); /** * Invoke reflective method being wrapped by this object * @param method the method to invoke * @param obj object for virtual method invocation * @param args arguments to method call * @return the object that is the result of the invoke */ public final Object invoke(RVMMethod method, Object obj, Object[] args) { int argsLength = args == null ? 0 : args.length; if (method.getParameterTypes().length != argsLength) { throwIllegalArgumentException(); } try { return invokeInternal(obj, args); } catch (ClassCastException e) { // FIXME: This is fragile and ill-advised way to handle this situation // I think A more robust way to handle it would be to put in the appropriate // try/catch structure in the generated bytecodes and handle it there. if (e.getStackTrace().length == (new Throwable()).getStackTrace().length + 6) { throw new IllegalArgumentException("argument type mismatch", e); } else { throw e; } } } /** * Reflective method invoker that performs no invocation */ public static final ReflectionBase nullInvoker = new ReflectionBase() { @Override public Object invokeInternal(Object obj, Object[] args) { return null; } }; }