/*
* 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;
}
};
}