mirror of
https://github.com/corda/corda.git
synced 2025-03-03 04:49:46 +00:00
support runtime-visible annotations and java.lang.reflect.Proxy
This commit is contained in:
parent
a2a33c259e
commit
7aa906d97b
31
classpath/avian/AnnotationInvocationHandler.java
Normal file
31
classpath/avian/AnnotationInvocationHandler.java
Normal 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
16
classpath/avian/Pair.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* Copyright (c) 2009, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package avian;
|
||||||
|
|
||||||
|
public class Pair<A,B> {
|
||||||
|
public A first;
|
||||||
|
public B second;
|
||||||
|
}
|
@ -10,14 +10,20 @@
|
|||||||
|
|
||||||
package java.lang;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
16
classpath/java/lang/annotation/Retention.java
Normal file
16
classpath/java/lang/annotation/Retention.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* Copyright (c) 2009, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package java.lang.annotation;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Retention {
|
||||||
|
public RetentionPolicy value();
|
||||||
|
}
|
15
classpath/java/lang/annotation/RetentionPolicy.java
Normal file
15
classpath/java/lang/annotation/RetentionPolicy.java
Normal 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
|
||||||
|
}
|
@ -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);
|
||||||
|
23
classpath/java/lang/reflect/AnnotatedElement.java
Normal file
23
classpath/java/lang/reflect/AnnotatedElement.java
Normal 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();
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
15
classpath/java/lang/reflect/InvocationHandler.java
Normal file
15
classpath/java/lang/reflect/InvocationHandler.java
Normal 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);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
54
classpath/java/lang/reflect/Proxy.java
Normal file
54
classpath/java/lang/reflect/Proxy.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
449
src/builtin.cpp
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
|
} // 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)
|
||||||
|
@ -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));
|
||||||
|
@ -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
|
||||||
|
274
src/machine.cpp
274
src/machine.cpp
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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
49
test/Annotations.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class Annotations {
|
||||||
|
private static void expect(boolean v) {
|
||||||
|
if (! v) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Method m = Annotations.class.getMethod("foo");
|
||||||
|
|
||||||
|
expect(m.isAnnotationPresent(Test.class));
|
||||||
|
|
||||||
|
expect(((Test) m.getAnnotation(Test.class)).value().equals("couscous"));
|
||||||
|
|
||||||
|
expect(((TestEnum) m.getAnnotation(TestEnum.class)).value()
|
||||||
|
.equals(Color.Red));
|
||||||
|
|
||||||
|
expect(((TestInteger) m.getAnnotation(TestInteger.class)).value() == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("couscous")
|
||||||
|
@TestEnum(Color.Red)
|
||||||
|
@TestInteger(42)
|
||||||
|
public static void foo() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
private @interface Test {
|
||||||
|
public String value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
private @interface TestEnum {
|
||||||
|
public Color value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
private @interface TestInteger {
|
||||||
|
public int value();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static enum Color {
|
||||||
|
Red, Yellow, Blue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
test/Proxies.java
Normal file
42
test/Proxies.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class Proxies {
|
||||||
|
private static void expect(boolean v) {
|
||||||
|
if (! v) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Foo foo = (Foo) Proxy.newProxyInstance
|
||||||
|
(Proxies.class.getClassLoader(), new Class[] { Foo.class },
|
||||||
|
new InvocationHandler() {
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] arguments)
|
||||||
|
{
|
||||||
|
if (method.getName().equals("bar")) {
|
||||||
|
return "bam";
|
||||||
|
} else if (method.getName().equals("baz")) {
|
||||||
|
return ((Integer) arguments[0]) + 1;
|
||||||
|
} else if (method.getName().equals("bim")) {
|
||||||
|
return ((Long) arguments[0]) - 1L;
|
||||||
|
} else if (method.getName().equals("boom")) {
|
||||||
|
return ((String) arguments[0]).substring(1);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(foo.bar().equals("bam"));
|
||||||
|
expect(foo.baz(42) == 43);
|
||||||
|
expect(foo.bim(42L) == 41L);
|
||||||
|
expect(foo.boom("hello").equals("ello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface Foo {
|
||||||
|
public String bar();
|
||||||
|
public int baz(int v);
|
||||||
|
public long bim(long v);
|
||||||
|
public String boom(String s);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user