fix various Android test suite regressions and add more reflection tests

Most of these regressions were simply due to testing a lot more stuff,
esp. annotations and reflection, revealing holes in the Android
compatibility code.  There are still some holes, but at least the
suite is passing (except for a fragile test in Serialize.java which I
will open an issue for).

Sorry this is such a big commit; there was more to address than I
initially expected.
This commit is contained in:
Joel Dice 2013-12-06 15:45:46 -07:00
parent 39e3850ed8
commit 7056315c18
9 changed files with 769 additions and 128 deletions

View File

@ -441,6 +441,39 @@ public class Classes {
return array;
}
public static int countFields(VMClass vmClass, boolean publicOnly) {
int count = 0;
if (vmClass.fieldTable != null) {
for (int i = 0; i < vmClass.fieldTable.length; ++i) {
if ((! publicOnly)
|| ((vmClass.fieldTable[i].flags & Modifier.PUBLIC))
!= 0)
{
++ count;
}
}
}
return count;
}
public static Field[] getFields(VMClass vmClass, boolean publicOnly) {
Field[] array = new Field[countFields(vmClass, publicOnly)];
if (vmClass.fieldTable != null) {
Classes.link(vmClass);
int ai = 0;
for (int i = 0; i < vmClass.fieldTable.length; ++i) {
if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC) != 0)
|| (! publicOnly))
{
array[ai++] = makeField(SystemClassLoader.getClass(vmClass), i);
}
}
}
return array;
}
public static Annotation getAnnotation(ClassLoader loader, Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
@ -469,7 +502,21 @@ public class Classes {
}
}
private static int index(VMMethod m) {
VMMethod[] table = m.class_.methodTable;
for (int i = 0; i < table.length; ++i) {
if (m == table[i]) return i;
}
throw new AssertionError();
}
public static Method makeMethod(VMMethod m) {
return makeMethod(SystemClassLoader.getClass(m.class_), index(m));
}
public static native Method makeMethod(Class c, int slot);
public static native Field makeField(Class c, int slot);
private static native void acquireClassLock();

View File

@ -11,4 +11,5 @@
package java.lang.annotation;
public interface Annotation {
Class<? extends Annotation> annotationType();
}

View File

@ -161,6 +161,40 @@ public class Field<T> extends AccessibleObject {
return ((Double) get(instance)).doubleValue();
}
private boolean matchType(Object value) {
switch (vmField.code) {
case ByteField:
return value instanceof Byte;
case BooleanField:
return value instanceof Boolean;
case CharField:
return value instanceof Character;
case ShortField:
return value instanceof Short;
case IntField:
return value instanceof Integer;
case LongField:
return value instanceof Long;
case FloatField:
return value instanceof Float;
case DoubleField:
return value instanceof Double;
case ObjectField:
return value == null || getType().isInstance(value);
default:
throw new Error();
}
}
public void set(Object instance, Object value)
throws IllegalAccessException
{
@ -173,6 +207,10 @@ public class Field<T> extends AccessibleObject {
throw new IllegalArgumentException();
}
if (! matchType(value)) {
throw new IllegalArgumentException();
}
Classes.initialize(vmField.class_);
switch (vmField.code) {
@ -212,14 +250,7 @@ public class Field<T> extends AccessibleObject {
break;
case ObjectField:
if (value == null || getType().isInstance(value)) {
setObject(target, vmField.offset, value);
} else {
throw new IllegalArgumentException
("needed " + getType() + ", got "
+ value.getClass().getName() +
" when setting " + Class.getName(vmField.class_) + "." + getName());
}
setObject(target, vmField.offset, value);
break;
default:

View File

@ -384,7 +384,7 @@ public class Proxy {
ConstantPool.addUtf8(pool, Classes.toString(m.spec)),
makeInvokeCode(pool, name, m.spec, m.parameterCount,
m.parameterFootprint, methodTable.size())));
refs.add(new Method(m));
refs.add(Classes.makeMethod(m));
}
}
}

View File

@ -674,6 +674,78 @@ getFinder(Thread* t, const char* name, unsigned nameLength)
return 0;
}
object
getDeclaredClasses(Thread* t, object c, bool publicOnly)
{
object addendum = classAddendum(t, c);
if (addendum) {
object table = classAddendumInnerClassTable(t, addendum);
if (table) {
PROTECT(t, table);
unsigned count = 0;
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object reference = arrayBody(t, table, i);
object outer = innerClassReferenceOuter(t, reference);
if (outer and byteArrayEqual(t, outer, className(t, c))
and ((not publicOnly)
or (innerClassReferenceFlags(t, reference) & ACC_PUBLIC)))
{
++ count;
}
}
object result = makeObjectArray(t, type(t, Machine::JclassType), count);
PROTECT(t, result);
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object reference = arrayBody(t, table, i);
object outer = innerClassReferenceOuter(t, reference);
if (outer and byteArrayEqual(t, outer, className(t, c))
and ((not publicOnly)
or (innerClassReferenceFlags(t, reference) & ACC_PUBLIC)))
{
object inner = getJClass
(t, resolveClass
(t, classLoader(t, c),
innerClassReferenceInner(t, arrayBody(t, table, i))));
-- count;
set(t, result, ArrayBody + (count * BytesPerWord), inner);
}
}
return result;
}
}
return makeObjectArray(t, type(t, Machine::JclassType), 0);
}
object
getDeclaringClass(Thread* t, object c)
{
object addendum = classAddendum(t, c);
if (addendum) {
object table = classAddendumInnerClassTable(t, addendum);
if (table) {
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object reference = arrayBody(t, table, i);
if (strcmp
(&byteArrayBody(t, innerClassReferenceInner(t, reference), 0),
&byteArrayBody(t, className(t, c), 0)) == 0)
{
return getJClass
(t, resolveClass
(t, classLoader(t, c), innerClassReferenceOuter(t, reference)));
}
}
}
}
return 0;
}
} // namespace vm
#endif//CLASSPATH_COMMON_H

View File

@ -142,11 +142,12 @@ makeField(Thread* t, object c, unsigned index)
PROTECT(t, field);
object type = resolveClassBySpec
(t, classLoader(t, fieldClass(t, field)),
reinterpret_cast<char*>
(&byteArrayBody(t, fieldSpec(t, field), 0)),
byteArrayLength(t, fieldSpec(t, field)) - 1);
object type = getJClass
(t, resolveClassBySpec
(t, classLoader(t, fieldClass(t, field)),
reinterpret_cast<char*>
(&byteArrayBody(t, fieldSpec(t, field), 0)),
byteArrayLength(t, fieldSpec(t, field)) - 1));
PROTECT(t, type);
object name = t->m->classpath->makeString
@ -604,6 +605,177 @@ closeMemoryMappedFile(Thread* t, object method, uintptr_t* arguments)
file);
}
bool
matchType(Thread* t, object field, object o)
{
switch (fieldCode(t, field)) {
case ByteField:
return objectClass(t, o) == type(t, Machine::ByteType);
case BooleanField:
return objectClass(t, o) == type(t, Machine::BooleanType);
case CharField:
return objectClass(t, o) == type(t, Machine::CharType);
case ShortField:
return objectClass(t, o) == type(t, Machine::ShortType);
case IntField:
return objectClass(t, o) == type(t, Machine::IntType);
case LongField:
return objectClass(t, o) == type(t, Machine::LongType);
case FloatField:
return objectClass(t, o) == type(t, Machine::FloatType);
case DoubleField:
return objectClass(t, o) == type(t, Machine::DoubleType);
case ObjectField:
if (o == 0) {
return true;
} else {
PROTECT(t, o);
object spec;
if (byteArrayBody(t, fieldSpec(t, field), 0) == '[') {
spec = fieldSpec(t, field);;
} else {
spec = makeByteArray(t, byteArrayLength(t, fieldSpec(t, field)) - 2);
memcpy(&byteArrayBody(t, spec, 0),
&byteArrayBody(t, fieldSpec(t, field), 1),
byteArrayLength(t, fieldSpec(t, field)) - 3);
byteArrayBody
(t, spec, byteArrayLength(t, fieldSpec(t, field)) - 3) = 0;
}
return instanceOf
(t, resolveClass(t, classLoader(t, fieldClass(t, field)), spec), o);
}
default: abort(t);
}
}
object
getField(Thread* t, object field, object instance)
{
PROTECT(t, field);
PROTECT(t, instance);
initClass(t, fieldClass(t, field));
object target;
if (fieldFlags(t, field) & ACC_STATIC) {
target = classStaticTable(t, fieldClass(t, field));
} else if (instanceOf(t, fieldClass(t, field), instance)){
target = instance;
} else {
throwNew(t, Machine::IllegalArgumentExceptionType);
}
unsigned offset = fieldOffset(t, field);
switch (fieldCode(t, field)) {
case ByteField:
return makeByte(t, fieldAtOffset<int8_t>(target, offset));
case BooleanField:
return makeBoolean(t, fieldAtOffset<int8_t>(target, offset));
case CharField:
return makeChar(t, fieldAtOffset<int16_t>(target, offset));
case ShortField:
return makeShort(t, fieldAtOffset<int16_t>(target, offset));
case IntField:
return makeInt(t, fieldAtOffset<int32_t>(target, offset));
case LongField:
return makeLong(t, fieldAtOffset<int64_t>(target, offset));
case FloatField:
return makeFloat(t, fieldAtOffset<int32_t>(target, offset));
case DoubleField:
return makeDouble(t, fieldAtOffset<int64_t>(target, offset));
case ObjectField:
return fieldAtOffset<object>(target, offset);
default: abort(t);
}
}
void
setField(Thread* t, object field, object instance, object value)
{
PROTECT(t, field);
PROTECT(t, instance);
PROTECT(t, value);
if (not matchType(t, field, value)) {
throwNew(t, Machine::IllegalArgumentExceptionType);
}
object target;
if ((fieldFlags(t, field) & ACC_STATIC) != 0) {
target = classStaticTable(t, fieldClass(t, field));
} else if (instanceOf(t, fieldClass(t, field), instance)){
target = instance;
} else {
throwNew(t, Machine::IllegalArgumentExceptionType);
}
PROTECT(t, target);
initClass(t, fieldClass(t, field));
unsigned offset = fieldOffset(t, field);
switch (fieldCode(t, field)) {
case ByteField:
fieldAtOffset<int8_t>(target, offset) = byteValue(t, value);
break;
case BooleanField:
fieldAtOffset<int8_t>(target, offset) = booleanValue(t, value);
break;
case CharField:
fieldAtOffset<int16_t>(target, offset) = charValue(t, value);
break;
case ShortField:
fieldAtOffset<int16_t>(target, offset) = shortValue(t, value);
break;
case IntField:
fieldAtOffset<int32_t>(target, offset) = intValue(t, value);
break;
case LongField:
fieldAtOffset<int64_t>(target, offset) = longValue(t, value);
break;
case FloatField:
fieldAtOffset<int32_t>(target, offset) = floatValue(t, value);
break;
case DoubleField:
fieldAtOffset<int64_t>(target, offset) = doubleValue(t, value);
break;
case ObjectField:
set(t, target, offset, value);
break;
default: abort(t);
}
}
} // namespace local
} // namespace
@ -788,6 +960,14 @@ Avian_java_lang_String_length
return stringLength(t, reinterpret_cast<object>(arguments[0]));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_String_intern
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<intptr_t>
(intern(t, reinterpret_cast<object>(arguments[0])));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_String_charAt
(Thread* t, object, uintptr_t* arguments)
@ -849,6 +1029,63 @@ Avian_java_lang_Class_getInterfaces
(makeObjectArray(t, type(t, Machine::JclassType), 0));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_getDeclaredClasses
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<intptr_t>
(getDeclaredClasses
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[0])),
arguments[1]));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_getDeclaringClass
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<intptr_t>
(getDeclaringClass
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[0]))));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_getEnclosingMethod
(Thread* t, object, uintptr_t* arguments)
{
object c = jclassVmClass(t, reinterpret_cast<object>(arguments[0]));
PROTECT(t, c);
object addendum = classAddendum(t, c);
if (addendum) {
object enclosingClass = classAddendumEnclosingClass(t, addendum);
if (enclosingClass) {
PROTECT(t, enclosingClass);
enclosingClass = getJClass
(t, resolveClass(t, classLoader(t, c), enclosingClass));
object enclosingMethod = classAddendumEnclosingMethod(t, addendum);
if (enclosingMethod) {
PROTECT(t, enclosingMethod);
return reinterpret_cast<uintptr_t>
(t->m->classpath->makeJMethod
(t, findMethodInClass
(t, enclosingClass, pairFirst(t, enclosingMethod),
pairSecond(t, enclosingMethod))));
}
}
}
return 0;
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_getEnclosingConstructor
(Thread* t, object method, uintptr_t* arguments)
{
return Avian_java_lang_Class_getEnclosingMethod(t, method, arguments);
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_newInstanceImpl
(Thread* t, object, uintptr_t* arguments)
@ -1201,6 +1438,50 @@ Avian_dalvik_system_VMStack_getCallingClassLoader
return reinterpret_cast<uintptr_t>(v.loader);
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_dalvik_system_VMStack_getClasses
(Thread* t, object, uintptr_t*)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t):
t(t), array(0), counter(0)
{ }
virtual bool visit(Processor::StackWalker* walker) {
if (counter < 2) {
return true;
} else {
if (array == 0) {
array = makeObjectArray
(t, type(t, Machine::JclassType), walker->count());
}
object c = getJClass(t, methodClass(t, walker->method()));
assert(t, counter - 2 < objectArrayLength(t, array));
set(t, array, ArrayBody + ((counter - 2) * BytesPerWord), c);
return true;
}
++ counter;
}
Thread* t;
object array;
unsigned counter;
} v(t);
PROTECT(t, v.array);
t->m->processor->walkStack(t, &v);
return reinterpret_cast<uintptr_t>
(v.array ? v.array : makeObjectArray(t, type(t, Machine::JclassType), 0));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Math_min
(Thread*, object, uintptr_t* arguments)
@ -1391,6 +1672,23 @@ Avian_java_lang_Class_isPrimitive
& PrimitiveFlag) != 0;
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_isAnonymousClass
(Thread* t, object, uintptr_t* arguments)
{
object name = className
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[0])));
for (unsigned i = 0; i < byteArrayLength(t, name) - 1; ++i) {
int c = byteArrayBody(t, name, i);
if (c != '$' and (c < '0' or c > '9')) {
return false;
}
}
return true;
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_getClassLoader
(Thread* t, object, uintptr_t* arguments)
@ -1446,6 +1744,23 @@ Avian_java_lang_Class_getDeclaredMethods
(t->m->processor->invoke(t, get, 0, jclassVmClass(t, c), publicOnly));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Class_getDeclaredFields
(Thread* t, object, uintptr_t* arguments)
{
object c = reinterpret_cast<object>(arguments[0]);
PROTECT(t, c);
bool publicOnly = arguments[1];
object get = resolveMethod
(t, root(t, Machine::BootLoader), "avian/Classes", "getFields",
"(Lavian/VMClass;Z)[Ljava/lang/reflect/Field;");
return reinterpret_cast<uintptr_t>
(t->m->processor->invoke(t, get, 0, jclassVmClass(t, c), publicOnly));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Method_invokeNative
(Thread* t, object, uintptr_t* arguments)
@ -1581,6 +1896,31 @@ Avian_java_lang_reflect_Method_getDeclaredAnnotations
0));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Method_getDefaultValue
(Thread* t, object, uintptr_t* arguments)
{
object method = arrayBody
(t, classMethodTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[1]))),
arguments[2]);
object addendum = methodAddendum(t, method);
if (addendum) {
object get = resolveMethod
(t, root(t, Machine::BootLoader), "avian/Classes",
"getAnnotationDefaultValue",
"(Ljava/lang/ClassLoader;Lavian/MethodAddendum;)"
"Ljava/lang/Object;");
return reinterpret_cast<uintptr_t>
(t->m->processor->invoke
(t, get, 0, classLoader(t, methodClass(t, method)), addendum));
}
return 0;
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Constructor_constructNative
(Thread* t, object, uintptr_t* arguments)
@ -1589,6 +1929,9 @@ Avian_java_lang_reflect_Constructor_constructNative
PROTECT(t, args);
object c = jclassVmClass(t, reinterpret_cast<object>(arguments[2]));
PROTECT(t, c);
initClass(t, c);
object method = arrayBody(t, classMethodTable(t, c), arguments[4]);
PROTECT(t, method);
@ -1609,16 +1952,84 @@ Avian_java_lang_reflect_Field_getField
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[2]))),
arguments[4]);
PROTECT(t, field);
if (fieldFlags(t, field) & ACC_STATIC) {
return reinterpret_cast<uintptr_t>
(fieldAtOffset<object>
(classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field)));
} else {
return reinterpret_cast<uintptr_t>
(fieldAtOffset<object>
(reinterpret_cast<object>(arguments[1]), fieldOffset(t, field)));
}
object instance = reinterpret_cast<object>(arguments[1]);
PROTECT(t, instance);
return reinterpret_cast<intptr_t>(local::getField(t, field, instance));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Field_getIField
(Thread* t, object, uintptr_t* arguments)
{
object field = arrayBody
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[2]))),
arguments[4]);
PROTECT(t, field);
object instance = reinterpret_cast<object>(arguments[1]);
PROTECT(t, instance);
return intValue(t, local::getField(t, field, instance));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Field_getJField
(Thread* t, object, uintptr_t* arguments)
{
object field = arrayBody
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[2]))),
arguments[4]);
PROTECT(t, field);
object instance = reinterpret_cast<object>(arguments[1]);
PROTECT(t, instance);
return longValue(t, local::getField(t, field, instance));
}
extern "C" AVIAN_EXPORT void JNICALL
Avian_java_lang_reflect_Field_setField
(Thread* t, object, uintptr_t* arguments)
{
object field = arrayBody
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[2]))),
arguments[4]);
PROTECT(t, field);
object instance = reinterpret_cast<object>(arguments[1]);
PROTECT(t, instance);
object value = reinterpret_cast<object>(arguments[6]);
PROTECT(t, value);
local::setField(t, field, instance, value);
}
extern "C" AVIAN_EXPORT void JNICALL
Avian_java_lang_reflect_Field_setIField
(Thread* t, object, uintptr_t* arguments)
{
object field = arrayBody
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[2]))),
arguments[4]);
object instance = reinterpret_cast<object>(arguments[1]);
PROTECT(t, instance);
object value = makeInt(t, arguments[7]);
local::setField(t, field, instance, value);
}
extern "C" AVIAN_EXPORT int64_t JNICALL
@ -1632,6 +2043,71 @@ Avian_java_lang_reflect_Field_getFieldModifiers
arguments[2]));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Field_getAnnotation
(Thread* t, object, uintptr_t* arguments)
{
object field = arrayBody
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[0]))),
arguments[1]);
object addendum = fieldAddendum(t, field);
if (addendum) {
object table = addendumAnnotationTable(t, addendum);
if (table) {
for (unsigned i = 0; i < objectArrayLength(t, table); ++i) {
if (objectArrayBody(t, objectArrayBody(t, table, i), 1)
== reinterpret_cast<object>(arguments[2]))
{
PROTECT(t, field);
PROTECT(t, table);
object get = resolveMethod
(t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotation",
"(Ljava/lang/ClassLoader;[Ljava/lang/Object;)"
"Ljava/lang/annotation/Annotation;");
return reinterpret_cast<uintptr_t>
(t->m->processor->invoke
(t, get, 0, classLoader(t, fieldClass(t, field)),
objectArrayBody(t, table, i)));
}
}
}
}
return false;
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Field_getSignatureAnnotation
(Thread* t, object, uintptr_t* arguments)
{
object field = arrayBody
(t, classFieldTable
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[1]))),
arguments[2]);
object addendum = fieldAddendum(t, field);
if (addendum) {
object signature = addendumSignature(t, addendum);
if (signature) {
object array = makeObjectArray(t, 1);
PROTECT(t, array);
object string = t->m->classpath->makeString
(t, signature, 0, byteArrayLength(t, signature) - 1);
set(t, array, ArrayBody, string);
return reinterpret_cast<uintptr_t>(array);
}
}
return reinterpret_cast<uintptr_t>(makeObjectArray(t, 0));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_Throwable_nativeFillInStackTrace
(Thread* t, object, uintptr_t*)
@ -1656,6 +2132,15 @@ Avian_avian_Classes_makeMethod
(t, reinterpret_cast<object>(arguments[0]), arguments[1]));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_avian_Classes_makeField
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<uintptr_t>
(local::makeField
(t, reinterpret_cast<object>(arguments[0]), arguments[1]));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_java_lang_reflect_Array_createObjectArray
(Thread* t, object, uintptr_t* arguments)

View File

@ -4297,49 +4297,10 @@ EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c)
uint64_t
jvmGetDeclaredClasses(Thread* t, uintptr_t* arguments)
{
jclass c = reinterpret_cast<jobject>(arguments[0]);
object addendum = classAddendum(t, jclassVmClass(t, *c));
if (addendum) {
object table = classAddendumInnerClassTable(t, addendum);
if (table) {
PROTECT(t, table);
unsigned count = 0;
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object outer = innerClassReferenceOuter(t, arrayBody(t, table, i));
if (outer and byteArrayEqual
(t, outer, className(t, jclassVmClass(t, *c))))
{
++ count;
}
}
object result = makeObjectArray(t, type(t, Machine::JclassType), count);
PROTECT(t, result);
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object outer = innerClassReferenceOuter(t, arrayBody(t, table, i));
if (outer and byteArrayEqual
(t, outer, className(t, jclassVmClass(t, *c))))
{
object inner = getJClass
(t, resolveClass
(t, classLoader(t, jclassVmClass(t, *c)),
innerClassReferenceInner(t, arrayBody(t, table, i))));
-- count;
set(t, result, ArrayBody + (count * BytesPerWord), inner);
}
}
return reinterpret_cast<uintptr_t>(makeLocalReference(t, result));
}
}
return reinterpret_cast<uintptr_t>
(makeLocalReference
(t, makeObjectArray(t, type(t, Machine::JclassType), 0)));
(t, getDeclaredClasses
(t, jclassVmClass(t, *reinterpret_cast<jobject>(arguments[0])), false)));
}
extern "C" AVIAN_EXPORT jobjectArray JNICALL
@ -4353,31 +4314,10 @@ EXPORT(JVM_GetDeclaredClasses)(Thread* t, jclass c)
uint64_t
jvmGetDeclaringClass(Thread* t, uintptr_t* arguments)
{
jclass c = reinterpret_cast<jobject>(arguments[0]);
object class_ = jclassVmClass(t, *c);
object addendum = classAddendum(t, class_);
if (addendum) {
object table = classAddendumInnerClassTable(t, addendum);
if (table) {
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object reference = arrayBody(t, table, i);
if (strcmp
(&byteArrayBody(t, innerClassReferenceInner(t, reference), 0),
&byteArrayBody(t, className(t, class_), 0)) == 0)
{
return reinterpret_cast<uintptr_t>
(makeLocalReference
(t, getJClass
(t, resolveClass
(t, classLoader(t, class_), innerClassReferenceOuter
(t, reference)))));
}
}
}
}
return 0;
return reinterpret_cast<uintptr_t>
(makeLocalReference
(t, getDeclaringClass
(t, jclassVmClass(t, *reinterpret_cast<jobject>(arguments[0])))));
}
extern "C" AVIAN_EXPORT jclass JNICALL

View File

@ -1947,9 +1947,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
object superVirtualTable = 0;
PROTECT(t, superVirtualTable);
if (classFlags(t, class_) & ACC_INTERFACE) {
addInterfaceMethods(t, class_, virtualMap, &virtualCount, false);
} else {
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
if (classSuper(t, class_)) {
superVirtualTable = classVirtualTable(t, classSuper(t, class_));
}
@ -2144,13 +2142,10 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
set(t, class_, ClassMethodTable, methodTable);
}
object abstractVirtuals;
if (classFlags(t, class_) & ACC_INTERFACE) {
abstractVirtuals = 0;
} else {
abstractVirtuals = addInterfaceMethods
(t, class_, virtualMap, &virtualCount, true);
}
object abstractVirtuals = addInterfaceMethods
(t, class_, virtualMap, &virtualCount, true);
PROTECT(t, abstractVirtuals);
bool populateInterfaceVtables = false;
@ -2212,43 +2207,45 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p));
++ i;
}
}
if (abstractVirtuals) {
PROTECT(t, vtable);
if (abstractVirtuals) {
PROTECT(t, vtable);
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, ClassAddendumMethodTable,
classMethodTable(t, class_));
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, ClassAddendumMethodTable,
classMethodTable(t, class_));
unsigned oldLength = classMethodTable(t, class_) ?
arrayLength(t, classMethodTable(t, class_)) : 0;
unsigned oldLength = classMethodTable(t, class_) ?
arrayLength(t, classMethodTable(t, class_)) : 0;
object newMethodTable = makeArray
(t, oldLength + listSize(t, abstractVirtuals));
object newMethodTable = makeArray
(t, oldLength + listSize(t, abstractVirtuals));
if (oldLength) {
memcpy(&arrayBody(t, newMethodTable, 0),
&arrayBody(t, classMethodTable(t, class_), 0),
oldLength * sizeof(object));
}
if (oldLength) {
memcpy(&arrayBody(t, newMethodTable, 0),
&arrayBody(t, classMethodTable(t, class_), 0),
oldLength * sizeof(object));
}
mark(t, newMethodTable, ArrayBody, oldLength);
mark(t, newMethodTable, ArrayBody, oldLength);
unsigned mti = oldLength;
for (object p = listFront(t, abstractVirtuals);
p; p = pairSecond(t, p))
{
set(t, newMethodTable,
ArrayBody + ((mti++) * BytesPerWord), pairFirst(t, p));
unsigned mti = oldLength;
for (object p = listFront(t, abstractVirtuals);
p; p = pairSecond(t, p))
{
set(t, newMethodTable,
ArrayBody + ((mti++) * BytesPerWord), pairFirst(t, p));
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
set(t, vtable,
ArrayBody + ((i++) * BytesPerWord), pairFirst(t, p));
}
assert(t, arrayLength(t, newMethodTable) == mti);
set(t, class_, ClassMethodTable, newMethodTable);
}
assert(t, arrayLength(t, newMethodTable) == mti);
set(t, class_, ClassMethodTable, newMethodTable);
}
assert(t, arrayLength(t, vtable) == i);

View File

@ -59,6 +59,10 @@ public class Reflection {
expect(egads.getAnnotation(Deprecated.class) == null);
}
private Integer[] array;
private Integer integer;
public static Hello<Hello<Reflection>>.World<Hello<String>> pinky;
private static void genericType() throws Exception {
@ -131,10 +135,58 @@ public class Reflection {
expect(7.0 == (Double) Reflection.class.getMethod
("doubleMethod").invoke(null));
Class[][] array = new Class[][] { { Class.class } };
expect("[Ljava.lang.Class;".equals(array[0].getClass().getName()));
expect(Class[].class == array[0].getClass());
expect(array.getClass().getComponentType() == array[0].getClass());
{ Class[][] array = new Class[][] { { Class.class } };
expect("[Ljava.lang.Class;".equals(array[0].getClass().getName()));
expect(Class[].class == array[0].getClass());
expect(array.getClass().getComponentType() == array[0].getClass());
}
{ Reflection r = new Reflection();
expect(r.egads == 0);
Reflection.class.getDeclaredField("egads").set(r, 42);
expect(((int) Reflection.class.getDeclaredField("egads").get(r)) == 42);
Reflection.class.getDeclaredField("egads").setInt(r, 43);
expect(Reflection.class.getDeclaredField("egads").getInt(r) == 43);
Integer[] array = new Integer[0];
Reflection.class.getDeclaredField("array").set(r, array);
expect(Reflection.class.getDeclaredField("array").get(r) == array);
try {
Reflection.class.getDeclaredField("array").set(r, new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
Integer integer = 45;
Reflection.class.getDeclaredField("integer").set(r, integer);
expect(Reflection.class.getDeclaredField("integer").get(r) == integer);
try {
Reflection.class.getDeclaredField("integer").set(r, new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
try {
Reflection.class.getDeclaredField("integer").set
(new Object(), integer);
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
try {
Reflection.class.getDeclaredField("integer").get(new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
}
try {
Foo.class.getMethod("foo").invoke(null);
@ -157,6 +209,22 @@ public class Reflection {
// cool
}
try {
Foo.class.getField("foo").set(null, 42);
expect(false);
} catch (NoClassDefFoundError e) {
// cool
}
try {
Foo.class.getField("foo").set(null, new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
} catch (NoClassDefFoundError e) {
// cool
}
{ Method m = Reflection.class.getMethod("throwOOME");
try {
m.invoke(null);