Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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

  • Loading branch information...
commit 7aa906d97bf5476edff745ed2bc8ac096cbb54c5 1 parent a2a33c2
Joel Dice authored
View
31 classpath/avian/AnnotationInvocationHandler.java
@@ -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();
+ }
+}
View
16 classpath/avian/Pair.java
@@ -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
256 classpath/java/lang/Class.java
@@ -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.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 @@
private Method[] virtualTable;
private Field[] fieldTable;
private Method[] methodTable;
+ private Addendum addendum;
private Object staticTable;
private ClassLoader loader;
@@ -139,6 +149,157 @@ public T newInstance()
}
}
+ 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 static Class forName(String name, boolean initialize,
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 @@ private int countMethods(boolean publicOnly) {
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 T cast(Object o) {
}
public Object[] getSigners() {
- return Static.signers.get(this);
+ return addendum == null ? null : addendum.signers;
}
public Package getPackage() {
@@ -584,8 +744,76 @@ public Package getPackage() {
}
}
+ 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 Class getEnclosingClass() {
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 ProtectionDomain getProtectionDomain() {
// 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;
}
}
View
4 classpath/java/lang/ClassLoader.java
@@ -83,7 +83,9 @@ protected Class loadClass(String name, boolean resolve)
return c;
}
- protected native void resolveClass(Class c);
+ protected void resolveClass(Class c) {
+ c.link(this);
+ }
private ClassLoader getParent() {
return parent;
View
16 classpath/java/lang/annotation/Retention.java
@@ -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
15 classpath/java/lang/annotation/RetentionPolicy.java
@@ -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
10 classpath/java/lang/reflect/AccessibleObject.java
@@ -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);
View
23 classpath/java/lang/reflect/AnnotatedElement.java
@@ -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
14 classpath/java/lang/reflect/Constructor.java
@@ -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 boolean 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() {
throw new UnsupportedOperationException();
}
View
50 classpath/java/lang/reflect/Field.java
@@ -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 @@
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 void set(Object instance, Object value)
}
}
+ 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 boolean isEnumConstant() {
private static native void setObject
(Object instance, int offset, Object value);
+
+ public static class Addendum {
+ public Object[] annotationTable;
+ }
}
View
15 classpath/java/lang/reflect/InvocationHandler.java
@@ -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
50 classpath/java/lang/reflect/Method.java
@@ -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 @@
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 getReturnType() {
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 Type getGenericReturnType() {
public TypeVariable<Method<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
+
+ public static class Addendum {
+ public Object[] annotationTable;
+ }
}
View
54 classpath/java/lang/reflect/Proxy.java
@@ -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
449 src/builtin.cpp
@@ -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
@@ -500,6 +730,195 @@ Avian_java_lang_reflect_Array_makeObjectArray
}
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)
{
View
9 src/compile.cpp
@@ -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));
View
6 src/interpret.cpp
@@ -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
View
274 src/machine.cpp
@@ -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
}
@@ -605,51 +604,6 @@ makeByteArray(Thread* t, const char* format, va_list a)
}
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)
{
if (*value == NoByte) {
@@ -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);
View
32 src/machine.h
@@ -1204,6 +1204,7 @@ class Machine {
object tenuredWeakReferences;
object shutdownHooks;
object objectsToFinalize;
+ object invokeMethod;
bool unsafe;
bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable;
@@ -1847,6 +1848,12 @@ makeExceptionInInitializerError(Thread* t, object cause)
}
inline object
+makeIncompatibleClassChangeError(Thread* t)
+{
+ return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0);
+}
+
+inline object
makeNew(Thread* t, object class_)
{
assert(t, t->state == Thread::ActiveState);
@@ -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
View
16 src/process.h
@@ -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)
View
2  src/processor.h
@@ -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;
View
14 src/types.def
@@ -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)
View
49 test/Annotations.java
@@ -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
+ }
+
+}
View
42 test/Proxies.java
@@ -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);
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.