clean up Array.get(), Array.set(), and Method.invoke() implementations

This commit is contained in:
Joel Dice 2007-08-18 11:53:30 -06:00
parent d169e4eadf
commit aa5e751e69
6 changed files with 170 additions and 157 deletions

View File

@ -6,6 +6,8 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public final class Class <T> {
private static final int PrimitiveFlag = 1 << 4;
private short flags;
private byte vmFlags;
private byte arrayDimensions;
@ -330,14 +332,6 @@ public final class Class <T> {
}
public boolean isPrimitive() {
return equals(boolean.class)
|| equals(byte.class)
|| equals(char.class)
|| equals(short.class)
|| equals(int.class)
|| equals(long.class)
|| equals(float.class)
|| equals(double.class)
|| equals(void.class);
return (vmFlags & PrimitiveFlag) != 0;
}
}

View File

@ -3,9 +3,86 @@ package java.lang.reflect;
public final class Array {
private Array() { }
public static native Object get(Object array, int index);
public static Object get(Object array, int index) {
String className = array.getClass().getName();
if (! className.startsWith("[")) {
throw new IllegalArgumentException();
}
public static native void set(Object array, int index, Object value);
switch (className.charAt(1)) {
case 'B':
return Byte.valueOf(((byte[]) array)[index]);
case 'C':
return Character.valueOf(((char[]) array)[index]);
case 'D':
return Double.valueOf(((double[]) array)[index]);
case 'F':
return Float.valueOf(((float[]) array)[index]);
case 'I':
return Integer.valueOf(((int[]) array)[index]);
case 'J':
return Long.valueOf(((long[]) array)[index]);
case 'S':
return Short.valueOf(((short[]) array)[index]);
case 'Z':
return Boolean.valueOf(((boolean[]) array)[index]);
case 'L':
case '[':
return getObject(array, index);
default:
throw new Error();
}
}
private static native Object getObject(Object array, int index);
public static void set(Object array, int index, Object value) {
String className = array.getClass().getName();
if (! className.startsWith("[")) {
throw new IllegalArgumentException();
}
switch (className.charAt(1)) {
case 'B':
((byte[]) array)[index] = (Byte) value;
break;
case 'C':
((char[]) array)[index] = (Character) value;
break;
case 'D':
((double[]) array)[index] = (Double) value;
break;
case 'F':
((float[]) array)[index] = (Float) value;
break;
case 'I':
((int[]) array)[index] = (Integer) value;
break;
case 'J':
((long[]) array)[index] = (Long) value;
break;
case 'S':
((short[]) array)[index] = (Short) value;
break;
case 'Z':
((boolean[]) array)[index] = (Boolean) value;
break;
case 'L':
case '[':
if (array.getClass().getComponentType().isInstance(value)) {
setObject(array, index, value);
} else {
throw new IllegalArgumentException();
}
break;
default:
throw new Error();
}
}
private static native void setObject(Object array, int index, Object value);
public static native int getLength(Object array);
@ -16,22 +93,26 @@ public final class Array {
throw new NegativeArraySizeException();
}
if (elementType.equals(boolean.class)) {
return new boolean[length];
} else if (elementType.equals(byte.class)) {
return new byte[length];
} else if (elementType.equals(char.class)) {
return new char[length];
} else if (elementType.equals(short.class)) {
return new short[length];
} else if (elementType.equals(int.class)) {
return new int[length];
} else if (elementType.equals(long.class)) {
return new long[length];
} else if (elementType.equals(float.class)) {
return new float[length];
} else if (elementType.equals(double.class)) {
return new double[length];
if (elementType.isPrimitive()) {
if (elementType.equals(boolean.class)) {
return new boolean[length];
} else if (elementType.equals(byte.class)) {
return new byte[length];
} else if (elementType.equals(char.class)) {
return new char[length];
} else if (elementType.equals(short.class)) {
return new short[length];
} else if (elementType.equals(int.class)) {
return new int[length];
} else if (elementType.equals(long.class)) {
return new long[length];
} else if (elementType.equals(float.class)) {
return new float[length];
} else if (elementType.equals(double.class)) {
return new double[length];
} else {
throw new IllegalArgumentException();
}
} else {
return makeObjectArray(elementType, length);
}

View File

@ -87,6 +87,27 @@ public class Method<T> extends AccessibleObject implements Member {
return types;
}
public native Object invoke(Object instance, Object ... arguments)
public Object invoke(Object instance, Object ... arguments)
throws InvocationTargetException, IllegalAccessException
{
if ((flags & Modifier.STATIC) != 0) {
if (arguments.length == parameterCount) {
return invoke(this, instance, arguments);
} else {
throw new ArrayIndexOutOfBoundsException();
}
} else if (class_.isInstance(instance)) {
if (arguments.length == parameterCount - 1) {
return invoke(this, instance, arguments);
} else {
throw new ArrayIndexOutOfBoundsException();
}
} else {
throw new IllegalArgumentException();
}
}
public static native Object invoke(Method method, Object instance,
Object ... arguments)
throws InvocationTargetException, IllegalAccessException;
}

View File

@ -7,16 +7,6 @@ using namespace vm;
namespace {
object
doInvoke(Thread* t, object this_, object instance, object arguments)
{
object v = run2(t, this_, instance, arguments);
if (t->exception) {
t->exception = makeInvocationTargetException(t, t->exception);
}
return v;
}
inline void
replace(char a, char b, char* c)
{
@ -261,10 +251,10 @@ Field_setPrimitive(Thread* t, jclass, jobject instance, jint code, jint offset,
}
void
Field_setObject(Thread*, jclass, jobject instance, jint offset,
Field_setObject(Thread* t, jclass, jobject instance, jint offset,
jobject value)
{
cast<object>(*instance, offset) = (value ? *value : 0);
set(t, cast<object>(*instance, offset), (value ? *value : 0));
}
jobject
@ -281,129 +271,26 @@ Method_getCaller(Thread* t, jclass)
}
jobject
Method_invoke(Thread* t, jobject this_, jobject instancep,
jobjectArray argumentsp)
Method_invoke(Thread* t, jclass, jobject method, jobject instance,
jobjectArray arguments)
{
object method = *this_;
if (argumentsp) {
object arguments = *argumentsp;
if (methodFlags(t, method) & ACC_STATIC) {
if (objectArrayLength(t, arguments)
== methodParameterCount(t, method))
{
return pushReference(t, doInvoke(t, method, 0, arguments));
} else {
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
}
} else if (instancep) {
object instance = *instancep;
if (instanceOf(t, methodClass(t, method), instance)) {
if (objectArrayLength(t, arguments)
== static_cast<unsigned>(methodParameterCount(t, method) - 1))
{
return pushReference(t, doInvoke(t, method, instance, arguments));
} else {
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
}
}
} else {
t->exception = makeNullPointerException(t);
}
} else {
t->exception = makeNullPointerException(t);
object v = run2(t, *method, (instance ? *instance : 0), *arguments);
if (t->exception) {
t->exception = makeInvocationTargetException(t, t->exception);
}
return 0;
return pushReference(t, v);
}
jobject
Array_get(Thread* t, jobject array, int index)
Array_getObject(Thread* t, jobject array, int index)
{
if (LIKELY(array)) {
object a = *array;
unsigned elementSize = classArrayElementSize(t, objectClass(t, a));
if (LIKELY(elementSize)) {
intptr_t length = cast<uintptr_t>(a, BytesPerWord);
if (LIKELY(index >= 0 and index < length)) {
switch (byteArrayBody(t, className(t, objectClass(t, a)), 1)) {
case 'B':
return pushReference(t, makeByte(t, byteArrayBody(t, a, index)));
case 'C':
return pushReference(t, makeChar(t, charArrayBody(t, a, index)));
case 'D':
return pushReference(t, makeDouble(t, doubleArrayBody(t, a, index)));
case 'F':
return pushReference(t, makeFloat(t, floatArrayBody(t, a, index)));
case 'I':
return pushReference(t, makeInt(t, intArrayBody(t, a, index)));
case 'J':
return pushReference(t, makeLong(t, longArrayBody(t, a, index)));
case 'S':
return pushReference(t, makeShort(t, shortArrayBody(t, a, index)));
case 'Z':
return pushReference
(t, makeBoolean(t, booleanArrayBody(t, a, index)));
case 'L':
case '[':
return pushReference(t, objectArrayBody(t, a, index));
default: abort(t);
}
} else {
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
}
} else {
t->exception = makeIllegalArgumentException(t);
}
} else {
t->exception = makeNullPointerException(t);
}
return 0;
return pushReference(t, objectArrayBody(t, *array, index));
}
void
Array_set(Thread* t, jobject array, int index, jobject value)
Array_setObject(Thread* t, jobject array, int index, jobject value)
{
if (LIKELY(array)) {
object a = *array;
object v = (value ? *value : 0);
unsigned elementSize = classArrayElementSize(t, objectClass(t, a));
if (LIKELY(elementSize)) {
intptr_t length = cast<uintptr_t>(a, BytesPerWord);
if (LIKELY(index >= 0 and index < length)) {
switch (byteArrayBody(t, className(t, objectClass(t, a)), 1)) {
case 'L':
case '[':
set(t, objectArrayBody(t, a, index), v);
break;
default: {
uint8_t* p = &cast<uint8_t>
(a, (2 * BytesPerWord) + (index * elementSize));
if (v) {
memcpy(p, &cast<uint8_t>(v, BytesPerWord), elementSize);
} else {
t->exception = makeNullPointerException(t);
}
} break;
}
} else {
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
}
} else {
t->exception = makeIllegalArgumentException(t);
}
} else {
t->exception = makeNullPointerException(t);
}
set(t, objectArrayBody(t, *array, index), (value ? *value : 0));
}
jint
@ -749,6 +636,16 @@ populateBuiltinMap(Thread* t, object map)
{ "Java_java_lang_Throwable_trace",
reinterpret_cast<void*>(::Throwable_trace) },
{ "Java_java_lang_Float_floatToRawIntBits",
reinterpret_cast<void*>(::Float_floatToRawIntBits) },
{ "Java_java_lang_Float_intBitsToFloat",
reinterpret_cast<void*>(::Float_intBitsToFloat) },
{ "Java_java_lang_Double_doubleToRawLongBits",
reinterpret_cast<void*>(::Double_doubleToRawLongBits) },
{ "Java_java_lang_Double_longBitsToDouble",
reinterpret_cast<void*>(::Double_longBitsToDouble) },
{ "Java_java_lang_Object_getClass",
reinterpret_cast<void*>(::Object_getClass) },
{ "Java_java_lang_Object_notify",
@ -764,10 +661,10 @@ populateBuiltinMap(Thread* t, object map)
{ "Java_java_lang_Object_clone",
reinterpret_cast<void*>(::Object_clone) },
{ "Java_java_lang_reflect_Array_get",
reinterpret_cast<void*>(::Array_get) },
{ "Java_java_lang_reflect_Array_set",
reinterpret_cast<void*>(::Array_set) },
{ "Java_java_lang_reflect_Array_getObject",
reinterpret_cast<void*>(::Array_getObject) },
{ "Java_java_lang_reflect_Array_setObject",
reinterpret_cast<void*>(::Array_setObject) },
{ "Java_java_lang_reflect_Array_getLength",
reinterpret_cast<void*>(::Array_getLength) },
{ "Java_java_lang_reflect_Array_makeObjectArray",

View File

@ -1364,6 +1364,25 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JcharType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JshortType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JintType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JlongType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType))
|= PrimitiveFlag;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
#include "type-java-initializations.cpp"

View File

@ -60,6 +60,7 @@ const unsigned ReferenceFlag = 1 << 0;
const unsigned WeakReferenceFlag = 1 << 1;
const unsigned NeedInitFlag = 1 << 2;
const unsigned InitFlag = 1 << 3;
const unsigned PrimitiveFlag = 1 << 4;
// method flags:
const unsigned ClassInitFlag = 1 << 0;