support runtime-visible annotations and java.lang.reflect.Proxy

This commit is contained in:
Joel Dice 2009-09-18 18:01:54 -06:00
parent a2a33c259e
commit 7aa906d97b
23 changed files with 1278 additions and 169 deletions

@ -0,0 +1,31 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class AnnotationInvocationHandler implements InvocationHandler {
private Object[] data;
public AnnotationInvocationHandler(Object[] data) {
this.data = data;
}
public Object invoke(Object proxy, Method method, Object[] arguments) {
for (int i = 2; i < data.length; i += 2) {
if (method.getName().equals(data[i])) {
return data[i + 1];
}
}
throw new IllegalArgumentException();
}
}

16
classpath/avian/Pair.java Normal file

@ -0,0 +1,16 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class Pair<A,B> {
public A first;
public B second;
}

@ -10,14 +10,20 @@
package java.lang;
import avian.AnnotationInvocationHandler;
import avian.Pair;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.AnnotatedElement;
import java.lang.annotation.Annotation;
import java.io.InputStream;
import java.io.IOException;
@ -28,8 +34,11 @@ import java.security.ProtectionDomain;
import java.security.Permissions;
import java.security.AllPermission;
public final class Class <T> implements Type, GenericDeclaration {
public final class Class <T>
implements Type, GenericDeclaration, AnnotatedElement
{
private static final int PrimitiveFlag = 1 << 5;
private static final int LinkFlag = 1 << 8;
private short flags;
private short vmFlags;
@ -44,6 +53,7 @@ public final class Class <T> implements Type, GenericDeclaration {
private Method[] virtualTable;
private Field[] fieldTable;
private Method[] methodTable;
private Addendum addendum;
private Object staticTable;
private ClassLoader loader;
@ -139,6 +149,157 @@ public final class Class <T> implements Type, GenericDeclaration {
}
}
private static Class loadClass(ClassLoader loader,
byte[] nameBytes, int offset, int length)
{
String name = new String(nameBytes, offset, length, false);
try {
return loader.loadClass(name);
} catch (ClassNotFoundException e) {
NoClassDefFoundError error = new NoClassDefFoundError(name);
error.initCause(e);
throw error;
}
}
private static Object resolveAnnotationValue(ClassLoader loader,
Object raw)
{
if (raw instanceof Pair) {
Pair<byte[],byte[]> p = (Pair<byte[],byte[]>) raw;
return Enum.valueOf
(loadClass(loader, p.first, 1, p.first.length - 3),
new String(p.second, 0, p.second.length - 1, false));
} else if (raw instanceof byte[]) {
byte[] typeName = (byte[]) raw;
return loadClass(loader, typeName, 0, typeName.length - 1);
} else if (raw.getClass().isArray()) {
Object[] array = (Object[]) raw;
if (array.length > 0 && array[0] == null) {
resolveAnnotation(loader, array);
} else {
for (int i = 0; i < array.length; ++i) {
array[i] = resolveAnnotationValue(loader, array[i]);
}
}
}
return raw;
}
private static void resolveAnnotation(ClassLoader loader,
Object[] annotation)
{
byte[] typeName = (byte[]) annotation[1];
annotation[1] = loadClass(loader, typeName, 1, typeName.length - 3);
for (int i = 2; i < annotation.length; i += 2) {
byte[] name = (byte[]) annotation[i];
annotation[i] = new String(name, 0, name.length - 1, false).intern();
annotation[i + 1] = resolveAnnotationValue(loader, annotation[i + 1]);
}
}
private static void resolveAnnotationTable(ClassLoader loader,
Object[] table)
{
for (int i = 0; i < table.length; ++i) {
resolveAnnotation(loader, (Object[]) table[i]);
}
}
private static int resolveSpec(ClassLoader loader, byte[] spec, int start) {
int result;
int end;
switch (spec[start]) {
case 'L':
++ start;
end = start;
while (spec[end] != ';') ++ end;
result = end + 1;
break;
case '[':
end = start + 1;
while (spec[end] == '[') ++ end;
switch (spec[end]) {
case 'L':
++ end;
while (spec[end] != ';') ++ end;
++ end;
break;
default:
++ end;
}
result = end;
break;
default:
return start + 1;
}
loadClass(loader, spec, start, end - start);
return result;
}
private static native void acquireClassLock();
private static native void releaseClassLock();
void link(ClassLoader loader) {
acquireClassLock();
try {
if ((vmFlags & LinkFlag) == 0) {
if (super_ != null) {
super_.link(loader);
}
if (addendum != null && addendum.annotationTable != null) {
resolveAnnotationTable(loader, addendum.annotationTable);
}
if (interfaceTable != null) {
int stride = (isInterface() ? 1 : 2);
for (int i = 0; i < interfaceTable.length; i += stride) {
((Class) interfaceTable[i]).link(loader);
}
}
if (methodTable != null) {
for (int i = 0; i < methodTable.length; ++i) {
Method m = methodTable[i];
for (int j = 1; j < m.spec.length;) {
j = resolveSpec(loader, m.spec, j);
}
if (m.addendum != null && m.addendum.annotationTable != null) {
resolveAnnotationTable(loader, m.addendum.annotationTable);
}
}
}
if (fieldTable != null) {
for (int i = 0; i < fieldTable.length; ++i) {
Field f = fieldTable[i];
resolveSpec(loader, f.spec, 0);
if (f.addendum != null && f.addendum.annotationTable != null) {
resolveAnnotationTable(loader, f.addendum.annotationTable);
}
}
}
vmFlags |= LinkFlag;
}
} finally {
releaseClassLock();
}
}
public static Class forName(String name) throws ClassNotFoundException {
return forName
(name, true, Method.getCaller().getDeclaringClass().getClassLoader());
@ -161,8 +322,6 @@ public final class Class <T> implements Type, GenericDeclaration {
private static native Class primitiveClass(char name);
private native void link(ClassLoader loader);
private native void initialize();
public static Class forCanonicalName(String name) {
@ -479,9 +638,10 @@ public final class Class <T> implements Type, GenericDeclaration {
if (interfaceTable != null) {
link(loader);
Class[] array = new Class[interfaceTable.length / 2];
int stride = (isInterface() ? 1 : 2);
Class[] array = new Class[interfaceTable.length / stride];
for (int i = 0; i < array.length; ++i) {
array[i] = (Class) interfaceTable[i * 2];
array[i] = (Class) interfaceTable[i * stride];
}
return array;
} else {
@ -566,7 +726,7 @@ public final class Class <T> implements Type, GenericDeclaration {
}
public Object[] getSigners() {
return Static.signers.get(this);
return addendum == null ? null : addendum.signers;
}
public Package getPackage() {
@ -584,8 +744,76 @@ public final class Class <T> implements Type, GenericDeclaration {
}
}
public boolean isAnnotationPresent
(Class<? extends Annotation> class_)
{
return getAnnotation(class_) != null;
}
private Annotation getAnnotation(Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(loader, new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
for (Class c = this; c != null; c = c.super_) {
if (c.addendum != null && c.addendum.annotationTable != null) {
link(c.loader);
Object[] table = c.addendum.annotationTable;
for (int i = 0; i < table.length; ++i) {
Object[] a = (Object[]) table[i];
if (a[1] == class_) {
return (T) c.getAnnotation(a);
}
}
}
}
return null;
}
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
if (addendum != null && addendum.annotationTable != null) {
link(loader);
Object[] table = addendum.annotationTable;
Annotation[] array = new Annotation[table.length];
for (int i = 0; i < table.length; ++i) {
array[i] = getAnnotation((Object[]) table[i]);
}
return array;
} else {
return new Annotation[0];
}
}
private int countAnnotations() {
int count = 0;
for (Class c = this; c != null; c = c.super_) {
if (c.addendum != null && c.addendum.annotationTable != null) {
count += c.addendum.annotationTable.length;
}
}
return count;
}
public Annotation[] getAnnotations() {
Annotation[] array = new Annotation[countMethods(true)];
int i = 0;
for (Class c = this; c != null; c = c.super_) {
if (c.addendum != null && c.addendum.annotationTable != null) {
Object[] table = c.addendum.annotationTable;
for (int j = 0; j < table.length; ++j) {
array[i++] = getAnnotation((Object[]) table[j]);
}
}
}
return array;
}
public boolean isEnum() {
@ -612,10 +840,6 @@ public final class Class <T> implements Type, GenericDeclaration {
throw new UnsupportedOperationException();
}
public <A extends Annotation> A getAnnotation(Class<A> c) {
throw new UnsupportedOperationException();
}
public ProtectionDomain getProtectionDomain() {
Permissions p = new Permissions();
p.add(new AllPermission());
@ -625,11 +849,15 @@ public final class Class <T> implements Type, GenericDeclaration {
// for GNU Classpath compatibility:
void setSigners(Object[] signers) {
if (signers != null && signers.length > 0) {
Static.signers.put(this, signers);
if (addendum == null) {
addendum = new Addendum();
}
addendum.signers = signers;
}
}
private static class Static {
public static final Map<Class,Object[]> signers = new HashMap();
private static class Addendum {
public Object[] annotationTable;
public Object[] signers;
}
}

@ -83,7 +83,9 @@ public abstract class ClassLoader {
return c;
}
protected native void resolveClass(Class c);
protected void resolveClass(Class c) {
c.link(this);
}
private ClassLoader getParent() {
return parent;

@ -0,0 +1,16 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.annotation;
@Retention(RetentionPolicy.RUNTIME)
public @interface Retention {
public RetentionPolicy value();
}

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.annotation;
public enum RetentionPolicy {
CLASS, RUNTIME, SOURCE
}

@ -10,9 +10,17 @@
package java.lang.reflect;
public abstract class AccessibleObject {
import java.lang.annotation.Annotation;
public abstract class AccessibleObject implements AnnotatedElement {
protected static final int Accessible = 1 << 0;
public boolean isAnnotationPresent
(Class<? extends Annotation> class_)
{
return getAnnotation(class_) != null;
}
public abstract boolean isAccessible();
public abstract void setAccessible(boolean v);

@ -0,0 +1,23 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
import java.lang.annotation.Annotation;
public interface AnnotatedElement {
public boolean isAnnotationPresent(Class<? extends Annotation> class_);
public <T extends Annotation> T getAnnotation(Class<T> class_);
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations();
}

@ -10,6 +10,8 @@
package java.lang.reflect;
import java.lang.annotation.Annotation;
public class Constructor<T> extends AccessibleObject
implements Member, GenericDeclaration
{
@ -52,6 +54,18 @@ public class Constructor<T> extends AccessibleObject
return method.isSynthetic();
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
return method.getAnnotation(class_);
}
public Annotation[] getAnnotations() {
return method.getAnnotations();
}
public Annotation[] getDeclaredAnnotations() {
return method.getDeclaredAnnotations();
}
public TypeVariable<Constructor<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}

@ -10,6 +10,10 @@
package java.lang.reflect;
import avian.AnnotationInvocationHandler;
import java.lang.annotation.Annotation;
public class Field<T> extends AccessibleObject {
private static final int VoidField = 0;
private static final int ByteField = 1;
@ -27,7 +31,8 @@ public class Field<T> extends AccessibleObject {
private short flags;
private short offset;
private byte[] name;
private byte[] spec;
public byte[] spec;
public Addendum addendum;
private Class<T> class_;
private Field() { }
@ -195,6 +200,45 @@ public class Field<T> extends AccessibleObject {
}
}
private Annotation getAnnotation(Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(class_.getClassLoader(), new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
for (int i = 0; i < table.length; ++i) {
Object[] a = (Object[]) table[i];
if (a[1] == class_) {
return (T) getAnnotation(a);
}
}
}
return null;
}
public Annotation[] getAnnotations() {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
Annotation[] array = new Annotation[table.length];
for (int i = 0; i < table.length; ++i) {
array[i] = getAnnotation((Object[]) table[i]);
}
return array;
} else {
return new Annotation[0];
}
}
public Annotation[] getDeclaredAnnotations() {
return getAnnotations();
}
public boolean isEnumConstant() {
throw new UnsupportedOperationException();
}
@ -210,4 +254,8 @@ public class Field<T> extends AccessibleObject {
private static native void setObject
(Object instance, int offset, Object value);
public static class Addendum {
public Object[] annotationTable;
}
}

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] arguments);
}

@ -10,6 +10,10 @@
package java.lang.reflect;
import avian.AnnotationInvocationHandler;
import java.lang.annotation.Annotation;
public class Method<T> extends AccessibleObject
implements Member, GenericDeclaration
{
@ -21,7 +25,8 @@ public class Method<T> extends AccessibleObject
private short offset;
private int nativeID;
private byte[] name;
private byte[] spec;
public byte[] spec;
public Addendum addendum;
private Class<T> class_;
private Object code;
private long compiled;
@ -142,6 +147,45 @@ public class Method<T> extends AccessibleObject
throw new RuntimeException();
}
private Annotation getAnnotation(Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(class_.getClassLoader(), new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
for (int i = 0; i < table.length; ++i) {
Object[] a = (Object[]) table[i];
if (a[1] == class_) {
return (T) getAnnotation(a);
}
}
}
return null;
}
public Annotation[] getAnnotations() {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
Annotation[] array = new Annotation[table.length];
for (int i = 0; i < table.length; ++i) {
array[i] = getAnnotation((Object[]) table[i]);
}
return array;
} else {
return new Annotation[0];
}
}
public Annotation[] getDeclaredAnnotations() {
return getAnnotations();
}
public boolean isSynthetic() {
throw new UnsupportedOperationException();
}
@ -165,4 +209,8 @@ public class Method<T> extends AccessibleObject
public TypeVariable<Method<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
public static class Addendum {
public Object[] annotationTable;
}
}

@ -0,0 +1,54 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public class Proxy {
private static int nextNumber;
protected InvocationHandler h;
public static Class getProxyClass(ClassLoader loader,
Class ... interfaces)
{
for (Class c: interfaces) {
if (! c.isInterface()) {
throw new IllegalArgumentException();
}
}
int number;
synchronized (Proxy.class) {
number = nextNumber++;
}
return makeClass
(loader, interfaces, ("Proxy-" + number + "\0").getBytes());
}
private static native Class makeClass(ClassLoader loader,
Class[] interfaces,
byte[] name);
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler handler)
{
try {
return Proxy.getProxyClass(loader, interfaces)
.getConstructor(new Class[] { InvocationHandler.class })
.newInstance(new Object[] { handler });
} catch (Exception e) {
AssertionError error = new AssertionError();
error.initCause(e);
throw error;
}
}
}

@ -79,6 +79,242 @@ runOnLoadIfFound(Thread* t, System::Library* library)
}
}
void JNICALL
proxyConstruct(Thread* t, object, uintptr_t* arguments)
{
set(t, reinterpret_cast<object>(arguments[0]), ProxyH,
reinterpret_cast<object>(arguments[1]));
}
int64_t JNICALL
proxyInvoke(Thread* t, object method, uintptr_t* arguments)
{
PROTECT(t, method);
unsigned size = methodParameterFootprint(t, method);
RUNTIME_ARRAY(bool, objectMask, size);
assert(t, (methodFlags(t, method) & ACC_STATIC) == 0);
unsigned i = 0;
RUNTIME_ARRAY_BODY(objectMask)[i++] = true;
unsigned argumentCount = 0;
for (MethodSpecIterator it
(t, reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0)));
it.hasNext();)
{
++ argumentCount;
switch (*it.next()) {
case 'L':
case '[':
RUNTIME_ARRAY_BODY(objectMask)[i++] = true;
break;
case 'J':
case 'D':
RUNTIME_ARRAY_BODY(objectMask)[i++] = false;
RUNTIME_ARRAY_BODY(objectMask)[i++] = false;
break;
default:
RUNTIME_ARRAY_BODY(objectMask)[i++] = false;
break;
}
}
class MyProtector: public Thread::Protector {
public:
MyProtector(Thread* t, uintptr_t* array, bool* mask, unsigned count):
Protector(t), array(array), mask(mask), count(count) { }
virtual void visit(Heap::Visitor* v) {
for (unsigned i = 0; i < count; ++i) {
if (mask[i]) {
v->visit(reinterpret_cast<object*>(array + i));
}
}
}
uintptr_t* array;
bool* mask;
unsigned count;
} protector(t, arguments, RUNTIME_ARRAY_BODY(objectMask), i);
object array = makeObjectArray
(t, t->m->loader, arrayBody(t, t->m->types, Machine::JobjectType),
argumentCount);
PROTECT(t, array);
i = 0;
unsigned ai = 1;
for (MethodSpecIterator it
(t, reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0)));
it.hasNext();)
{
object a;
unsigned size;
switch (*it.next()) {
case 'L':
case '[':
a = reinterpret_cast<object>(arguments[ai]);
size = 1;
break;
case 'Z':
a = makeBoolean(t, static_cast<int8_t>(arguments[ai]));
size = 1;
break;
case 'B':
a = makeByte(t, static_cast<int8_t>(arguments[ai]));
size = 1;
break;
case 'S':
a = makeShort(t, static_cast<int16_t>(arguments[ai]));
size = 1;
break;
case 'C':
a = makeChar(t, static_cast<uint16_t>(arguments[ai]));
size = 1;
break;
case 'I':
a = makeInt(t, static_cast<int32_t>(arguments[ai]));
size = 1;
break;
case 'F':
a = makeFloat(t, bitsToFloat(static_cast<int32_t>(arguments[ai])));
size = 1;
break;
case 'J': {
int64_t v; memcpy(&v, arguments + ai, 8);
a = makeLong(t, v);
size = 2;
} break;
case 'D': {
double v; memcpy(&v, arguments + ai, 8);
a = makeDouble(t, v);
size = 2;
} break;
default:
abort(t);
}
set(t, array, ArrayBody + (i * BytesPerWord), a);
++ i;
ai += size;
}
if (t->m->invokeMethod == 0) {
object m = resolveMethod
(t, t->m->loader, "java/lang/reflect/InvocationHandler", "invoke",
"(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)"
"Ljava/lang/Object;");
if (m) {
t->m->invokeMethod = m;
}
if (UNLIKELY(t->exception)) return 0;
}
object invoke = findInterfaceMethod
(t, t->m->invokeMethod, objectClass
(t, proxyH(t, reinterpret_cast<object>(arguments[0]))));
PROTECT(t, invoke);
object result = t->m->processor->invoke
(t, invoke, proxyH(t, reinterpret_cast<object>(arguments[0])),
reinterpret_cast<object>(arguments[0]), method, array);
if (UNLIKELY(t->exception)) return 0;
switch (methodReturnCode(t, method)) {
case BooleanField:
return booleanValue(t, result);
case ByteField:
return byteValue(t, result);
case CharField:
return charValue(t, result);
case ShortField:
return shortValue(t, result);
case FloatField:
return floatToBits(floatValue(t, result));
case IntField:
return intValue(t, result);
case LongField:
return longValue(t, result);
case DoubleField:
return doubleToBits(doubleValue(t, result));
case ObjectField:
return reinterpret_cast<int64_t>(result);
case VoidField:
return 0;
default:
abort(t);
}
}
void
addInterface(Thread* t, object map, object interface)
{
hashMapInsertMaybe
(t, map, className(t, interface), interface, byteArrayHash,
byteArrayEqual);
}
object
allInterfaces(Thread* t, object array)
{
PROTECT(t, array);
object map = makeHashMap(t, 0, 0);
PROTECT(t, map);
for (unsigned i = 0; i < objectArrayLength(t, array); ++i) {
addInterface(t, map, objectArrayBody(t, array, i));
object itable = classInterfaceTable(t, objectArrayBody(t, array, i));
if (itable) {
PROTECT(t, itable);
for (unsigned j = 0; j < arrayLength(t, itable); ++j) {
addInterface(t, map, arrayBody(t, itable, j));
}
}
}
object result = makeArray(t, hashMapSize(t, map));
unsigned i = 0;
for (HashMapIterator it(t, map); it.hasMore();) {
set(t, result, ArrayBody + (i * BytesPerWord), tripleSecond(t, it.next()));
++ i;
}
return result;
}
} // namespace
extern "C" JNIEXPORT int64_t JNICALL
@ -199,16 +435,6 @@ Avian_java_lang_ClassLoader_defineClass
return reinterpret_cast<int64_t>(c);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_ClassLoader_resolveClass
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
object class_ = reinterpret_cast<object>(arguments[1]);
linkClass(t, loader, class_);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedClass
(Thread* t, object, uintptr_t* arguments)
@ -302,13 +528,17 @@ Avian_java_lang_Class_initialize
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Class_link
(Thread* t, object, uintptr_t* arguments)
Avian_java_lang_Class_acquireClassLock
(Thread* t, object)
{
object this_ = reinterpret_cast<object>(arguments[0]);
object loader = reinterpret_cast<object>(arguments[1]);
acquire(t, t->m->classLock);
}
linkClass(t, loader, this_);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Class_releaseClassLock
(Thread* t, object)
{
release(t, t->m->classLock);
}
extern "C" JNIEXPORT int64_t JNICALL
@ -499,6 +729,195 @@ Avian_java_lang_reflect_Array_makeObjectArray
(makeObjectArray(t, classLoader(t, elementType), elementType, length));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_reflect_Proxy_makeClass
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
PROTECT(t, loader);
object interfaces = allInterfaces(t, reinterpret_cast<object>(arguments[1]));
PROTECT(t, interfaces);
object name = reinterpret_cast<object>(arguments[2]);
PROTECT(t, name);
object virtualMap = makeHashMap(t, 0, 0);
PROTECT(t, virtualMap);
object superVtable = classVirtualTable
(t, arrayBody(t, t->m->types, Machine::ProxyType));
PROTECT(t, superVtable);
for (unsigned i = 0; i < arrayLength(t, superVtable); ++i) {
object method = arrayBody(t, superVtable, i);
hashMapInsert(t, virtualMap, method, method, methodHash);
}
unsigned virtualCount = arrayLength(t, superVtable);
object newVirtuals = makeList(t, 0, 0, 0);
PROTECT(t, newVirtuals);
object ivtable = 0;
PROTECT(t, ivtable);
object method = 0;
PROTECT(t, method);
for (unsigned i = 0; i < arrayLength(t, interfaces); ++i) {
ivtable = classVirtualTable(t, arrayBody(t, interfaces, i));
if (ivtable) {
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
method = arrayBody(t, ivtable, j);
method = makeMethod
(t,
methodVmFlags(t, method) | FastNative,
methodReturnCode(t, method),
methodParameterCount(t, method),
methodParameterFootprint(t, method),
methodFlags(t, method) | ACC_NATIVE,
0,
0,
methodName(t, method),
methodSpec(t, method),
0,
0,
0,
reinterpret_cast<int64_t>(proxyInvoke));
object p = hashMapFindNode
(t, virtualMap, method, methodHash, methodEqual);
if (p) {
methodOffset(t, method) = methodOffset(t, tripleFirst(t, p));
set(t, p, TripleSecond, method);
} else {
methodOffset(t, method) = virtualCount++;
listAppend(t, newVirtuals, method);
hashMapInsert(t, virtualMap, method, method, methodHash);
}
}
}
}
object vtable = makeArray(t, virtualCount);
PROTECT(t, vtable);
unsigned i = 0;
for (; i < arrayLength(t, superVtable); ++i) {
method = hashMapFind
(t, virtualMap, arrayBody(t, superVtable, i), methodHash, methodEqual);
set(t, vtable, ArrayBody + (i * BytesPerWord), method);
}
object methodTable = makeArray(t, listSize(t, newVirtuals) + 1);
PROTECT(t, methodTable);
unsigned mti = 0;
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p));
++ i;
set(t, methodTable, ArrayBody + (mti * BytesPerWord), pairFirst(t, p));
++ mti;
}
#define NAME "<init>"
object constructorName = makeByteArray(t, sizeof(NAME));
PROTECT(t, constructorName);
memcpy(&byteArrayBody(t, constructorName, 0), NAME, sizeof(NAME));
#define SPEC "(Ljava/lang/reflect/InvocationHandler;)V"
object constructorSpec = makeByteArray(t, sizeof(SPEC));
PROTECT(t, constructorSpec);
memcpy(&byteArrayBody(t, constructorSpec, 0), SPEC, sizeof(SPEC));
object constructor = makeMethod
(t,
methodVmFlags(t, method) | FastNative,
VoidField,
1,
2,
methodFlags(t, method) | ACC_NATIVE,
0,
0,
constructorName,
constructorSpec,
0,
0,
0,
reinterpret_cast<int64_t>(proxyConstruct));
set(t, methodTable, ArrayBody + (mti * BytesPerWord), constructor);
++ mti;
assert(t, arrayLength(t, vtable) == i);
assert(t, arrayLength(t, methodTable) == mti);
object itable = makeArray(t, arrayLength(t, interfaces) * 2);
PROTECT(t, itable);
object newIVTable = 0;
PROTECT(t, newIVTable);
for (unsigned i = 0; i < arrayLength(t, interfaces); ++i) {
object interface = arrayBody(t, interfaces, i);
set(t, itable, ArrayBody + ((i * 2) * BytesPerWord), interface);
ivtable = classVirtualTable(t, interface);
if (ivtable) {
newIVTable = makeArray(t, arrayLength(t, ivtable));
set(t, itable, ArrayBody + (((i * 2) + 1) * BytesPerWord), newIVTable);
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
method = hashMapFind
(t, virtualMap, arrayBody(t, ivtable, j), methodHash, methodEqual);
assert(t, method);
set(t, newIVTable, ArrayBody + (j * BytesPerWord), method);
}
}
}
object c = t->m->processor->makeClass
(t,
0,
0,
classFixedSize(t, arrayBody(t, t->m->types, Machine::ProxyType)),
0,
0,
classObjectMask(t, arrayBody(t, t->m->types, Machine::ProxyType)),
name,
0,
arrayBody(t, t->m->types, Machine::ProxyType),
itable,
vtable,
0,
methodTable,
0,
0,
loader,
arrayLength(t, vtable));
PROTECT(t, c);
t->m->processor->initVtable(t, c);
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
set(t, arrayBody(t, methodTable, i), MethodClass, c);
}
return reinterpret_cast<int64_t>(c);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Float_floatToRawIntBits
(Thread*, object, uintptr_t* arguments)

@ -6331,7 +6331,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
default:
abort(t);
};
}
return r;
}
@ -6450,12 +6450,13 @@ class MyProcessor: public Processor {
uint16_t offset,
object name,
object spec,
object addendum,
object class_,
object code)
{
return vm::makeMethod
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
offset, 0, name, spec, class_, code,
offset, 0, name, spec, addendum, class_, code,
local::defaultThunk(static_cast<MyThread*>(t)));
}
@ -6475,13 +6476,14 @@ class MyProcessor: public Processor {
object fieldTable,
object methodTable,
object staticTable,
object addendum,
object loader,
unsigned vtableLength)
{
return vm::makeClass
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions,
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
fieldTable, methodTable, staticTable, loader, vtableLength);
fieldTable, methodTable, staticTable, addendum, loader, vtableLength);
}
virtual void
@ -7656,6 +7658,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext,
methodNativeID(t, method),
methodName(t, method),
methodSpec(t, method),
methodAddendum(t, method),
methodClass(t, method),
methodCode(t, method),
reinterpret_cast<intptr_t>(compiled));

@ -3093,11 +3093,12 @@ class MyProcessor: public Processor {
object name,
object spec,
object class_,
object addendum,
object code)
{
return vm::makeMethod
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
offset, 0, name, spec, class_, code, 0);
offset, 0, name, spec, addendum, class_, code, 0);
}
virtual object
@ -3116,13 +3117,14 @@ class MyProcessor: public Processor {
object fieldTable,
object methodTable,
object staticTable,
object addendum,
object loader,
unsigned vtableLength UNUSED)
{
return vm::makeClass
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions,
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
fieldTable, methodTable, staticTable, loader, 0);
fieldTable, methodTable, addendum, staticTable, loader, 0);
}
virtual void

@ -68,9 +68,8 @@ dispose(Thread* t, Thread* o, bool remove)
expect(t, find(t->m->rootThread, o));
unsigned c = count(t->m->rootThread, o);
Thread** threads = static_cast<Thread**>
(allocate(t->m->system, c * sizeof(Thread*)));
fill(t->m->rootThread, o, threads);
RUNTIME_ARRAY(Thread*, threads, c);
fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
#endif
if (o->parent) {
@ -115,7 +114,7 @@ dispose(Thread* t, Thread* o, bool remove)
expect(t, not find(t->m->rootThread, o));
for (unsigned i = 0; i < c; ++i) {
expect(t, find(t->m->rootThread, threads[i]));
expect(t, find(t->m->rootThread, RUNTIME_ARRAY_BODY(threads)[i]));
}
#endif
}
@ -604,51 +603,6 @@ makeByteArray(Thread* t, const char* format, va_list a)
return s;
}
unsigned
resolveSpec(Thread* t, object loader, object spec, unsigned offset)
{
int8_t* s = &byteArrayBody(t, spec, offset);
unsigned result;
switch (*s) {
case 'L':
++ offset;
while (*s and *s != ';') ++ s;
result = s + 1 - &byteArrayBody(t, spec, 0);
break;
case '[':
while (*s == '[') ++ s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
default:
++ s;
break;
}
result = s - &byteArrayBody(t, spec, 0);
break;
default:
return offset + 1;
}
PROTECT(t, spec);
PROTECT(t, loader);
unsigned length = s - &byteArrayBody(t, spec, offset);
object name = makeByteArray(t, length + 1);
memcpy(&byteArrayBody(t, name, 0),
&byteArrayBody(t, spec, offset),
length);
resolveClass(t, loader, name);
return result;
}
unsigned
readByte(Stream& s, unsigned* value)
{
@ -983,7 +937,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
object interfaceTable = 0;
if (hashMapSize(t, map)) {
unsigned length = hashMapSize(t, map) ;
unsigned length = hashMapSize(t, map);
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
length *= 2;
}
@ -1016,6 +970,122 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
set(t, class_, ClassInterfaceTable, interfaceTable);
}
object
parseAnnotation(Thread* t, Stream& s, object pool);
object
parseAnnotationValue(Thread* t, Stream& s, object pool)
{
unsigned tag = s.read1();
switch (tag) {
case 'Z':
return makeBoolean(t, singletonValue(t, pool, s.read2() - 1));
case 'B':
return makeByte(t, singletonValue(t, pool, s.read2() - 1));
case 'C':
return makeChar(t, singletonValue(t, pool, s.read2() - 1));
case 'S':
return makeShort(t, singletonValue(t, pool, s.read2() - 1));
case 'I':
return makeInt(t, singletonValue(t, pool, s.read2() - 1));
case 'F':
return makeFloat(t, bitsToFloat(singletonValue(t, pool, s.read2() - 1)));
case 'J': {
int64_t v; memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
return makeLong(t, v);
}
case 'D': {
double v; memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
return makeDouble(t, v);
}
case 's': {
object value = singletonObject(t, pool, s.read2() - 1);
return intern
(t, makeString(t, value, 0, byteArrayLength(t, value) - 1, 0));
}
case 'e': {
unsigned typeNameIndex = s.read2() - 1;
unsigned nameIndex = s.read2() - 1;
return makePair(t, singletonObject(t, pool, typeNameIndex),
singletonObject(t, pool, nameIndex));
}
case 'c':
return singletonObject(t, pool, s.read2() - 1);
case '@':
return parseAnnotation(t, s, pool);
case '[': {
unsigned count = s.read2();
object array = makeObjectArray(t, count);
PROTECT(t, array);
for (unsigned i = 0; i < count; ++i) {
object value = parseAnnotationValue(t, s, pool);
if (UNLIKELY(t->exception)) return 0;
set(t, array, ArrayBody + (i * BytesPerWord), value);
}
return array;
}
default: abort(t);
}
}
object
parseAnnotation(Thread* t, Stream& s, object pool)
{
PROTECT(t, pool);
unsigned typeIndex = s.read2() - 1;
unsigned elementCount = s.read2();
object array = makeObjectArray(t, (elementCount * 2) + 2);
PROTECT(t, array);
set(t, array, ArrayBody + BytesPerWord, singletonObject(t, pool, typeIndex));
for (unsigned i = 0; i < elementCount; ++i) {
set(t, array, ArrayBody + (((i * 2) + 2) * BytesPerWord),
singletonObject(t, pool, s.read2() - 1));
object value = parseAnnotationValue(t, s, pool);
if (UNLIKELY(t->exception)) return 0;
set(t, array, ArrayBody + (((i * 2) + 3) * BytesPerWord), value);
}
return array;
}
object
parseAnnotationTable(Thread* t, Stream& s, object pool)
{
PROTECT(t, pool);
unsigned annotationCount = s.read2();
object annotations = makeArray(t, annotationCount);
PROTECT(t, annotations);
for (unsigned i = 0; i < annotationCount; ++i) {
object annotation = parseAnnotation(t, s, pool);
if (UNLIKELY(t->exception)) return 0;
set(t, annotations, ArrayBody + (i * BytesPerWord), annotation);
}
return annotations;
}
void
parseFieldTable(Thread* t, Stream& s, object class_, object pool)
{
@ -1038,6 +1108,9 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
object staticValueTable = makeIntArray(t, count);
PROTECT(t, staticValueTable);
object addendum = 0;
PROTECT(t, addendum);
RUNTIME_ARRAY(uint8_t, staticTypes, count);
for (unsigned i = 0; i < count; ++i) {
@ -1059,6 +1132,11 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
value = s.read2();
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
addendum = makeFieldAddendum(t, parseAnnotationTable(t, s, pool));
} else {
s.skip(length);
}
@ -1072,6 +1150,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
0, // offset
singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1),
addendum,
class_);
if (flags & ACC_STATIC) {
@ -1318,6 +1397,7 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap,
0,
methodName(t, method),
methodSpec(t, method),
0,
class_,
0,
0);
@ -1380,12 +1460,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
object methodTable = makeArray(t, count);
PROTECT(t, methodTable);
object addendum = 0;
PROTECT(t, addendum);
object code = 0;
PROTECT(t, code);
for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2();
unsigned name = s.read2();
unsigned spec = s.read2();
object code = 0;
code = 0;
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1);
@ -1395,6 +1482,11 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
code = parseCode(t, s, pool);
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
addendum = makeMethodAddendum(t, parseAnnotationTable(t, s, pool));
} else {
s.skip(length);
}
@ -1417,6 +1509,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
0, // offset
singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1),
addendum,
class_,
code);
@ -1493,7 +1586,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
if (classInterfaceTable(t, classSuper(t, class_))
and arrayLength(t, classInterfaceTable(t, class_))
== arrayLength(t, classInterfaceTable(t, classSuper(t, class_))))
== arrayLength
(t, classInterfaceTable(t, classSuper(t, class_))))
{
// inherit interface table from superclass
set(t, class_, ClassInterfaceTable,
@ -1541,6 +1635,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
}
if (abstractVirtuals) {
PROTECT(t, vtable);
PROTECT(t, abstractVirtuals);
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
@ -1592,7 +1687,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
(t, virtualMap, method, methodHash, methodEqual);
assert(t, method);
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
}
}
}
@ -1612,6 +1707,14 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
object addendum = makeClassAddendum
(t, parseAnnotationTable(t, s, pool), 0);
set(t, class_, ClassAddendum, addendum);
} else {
s.skip(length);
}
@ -1702,6 +1805,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
vtable,
0,
0,
0,
elementClass,
loader,
arrayLength(t, vtable));
@ -1832,7 +1936,7 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
object class_ = t->m->processor->makeClass
(t, 0, BootstrapFlag, fixedSize, arrayElementSize, 0, mask, 0, 0, super, 0,
0, 0, 0, 0, t->m->loader, vtableLength);
0, 0, 0, 0, 0, t->m->loader, vtableLength);
set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_);
}
@ -1945,7 +2049,7 @@ boot(Thread* t)
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1);
codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
PROTECT(t, bootMethod);
#include "type-java-initializations.cpp"
@ -2084,6 +2188,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
tenuredWeakReferences(0),
shutdownHooks(0),
objectsToFinalize(0),
invokeMethod(0),
unsafe(false),
triedBuiltinOnLoad(false),
heapPoolIndex(0)
@ -2824,12 +2929,13 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
0, // object mask
referenceName
(t, singletonObject(t, pool, name - 1)),
0,
0, // source file
0, // super
0, // interfaces
0, // vtable
0, // fields
0, // methods
0, // addendum
0, // static table
loader,
0);// vtable length
@ -2878,6 +2984,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
classVirtualTable(t, class_),
classFieldTable(t, class_),
classMethodTable(t, class_),
classAddendum(t, class_),
classStaticTable(t, class_),
classLoader(t, class_),
vtableLength);
@ -3032,60 +3139,6 @@ resolveClass(Thread* t, object loader, object spec)
}
}
void
linkClass(Thread* t, object loader, object class_)
{
PROTECT(t, loader);
PROTECT(t, class_);
ACQUIRE(t, t->m->classLock);
if ((classVmFlags(t, class_) & LinkFlag) == 0) {
if (classSuper(t, class_)) {
linkClass(t, loader, classSuper(t, class_));
}
if (classInterfaceTable(t, class_)) {
unsigned increment = 2;
if (classFlags(t, class_) & ACC_INTERFACE) {
increment = 1;
}
for (unsigned i = 0; i < arrayLength(t, classInterfaceTable(t, class_));
i += increment)
{
linkClass(t, loader, arrayBody(t, classInterfaceTable(t, class_), i));
}
}
if (classMethodTable(t, class_)) {
for (unsigned i = 0;
i < arrayLength(t, classMethodTable(t, class_)); ++i)
{
object spec = methodSpec
(t, arrayBody(t, classMethodTable(t, class_), i));
PROTECT(t, spec);
for (unsigned j = 1; j < byteArrayLength(t, spec);) {
j = resolveSpec(t, loader, spec, j);
if (UNLIKELY(t->exception)) return;
}
}
}
if (classFieldTable(t, class_)) {
for (unsigned i = 0; i < arrayLength(t, classFieldTable(t, class_)); ++i)
{
resolveSpec(t, loader, fieldSpec
(t, arrayBody(t, classFieldTable(t, class_), i)), 0);
if (UNLIKELY(t->exception)) return;
}
}
classVmFlags(t, class_) |= LinkFlag;
}
}
object
resolveMethod(Thread* t, object class_, const char* methodName,
const char* methodSpec)
@ -3573,6 +3626,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
v->visit(&(m->jniMethodTable));
v->visit(&(m->shutdownHooks));
v->visit(&(m->objectsToFinalize));
v->visit(&(m->invokeMethod));
for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v);

@ -1204,6 +1204,7 @@ class Machine {
object tenuredWeakReferences;
object shutdownHooks;
object objectsToFinalize;
object invokeMethod;
bool unsafe;
bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable;
@ -1846,6 +1847,12 @@ makeExceptionInInitializerError(Thread* t, object cause)
return makeExceptionInInitializerError(t, 0, trace, cause, cause);
}
inline object
makeIncompatibleClassChangeError(Thread* t)
{
return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0);
}
inline object
makeNew(Thread* t, object class_)
{
@ -2194,6 +2201,13 @@ initClass(Thread* t, object c);
object
makeObjectArray(Thread* t, object loader, object elementClass, unsigned count);
inline object
makeObjectArray(Thread* t, unsigned count)
{
return makeObjectArray
(t, t->m->loader, arrayBody(t, t->m->types, Machine::JobjectType), count);
}
object
findInTable(Thread* t, object table, object name, object spec,
object& (*getName)(Thread*, object),
@ -2232,6 +2246,22 @@ findVirtualMethod(Thread* t, object method, object class_)
methodOffset(t, method));
}
inline object
findInterfaceMethod(Thread* t, object method, object class_)
{
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
object interface = methodClass(t, method);
object itable = classInterfaceTable(t, class_);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == interface) {
return arrayBody(t, arrayBody(t, itable, i + 1),
methodOffset(t, method));
}
}
abort(t);
}
inline unsigned
objectArrayLength(Thread* t UNUSED, object array)
{
@ -2248,7 +2278,7 @@ objectArrayBody(Thread* t UNUSED, object array, unsigned index)
assert(t, classObjectMask(t, objectClass(t, array))
== classObjectMask(t, arrayBody
(t, t->m->types, Machine::ArrayType)));
return cast<object>(array, (2 + index) * BytesPerWord);
return cast<object>(array, ArrayBody + (index * BytesPerWord));
}
unsigned

@ -59,22 +59,6 @@ isSpecialMethod(Thread* t, object method, object class_)
void*
resolveNativeMethod(Thread* t, object method);
inline object
findInterfaceMethod(Thread* t, object method, object class_)
{
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
object interface = methodClass(t, method);
object itable = classInterfaceTable(t, class_);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == interface) {
return arrayBody(t, arrayBody(t, itable, i + 1),
methodOffset(t, method));
}
}
abort(t);
}
inline void
populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions)

@ -54,6 +54,7 @@ class Processor {
uint16_t offset,
object name,
object spec,
object addendum,
object class_,
object code) = 0;
@ -72,6 +73,7 @@ class Processor {
object virtualTable,
object fieldTable,
object methodTable,
object addendum,
object staticTable,
object loader,
unsigned vtableLength) = 0;

@ -13,10 +13,20 @@
(type accessibleObject java/lang/reflect/AccessibleObject)
(type classAddendum java/lang/Class$Addendum)
(type field java/lang/reflect/Field)
(type fieldAddendum java/lang/reflect/Field$Addendum)
(type method java/lang/reflect/Method)
(type methodAddendum java/lang/reflect/Method$Addendum)
(type proxy java/lang/reflect/Proxy)
(type pair avian/Pair)
(type nativeMethodData
(void* function)
(uint16_t argumentTableSize)
@ -54,10 +64,6 @@
(object name)
(object spec))
(type pair
(object first)
(object second))
(type triple
(object first)
(object second)

49
test/Annotations.java Normal file

@ -0,0 +1,49 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class Annotations {
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
public static void main(String[] args) throws Exception {
Method m = Annotations.class.getMethod("foo");
expect(m.isAnnotationPresent(Test.class));
expect(((Test) m.getAnnotation(Test.class)).value().equals("couscous"));
expect(((TestEnum) m.getAnnotation(TestEnum.class)).value()
.equals(Color.Red));
expect(((TestInteger) m.getAnnotation(TestInteger.class)).value() == 42);
}
@Test("couscous")
@TestEnum(Color.Red)
@TestInteger(42)
public static void foo() {
}
@Retention(RetentionPolicy.RUNTIME)
private @interface Test {
public String value();
}
@Retention(RetentionPolicy.RUNTIME)
private @interface TestEnum {
public Color value();
}
@Retention(RetentionPolicy.RUNTIME)
private @interface TestInteger {
public int value();
}
private static enum Color {
Red, Yellow, Blue
}
}

42
test/Proxies.java Normal file

@ -0,0 +1,42 @@
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Proxies {
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
public static void main(String[] args) {
Foo foo = (Foo) Proxy.newProxyInstance
(Proxies.class.getClassLoader(), new Class[] { Foo.class },
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] arguments)
{
if (method.getName().equals("bar")) {
return "bam";
} else if (method.getName().equals("baz")) {
return ((Integer) arguments[0]) + 1;
} else if (method.getName().equals("bim")) {
return ((Long) arguments[0]) - 1L;
} else if (method.getName().equals("boom")) {
return ((String) arguments[0]).substring(1);
} else {
throw new IllegalArgumentException();
}
}
});
expect(foo.bar().equals("bam"));
expect(foo.baz(42) == 43);
expect(foo.bim(42L) == 41L);
expect(foo.boom("hello").equals("ello"));
}
private interface Foo {
public String bar();
public int baz(int v);
public long bim(long v);
public String boom(String s);
}
}