mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
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:
parent
39e3850ed8
commit
7056315c18
@ -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();
|
||||
|
||||
|
@ -11,4 +11,5 @@
|
||||
package java.lang.annotation;
|
||||
|
||||
public interface Annotation {
|
||||
Class<? extends Annotation> annotationType();
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user