Merge pull request #186 from dicej/getDeclaredMethods

fix Class.getDeclaredMethods
This commit is contained in:
Joshua Warner 2014-03-10 13:09:04 -06:00
commit 60d841df06
6 changed files with 84 additions and 38 deletions

View File

@ -13,7 +13,14 @@ package avian;
public class ClassAddendum extends Addendum { public class ClassAddendum extends Addendum {
public Object[] interfaceTable; public Object[] interfaceTable;
public InnerClassReference[] innerClassTable; public InnerClassReference[] innerClassTable;
public Object[] methodTable; /**
* If this value is negative, all the methods in VMClass.methodTable
* were declared in that class. Otherwise, only the first
* declaredMethodCount methods in that table were declared in that
* class, while the rest were declared in interfaces implemented or
* extended by that class.
*/
public int declaredMethodCount;
public Object enclosingClass; public Object enclosingClass;
public Object enclosingMethod; public Object enclosingMethod;
} }

View File

@ -221,6 +221,18 @@ public class Classes {
return result; return result;
} }
private static int declaredMethodCount(VMClass c) {
ClassAddendum a = c.addendum;
if (a != null) {
int count = a.declaredMethodCount;
if (count >= 0) {
return count;
}
}
VMMethod[] table = c.methodTable;
return table == null ? 0 : table.length;
}
public static void link(VMClass c, ClassLoader loader) { public static void link(VMClass c, ClassLoader loader) {
acquireClassLock(); acquireClassLock();
try { try {
@ -238,9 +250,10 @@ public class Classes {
} }
} }
if (c.methodTable != null) { VMMethod[] methodTable = c.methodTable;
for (int i = 0; i < c.methodTable.length; ++i) { if (methodTable != null) {
VMMethod m = c.methodTable[i]; for (int i = 0; i < methodTable.length; ++i) {
VMMethod m = methodTable[i];
for (int j = 1; j < m.spec.length;) { for (int j = 1; j < m.spec.length;) {
j = resolveSpec(loader, m.spec, j); j = resolveSpec(loader, m.spec, j);
@ -394,17 +407,18 @@ public class Classes {
public static int findMethod(VMClass vmClass, String name, public static int findMethod(VMClass vmClass, String name,
Class[] parameterTypes) Class[] parameterTypes)
{ {
if (vmClass.methodTable != null) { VMMethod[] methodTable = vmClass.methodTable;
if (methodTable != null) {
Classes.link(vmClass); Classes.link(vmClass);
if (parameterTypes == null) { if (parameterTypes == null) {
parameterTypes = new Class[0]; parameterTypes = new Class[0];
} }
for (int i = 0; i < vmClass.methodTable.length; ++i) { for (int i = 0; i < methodTable.length; ++i) {
if (toString(vmClass.methodTable[i].name).equals(name) VMMethod m = methodTable[i];
&& match(parameterTypes, if (toString(m.name).equals(name)
getParameterTypes(vmClass.methodTable[i]))) && match(parameterTypes, getParameterTypes(m)))
{ {
return i; return i;
} }
@ -415,12 +429,12 @@ public class Classes {
public static int countMethods(VMClass vmClass, boolean publicOnly) { public static int countMethods(VMClass vmClass, boolean publicOnly) {
int count = 0; int count = 0;
if (vmClass.methodTable != null) { VMMethod[] methodTable = vmClass.methodTable;
for (int i = 0; i < vmClass.methodTable.length; ++i) { if (methodTable != null) {
if (((! publicOnly) for (int i = 0, j = declaredMethodCount(vmClass); i < j; ++i) {
|| ((vmClass.methodTable[i].flags & Modifier.PUBLIC)) VMMethod m = methodTable[i];
!= 0) if (((! publicOnly) || ((m.flags & Modifier.PUBLIC)) != 0)
&& (! toString(vmClass.methodTable[i].name).startsWith("<"))) && (! toString(m.name).startsWith("<")))
{ {
++ count; ++ count;
} }
@ -431,14 +445,15 @@ public class Classes {
public static Method[] getMethods(VMClass vmClass, boolean publicOnly) { public static Method[] getMethods(VMClass vmClass, boolean publicOnly) {
Method[] array = new Method[countMethods(vmClass, publicOnly)]; Method[] array = new Method[countMethods(vmClass, publicOnly)];
if (vmClass.methodTable != null) { VMMethod[] methodTable = vmClass.methodTable;
if (methodTable != null) {
Classes.link(vmClass); Classes.link(vmClass);
int ai = 0; int ai = 0;
for (int i = 0; i < vmClass.methodTable.length; ++i) { for (int i = 0, j = declaredMethodCount(vmClass); i < j; ++i) {
if ((((vmClass.methodTable[i].flags & Modifier.PUBLIC) != 0) VMMethod m = methodTable[i];
|| (! publicOnly)) if (((! publicOnly) || ((m.flags & Modifier.PUBLIC) != 0))
&& ! toString(vmClass.methodTable[i].name).startsWith("<")) && ! toString(m.name).startsWith("<"))
{ {
array[ai++] = makeMethod(SystemClassLoader.getClass(vmClass), i); array[ai++] = makeMethod(SystemClassLoader.getClass(vmClass), i);
} }

View File

@ -24,6 +24,15 @@ public class VMClass {
public Object[] interfaceTable; public Object[] interfaceTable;
public VMMethod[] virtualTable; public VMMethod[] virtualTable;
public VMField[] fieldTable; public VMField[] fieldTable;
/**
* Methods declared in this class, plus any abstract virtual methods
* inherited from implemented or extended interfaces. If addendum
* is non-null and addendum.declaredMethodCount is non-negative,
* then the first addendum.declaredMethodCount methods are declared
* methods, while the rest are abstract virtual methods. If
* addendum is null or addendum.declaredMethodCount is negative, all
* are declared methods.
*/
public VMMethod[] methodTable; public VMMethod[] methodTable;
public ClassAddendum addendum; public ClassAddendum addendum;
public Object staticTable; public Object staticTable;

View File

@ -2121,25 +2121,26 @@ interceptFileOperations(Thread* t, bool updateRuntimeData)
} }
#endif // AVIAN_OPENJDK_SRC #endif // AVIAN_OPENJDK_SRC
object unsigned
getClassMethodTable(Thread* t, object c) classDeclaredMethodCount(Thread* t, object c)
{ {
object addendum = classAddendum(t, c); object addendum = classAddendum(t, c);
if (addendum) { if (addendum) {
object table = classAddendumMethodTable(t, addendum); int count = classAddendumDeclaredMethodCount(t, addendum);
if (table) { if (count >= 0) {
return table; return count;
} }
} }
return classMethodTable(t, c); object table = classMethodTable(t, c);
return table == 0 ? 0 : arrayLength(t, table);
} }
unsigned unsigned
countMethods(Thread* t, object c, bool publicOnly) countMethods(Thread* t, object c, bool publicOnly)
{ {
object table = getClassMethodTable(t, c); object table = classMethodTable(t, c);
unsigned count = 0; unsigned count = 0;
for (unsigned i = 0; i < arrayLength(t, table); ++i) { for (unsigned i = 0, j = classDeclaredMethodCount(t, c); i < j; ++i) {
object vmMethod = arrayBody(t, table, i); object vmMethod = arrayBody(t, table, i);
if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC))
and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') and byteArrayBody(t, methodName(t, vmMethod), 0) != '<')
@ -2171,9 +2172,9 @@ countFields(Thread* t, object c, bool publicOnly)
unsigned unsigned
countConstructors(Thread* t, object c, bool publicOnly) countConstructors(Thread* t, object c, bool publicOnly)
{ {
object table = getClassMethodTable(t, c); object table = classMethodTable(t, c);
unsigned count = 0; unsigned count = 0;
for (unsigned i = 0; i < arrayLength(t, table); ++i) { for (unsigned i = 0, j = classDeclaredMethodCount(t, c); i < j; ++i) {
object vmMethod = arrayBody(t, table, i); object vmMethod = arrayBody(t, table, i);
if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC))
and strcmp(reinterpret_cast<char*> and strcmp(reinterpret_cast<char*>
@ -4214,7 +4215,7 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments)
jclass c = reinterpret_cast<jclass>(arguments[0]); jclass c = reinterpret_cast<jclass>(arguments[0]);
jboolean publicOnly = arguments[1]; jboolean publicOnly = arguments[1];
object table = getClassMethodTable(t, jclassVmClass(t, *c)); object table = classMethodTable(t, jclassVmClass(t, *c));
if (table) { if (table) {
PROTECT(t, table); PROTECT(t, table);
@ -4224,7 +4225,9 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments)
PROTECT(t, array); PROTECT(t, array);
unsigned ai = 0; unsigned ai = 0;
for (unsigned i = 0; i < arrayLength(t, table); ++i) { for (unsigned i = 0, j = classDeclaredMethodCount(t, jclassVmClass(t, *c));
i < j; ++i)
{
object vmMethod = arrayBody(t, table, i); object vmMethod = arrayBody(t, table, i);
PROTECT(t, vmMethod); PROTECT(t, vmMethod);
@ -4308,7 +4311,7 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments)
jclass c = reinterpret_cast<jclass>(arguments[0]); jclass c = reinterpret_cast<jclass>(arguments[0]);
jboolean publicOnly = arguments[1]; jboolean publicOnly = arguments[1];
object table = getClassMethodTable(t, jclassVmClass(t, *c)); object table = classMethodTable(t, jclassVmClass(t, *c));
if (table) { if (table) {
PROTECT(t, table); PROTECT(t, table);
@ -4318,7 +4321,9 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments)
PROTECT(t, array); PROTECT(t, array);
unsigned ai = 0; unsigned ai = 0;
for (unsigned i = 0; i < arrayLength(t, table); ++i) { for (unsigned i = 0, j = classDeclaredMethodCount(t, jclassVmClass(t, *c));
i < j; ++i)
{
object vmMethod = arrayBody(t, table, i); object vmMethod = arrayBody(t, table, i);
PROTECT(t, vmMethod); PROTECT(t, vmMethod);

View File

@ -1123,7 +1123,7 @@ getClassAddendum(Thread* t, object class_, object pool)
if (addendum == 0) { if (addendum == 0) {
PROTECT(t, class_); PROTECT(t, class_);
addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, 0, 0, 0); addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0);
set(t, class_, ClassAddendum, addendum); set(t, class_, ClassAddendum, addendum);
} }
return addendum; return addendum;
@ -2206,13 +2206,15 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
if (abstractVirtuals) { if (abstractVirtuals) {
PROTECT(t, vtable); PROTECT(t, vtable);
object addendum = getClassAddendum(t, class_, pool); object originalMethodTable = classMethodTable(t, class_);
set(t, addendum, ClassAddendumMethodTable, PROTECT(t, originalMethodTable);
classMethodTable(t, class_));
unsigned oldLength = classMethodTable(t, class_) ? unsigned oldLength = classMethodTable(t, class_) ?
arrayLength(t, classMethodTable(t, class_)) : 0; arrayLength(t, classMethodTable(t, class_)) : 0;
object addendum = getClassAddendum(t, class_, pool);
classAddendumDeclaredMethodCount(t, addendum) = oldLength;
object newMethodTable = makeArray object newMethodTable = makeArray
(t, oldLength + listSize(t, abstractVirtuals)); (t, oldLength + listSize(t, abstractVirtuals));

View File

@ -241,6 +241,8 @@ public class Reflection {
expect(avian.TestReflection.get(Baz.class.getField("foo"), new Baz()) expect(avian.TestReflection.get(Baz.class.getField("foo"), new Baz())
.equals(42)); .equals(42));
expect((Baz.class.getModifiers() & Modifier.PUBLIC) == 0); expect((Baz.class.getModifiers() & Modifier.PUBLIC) == 0);
expect(B.class.getDeclaredMethods().length == 0);
} }
protected static class Baz { protected static class Baz {
@ -263,3 +265,9 @@ class Foo {
} }
class MyException extends RuntimeException { } class MyException extends RuntimeException { }
interface A {
void foo();
}
interface B extends A { }