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

View File

@ -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
View 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;
}

View File

@ -10,14 +10,20 @@
package java.lang; package java.lang;
import avian.AnnotationInvocationHandler;
import avian.Pair;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.GenericDeclaration; import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.AnnotatedElement;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
@ -28,8 +34,11 @@ import java.security.ProtectionDomain;
import java.security.Permissions; import java.security.Permissions;
import java.security.AllPermission; 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 PrimitiveFlag = 1 << 5;
private static final int LinkFlag = 1 << 8;
private short flags; private short flags;
private short vmFlags; private short vmFlags;
@ -44,6 +53,7 @@ public final class Class <T> implements Type, GenericDeclaration {
private Method[] virtualTable; private Method[] virtualTable;
private Field[] fieldTable; private Field[] fieldTable;
private Method[] methodTable; private Method[] methodTable;
private Addendum addendum;
private Object staticTable; private Object staticTable;
private ClassLoader loader; 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 { public static Class forName(String name) throws ClassNotFoundException {
return forName return forName
(name, true, Method.getCaller().getDeclaringClass().getClassLoader()); (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 static native Class primitiveClass(char name);
private native void link(ClassLoader loader);
private native void initialize(); private native void initialize();
public static Class forCanonicalName(String name) { public static Class forCanonicalName(String name) {
@ -479,9 +638,10 @@ public final class Class <T> implements Type, GenericDeclaration {
if (interfaceTable != null) { if (interfaceTable != null) {
link(loader); 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) { for (int i = 0; i < array.length; ++i) {
array[i] = (Class) interfaceTable[i * 2]; array[i] = (Class) interfaceTable[i * stride];
} }
return array; return array;
} else { } else {
@ -566,7 +726,7 @@ public final class Class <T> implements Type, GenericDeclaration {
} }
public Object[] getSigners() { public Object[] getSigners() {
return Static.signers.get(this); return addendum == null ? null : addendum.signers;
} }
public Package getPackage() { 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() { 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() { public boolean isEnum() {
@ -612,10 +840,6 @@ public final class Class <T> implements Type, GenericDeclaration {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public <A extends Annotation> A getAnnotation(Class<A> c) {
throw new UnsupportedOperationException();
}
public ProtectionDomain getProtectionDomain() { public ProtectionDomain getProtectionDomain() {
Permissions p = new Permissions(); Permissions p = new Permissions();
p.add(new AllPermission()); p.add(new AllPermission());
@ -625,11 +849,15 @@ public final class Class <T> implements Type, GenericDeclaration {
// for GNU Classpath compatibility: // for GNU Classpath compatibility:
void setSigners(Object[] signers) { void setSigners(Object[] signers) {
if (signers != null && signers.length > 0) { if (signers != null && signers.length > 0) {
Static.signers.put(this, signers); if (addendum == null) {
addendum = new Addendum();
}
addendum.signers = signers;
} }
} }
private static class Static { private static class Addendum {
public static final Map<Class,Object[]> signers = new HashMap(); public Object[] annotationTable;
public Object[] signers;
} }
} }

View File

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

View 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 java.lang.annotation;
@Retention(RetentionPolicy.RUNTIME)
public @interface Retention {
public RetentionPolicy value();
}

View File

@ -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
}

View File

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

View File

@ -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();
}

View File

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

View File

@ -10,6 +10,10 @@
package java.lang.reflect; package java.lang.reflect;
import avian.AnnotationInvocationHandler;
import java.lang.annotation.Annotation;
public class Field<T> extends AccessibleObject { public class Field<T> extends AccessibleObject {
private static final int VoidField = 0; private static final int VoidField = 0;
private static final int ByteField = 1; private static final int ByteField = 1;
@ -27,7 +31,8 @@ public class Field<T> extends AccessibleObject {
private short flags; private short flags;
private short offset; private short offset;
private byte[] name; private byte[] name;
private byte[] spec; public byte[] spec;
public Addendum addendum;
private Class<T> class_; private Class<T> class_;
private Field() { } 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() { public boolean isEnumConstant() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -210,4 +254,8 @@ public class Field<T> extends AccessibleObject {
private static native void setObject private static native void setObject
(Object instance, int offset, Object value); (Object instance, int offset, Object value);
public static class Addendum {
public Object[] annotationTable;
}
} }

View File

@ -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);
}

View File

@ -10,6 +10,10 @@
package java.lang.reflect; package java.lang.reflect;
import avian.AnnotationInvocationHandler;
import java.lang.annotation.Annotation;
public class Method<T> extends AccessibleObject public class Method<T> extends AccessibleObject
implements Member, GenericDeclaration implements Member, GenericDeclaration
{ {
@ -21,7 +25,8 @@ public class Method<T> extends AccessibleObject
private short offset; private short offset;
private int nativeID; private int nativeID;
private byte[] name; private byte[] name;
private byte[] spec; public byte[] spec;
public Addendum addendum;
private Class<T> class_; private Class<T> class_;
private Object code; private Object code;
private long compiled; private long compiled;
@ -142,6 +147,45 @@ public class Method<T> extends AccessibleObject
throw new RuntimeException(); 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() { public boolean isSynthetic() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -165,4 +209,8 @@ public class Method<T> extends AccessibleObject
public TypeVariable<Method<T>>[] getTypeParameters() { public TypeVariable<Method<T>>[] getTypeParameters() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public static class Addendum {
public Object[] annotationTable;
}
} }

View File

@ -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;
}
}
}

View File

@ -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 } // namespace
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
@ -199,16 +435,6 @@ Avian_java_lang_ClassLoader_defineClass
return reinterpret_cast<int64_t>(c); 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 extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedClass Avian_avian_SystemClassLoader_findLoadedClass
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
@ -302,13 +528,17 @@ Avian_java_lang_Class_initialize
} }
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Class_link Avian_java_lang_Class_acquireClassLock
(Thread* t, object, uintptr_t* arguments) (Thread* t, object)
{ {
object this_ = reinterpret_cast<object>(arguments[0]); acquire(t, t->m->classLock);
object loader = reinterpret_cast<object>(arguments[1]); }
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 extern "C" JNIEXPORT int64_t JNICALL
@ -499,6 +729,195 @@ Avian_java_lang_reflect_Array_makeObjectArray
(makeObjectArray(t, classLoader(t, elementType), elementType, length)); (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 extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Float_floatToRawIntBits Avian_java_lang_Float_floatToRawIntBits
(Thread*, object, uintptr_t* arguments) (Thread*, object, uintptr_t* arguments)

View File

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

View File

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

View File

@ -68,9 +68,8 @@ dispose(Thread* t, Thread* o, bool remove)
expect(t, find(t->m->rootThread, o)); expect(t, find(t->m->rootThread, o));
unsigned c = count(t->m->rootThread, o); unsigned c = count(t->m->rootThread, o);
Thread** threads = static_cast<Thread**> RUNTIME_ARRAY(Thread*, threads, c);
(allocate(t->m->system, c * sizeof(Thread*))); fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
fill(t->m->rootThread, o, threads);
#endif #endif
if (o->parent) { if (o->parent) {
@ -115,7 +114,7 @@ dispose(Thread* t, Thread* o, bool remove)
expect(t, not find(t->m->rootThread, o)); expect(t, not find(t->m->rootThread, o));
for (unsigned i = 0; i < c; ++i) { 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 #endif
} }
@ -604,51 +603,6 @@ makeByteArray(Thread* t, const char* format, va_list a)
return s; 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 unsigned
readByte(Stream& s, unsigned* value) readByte(Stream& s, unsigned* value)
{ {
@ -983,7 +937,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
object interfaceTable = 0; object interfaceTable = 0;
if (hashMapSize(t, map)) { if (hashMapSize(t, map)) {
unsigned length = hashMapSize(t, map) ; unsigned length = hashMapSize(t, map);
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
length *= 2; length *= 2;
} }
@ -1016,6 +970,122 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
set(t, class_, ClassInterfaceTable, interfaceTable); 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 void
parseFieldTable(Thread* t, Stream& s, object class_, object pool) 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); object staticValueTable = makeIntArray(t, count);
PROTECT(t, staticValueTable); PROTECT(t, staticValueTable);
object addendum = 0;
PROTECT(t, addendum);
RUNTIME_ARRAY(uint8_t, staticTypes, count); RUNTIME_ARRAY(uint8_t, staticTypes, count);
for (unsigned i = 0; i < count; ++i) { 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) &byteArrayBody(t, name, 0)) == 0)
{ {
value = s.read2(); 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 { } else {
s.skip(length); s.skip(length);
} }
@ -1072,6 +1150,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
0, // offset 0, // offset
singletonObject(t, pool, name - 1), singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1), singletonObject(t, pool, spec - 1),
addendum,
class_); class_);
if (flags & ACC_STATIC) { if (flags & ACC_STATIC) {
@ -1318,6 +1397,7 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap,
0, 0,
methodName(t, method), methodName(t, method),
methodSpec(t, method), methodSpec(t, method),
0,
class_, class_,
0, 0,
0); 0);
@ -1380,12 +1460,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
object methodTable = makeArray(t, count); object methodTable = makeArray(t, count);
PROTECT(t, methodTable); PROTECT(t, methodTable);
object addendum = 0;
PROTECT(t, addendum);
object code = 0;
PROTECT(t, code);
for (unsigned i = 0; i < count; ++i) { for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2(); unsigned flags = s.read2();
unsigned name = s.read2(); unsigned name = s.read2();
unsigned spec = s.read2(); unsigned spec = s.read2();
object code = 0; code = 0;
unsigned attributeCount = s.read2(); unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) { for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1); 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) &byteArrayBody(t, name, 0)) == 0)
{ {
code = parseCode(t, s, pool); 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 { } else {
s.skip(length); s.skip(length);
} }
@ -1417,6 +1509,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
0, // offset 0, // offset
singletonObject(t, pool, name - 1), singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1), singletonObject(t, pool, spec - 1),
addendum,
class_, class_,
code); code);
@ -1493,7 +1586,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
if (classInterfaceTable(t, classSuper(t, class_)) if (classInterfaceTable(t, classSuper(t, class_))
and arrayLength(t, classInterfaceTable(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 // inherit interface table from superclass
set(t, class_, ClassInterfaceTable, set(t, class_, ClassInterfaceTable,
@ -1541,6 +1635,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
} }
if (abstractVirtuals) { if (abstractVirtuals) {
PROTECT(t, vtable);
PROTECT(t, abstractVirtuals); PROTECT(t, abstractVirtuals);
unsigned oldLength = arrayLength(t, classMethodTable(t, class_)); 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); (t, virtualMap, method, methodHash, methodEqual);
assert(t, method); 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) &byteArrayBody(t, name, 0)) == 0)
{ {
set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1)); 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 { } else {
s.skip(length); s.skip(length);
} }
@ -1702,6 +1805,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
vtable, vtable,
0, 0,
0, 0,
0,
elementClass, elementClass,
loader, loader,
arrayLength(t, vtable)); arrayLength(t, vtable));
@ -1832,7 +1936,7 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
object class_ = t->m->processor->makeClass object class_ = t->m->processor->makeClass
(t, 0, BootstrapFlag, fixedSize, arrayElementSize, 0, mask, 0, 0, super, 0, (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_); 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); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1);
codeBody(t, bootCode, 0) = impdep1; codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod 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); PROTECT(t, bootMethod);
#include "type-java-initializations.cpp" #include "type-java-initializations.cpp"
@ -2084,6 +2188,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
tenuredWeakReferences(0), tenuredWeakReferences(0),
shutdownHooks(0), shutdownHooks(0),
objectsToFinalize(0), objectsToFinalize(0),
invokeMethod(0),
unsafe(false), unsafe(false),
triedBuiltinOnLoad(false), triedBuiltinOnLoad(false),
heapPoolIndex(0) heapPoolIndex(0)
@ -2824,12 +2929,13 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
0, // object mask 0, // object mask
referenceName referenceName
(t, singletonObject(t, pool, name - 1)), (t, singletonObject(t, pool, name - 1)),
0, 0, // source file
0, // super 0, // super
0, // interfaces 0, // interfaces
0, // vtable 0, // vtable
0, // fields 0, // fields
0, // methods 0, // methods
0, // addendum
0, // static table 0, // static table
loader, loader,
0);// vtable length 0);// vtable length
@ -2878,6 +2984,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
classVirtualTable(t, class_), classVirtualTable(t, class_),
classFieldTable(t, class_), classFieldTable(t, class_),
classMethodTable(t, class_), classMethodTable(t, class_),
classAddendum(t, class_),
classStaticTable(t, class_), classStaticTable(t, class_),
classLoader(t, class_), classLoader(t, class_),
vtableLength); 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 object
resolveMethod(Thread* t, object class_, const char* methodName, resolveMethod(Thread* t, object class_, const char* methodName,
const char* methodSpec) const char* methodSpec)
@ -3573,6 +3626,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
v->visit(&(m->jniMethodTable)); v->visit(&(m->jniMethodTable));
v->visit(&(m->shutdownHooks)); v->visit(&(m->shutdownHooks));
v->visit(&(m->objectsToFinalize)); v->visit(&(m->objectsToFinalize));
v->visit(&(m->invokeMethod));
for (Thread* t = m->rootThread; t; t = t->peer) { for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v); ::visitRoots(t, v);

View File

@ -1204,6 +1204,7 @@ class Machine {
object tenuredWeakReferences; object tenuredWeakReferences;
object shutdownHooks; object shutdownHooks;
object objectsToFinalize; object objectsToFinalize;
object invokeMethod;
bool unsafe; bool unsafe;
bool triedBuiltinOnLoad; bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable; JavaVMVTable javaVMVTable;
@ -1846,6 +1847,12 @@ makeExceptionInInitializerError(Thread* t, object cause)
return makeExceptionInInitializerError(t, 0, trace, cause, cause); return makeExceptionInInitializerError(t, 0, trace, cause, cause);
} }
inline object
makeIncompatibleClassChangeError(Thread* t)
{
return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0);
}
inline object inline object
makeNew(Thread* t, object class_) makeNew(Thread* t, object class_)
{ {
@ -2194,6 +2201,13 @@ initClass(Thread* t, object c);
object object
makeObjectArray(Thread* t, object loader, object elementClass, unsigned count); 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 object
findInTable(Thread* t, object table, object name, object spec, findInTable(Thread* t, object table, object name, object spec,
object& (*getName)(Thread*, object), object& (*getName)(Thread*, object),
@ -2232,6 +2246,22 @@ findVirtualMethod(Thread* t, object method, object class_)
methodOffset(t, method)); 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 inline unsigned
objectArrayLength(Thread* t UNUSED, object array) 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)) assert(t, classObjectMask(t, objectClass(t, array))
== classObjectMask(t, arrayBody == classObjectMask(t, arrayBody
(t, t->m->types, Machine::ArrayType))); (t, t->m->types, Machine::ArrayType)));
return cast<object>(array, (2 + index) * BytesPerWord); return cast<object>(array, ArrayBody + (index * BytesPerWord));
} }
unsigned unsigned

View File

@ -59,22 +59,6 @@ isSpecialMethod(Thread* t, object method, object class_)
void* void*
resolveNativeMethod(Thread* t, object method); 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 inline void
populateMultiArray(Thread* t, object array, int32_t* counts, populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions) unsigned index, unsigned dimensions)

View File

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

View File

@ -13,10 +13,20 @@
(type accessibleObject java/lang/reflect/AccessibleObject) (type accessibleObject java/lang/reflect/AccessibleObject)
(type classAddendum java/lang/Class$Addendum)
(type field java/lang/reflect/Field) (type field java/lang/reflect/Field)
(type fieldAddendum java/lang/reflect/Field$Addendum)
(type method java/lang/reflect/Method) (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 (type nativeMethodData
(void* function) (void* function)
(uint16_t argumentTableSize) (uint16_t argumentTableSize)
@ -54,10 +64,6 @@
(object name) (object name)
(object spec)) (object spec))
(type pair
(object first)
(object second))
(type triple (type triple
(object first) (object first)
(object second) (object second)

49
test/Annotations.java Normal file
View 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
View 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);
}
}