mirror of
https://github.com/corda/corda.git
synced 2025-03-02 04:34:13 +00:00
support runtime-visible annotations and java.lang.reflect.Proxy
This commit is contained in:
parent
a2a33c259e
commit
7aa906d97b
classpath
avian
java/lang
src
test
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;
|
||||
|
||||
import avian.AnnotationInvocationHandler;
|
||||
import avian.Pair;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.GenericDeclaration;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
@ -28,8 +34,11 @@ import java.security.ProtectionDomain;
|
||||
import java.security.Permissions;
|
||||
import java.security.AllPermission;
|
||||
|
||||
public final class Class <T> implements Type, GenericDeclaration {
|
||||
public final class Class <T>
|
||||
implements Type, GenericDeclaration, AnnotatedElement
|
||||
{
|
||||
private static final int PrimitiveFlag = 1 << 5;
|
||||
private static final int LinkFlag = 1 << 8;
|
||||
|
||||
private short flags;
|
||||
private short vmFlags;
|
||||
@ -44,6 +53,7 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
private Method[] virtualTable;
|
||||
private Field[] fieldTable;
|
||||
private Method[] methodTable;
|
||||
private Addendum addendum;
|
||||
private Object staticTable;
|
||||
private ClassLoader loader;
|
||||
|
||||
@ -139,6 +149,157 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
}
|
||||
}
|
||||
|
||||
private static Class loadClass(ClassLoader loader,
|
||||
byte[] nameBytes, int offset, int length)
|
||||
{
|
||||
String name = new String(nameBytes, offset, length, false);
|
||||
try {
|
||||
return loader.loadClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
NoClassDefFoundError error = new NoClassDefFoundError(name);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object resolveAnnotationValue(ClassLoader loader,
|
||||
Object raw)
|
||||
{
|
||||
if (raw instanceof Pair) {
|
||||
Pair<byte[],byte[]> p = (Pair<byte[],byte[]>) raw;
|
||||
return Enum.valueOf
|
||||
(loadClass(loader, p.first, 1, p.first.length - 3),
|
||||
new String(p.second, 0, p.second.length - 1, false));
|
||||
} else if (raw instanceof byte[]) {
|
||||
byte[] typeName = (byte[]) raw;
|
||||
return loadClass(loader, typeName, 0, typeName.length - 1);
|
||||
} else if (raw.getClass().isArray()) {
|
||||
Object[] array = (Object[]) raw;
|
||||
if (array.length > 0 && array[0] == null) {
|
||||
resolveAnnotation(loader, array);
|
||||
} else {
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = resolveAnnotationValue(loader, array[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
private static void resolveAnnotation(ClassLoader loader,
|
||||
Object[] annotation)
|
||||
{
|
||||
byte[] typeName = (byte[]) annotation[1];
|
||||
annotation[1] = loadClass(loader, typeName, 1, typeName.length - 3);
|
||||
|
||||
for (int i = 2; i < annotation.length; i += 2) {
|
||||
byte[] name = (byte[]) annotation[i];
|
||||
annotation[i] = new String(name, 0, name.length - 1, false).intern();
|
||||
annotation[i + 1] = resolveAnnotationValue(loader, annotation[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveAnnotationTable(ClassLoader loader,
|
||||
Object[] table)
|
||||
{
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
resolveAnnotation(loader, (Object[]) table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static int resolveSpec(ClassLoader loader, byte[] spec, int start) {
|
||||
int result;
|
||||
int end;
|
||||
switch (spec[start]) {
|
||||
case 'L':
|
||||
++ start;
|
||||
end = start;
|
||||
while (spec[end] != ';') ++ end;
|
||||
result = end + 1;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
end = start + 1;
|
||||
while (spec[end] == '[') ++ end;
|
||||
switch (spec[end]) {
|
||||
case 'L':
|
||||
++ end;
|
||||
while (spec[end] != ';') ++ end;
|
||||
++ end;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ end;
|
||||
}
|
||||
result = end;
|
||||
break;
|
||||
|
||||
default:
|
||||
return start + 1;
|
||||
}
|
||||
|
||||
loadClass(loader, spec, start, end - start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static native void acquireClassLock();
|
||||
|
||||
private static native void releaseClassLock();
|
||||
|
||||
void link(ClassLoader loader) {
|
||||
acquireClassLock();
|
||||
try {
|
||||
if ((vmFlags & LinkFlag) == 0) {
|
||||
if (super_ != null) {
|
||||
super_.link(loader);
|
||||
}
|
||||
|
||||
if (addendum != null && addendum.annotationTable != null) {
|
||||
resolveAnnotationTable(loader, addendum.annotationTable);
|
||||
}
|
||||
|
||||
if (interfaceTable != null) {
|
||||
int stride = (isInterface() ? 1 : 2);
|
||||
for (int i = 0; i < interfaceTable.length; i += stride) {
|
||||
((Class) interfaceTable[i]).link(loader);
|
||||
}
|
||||
}
|
||||
|
||||
if (methodTable != null) {
|
||||
for (int i = 0; i < methodTable.length; ++i) {
|
||||
Method m = methodTable[i];
|
||||
|
||||
for (int j = 1; j < m.spec.length;) {
|
||||
j = resolveSpec(loader, m.spec, j);
|
||||
}
|
||||
|
||||
if (m.addendum != null && m.addendum.annotationTable != null) {
|
||||
resolveAnnotationTable(loader, m.addendum.annotationTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldTable != null) {
|
||||
for (int i = 0; i < fieldTable.length; ++i) {
|
||||
Field f = fieldTable[i];
|
||||
|
||||
resolveSpec(loader, f.spec, 0);
|
||||
|
||||
if (f.addendum != null && f.addendum.annotationTable != null) {
|
||||
resolveAnnotationTable(loader, f.addendum.annotationTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vmFlags |= LinkFlag;
|
||||
}
|
||||
} finally {
|
||||
releaseClassLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static Class forName(String name) throws ClassNotFoundException {
|
||||
return forName
|
||||
(name, true, Method.getCaller().getDeclaringClass().getClassLoader());
|
||||
@ -161,8 +322,6 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
|
||||
private static native Class primitiveClass(char name);
|
||||
|
||||
private native void link(ClassLoader loader);
|
||||
|
||||
private native void initialize();
|
||||
|
||||
public static Class forCanonicalName(String name) {
|
||||
@ -479,9 +638,10 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
if (interfaceTable != null) {
|
||||
link(loader);
|
||||
|
||||
Class[] array = new Class[interfaceTable.length / 2];
|
||||
int stride = (isInterface() ? 1 : 2);
|
||||
Class[] array = new Class[interfaceTable.length / stride];
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = (Class) interfaceTable[i * 2];
|
||||
array[i] = (Class) interfaceTable[i * stride];
|
||||
}
|
||||
return array;
|
||||
} else {
|
||||
@ -566,7 +726,7 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
}
|
||||
|
||||
public Object[] getSigners() {
|
||||
return Static.signers.get(this);
|
||||
return addendum == null ? null : addendum.signers;
|
||||
}
|
||||
|
||||
public Package getPackage() {
|
||||
@ -584,8 +744,76 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAnnotationPresent
|
||||
(Class<? extends Annotation> class_)
|
||||
{
|
||||
return getAnnotation(class_) != null;
|
||||
}
|
||||
|
||||
private Annotation getAnnotation(Object[] a) {
|
||||
if (a[0] == null) {
|
||||
a[0] = Proxy.newProxyInstance
|
||||
(loader, new Class[] { (Class) a[1] },
|
||||
new AnnotationInvocationHandler(a));
|
||||
}
|
||||
return (Annotation) a[0];
|
||||
}
|
||||
|
||||
public <T extends Annotation> T getAnnotation(Class<T> class_) {
|
||||
for (Class c = this; c != null; c = c.super_) {
|
||||
if (c.addendum != null && c.addendum.annotationTable != null) {
|
||||
link(c.loader);
|
||||
|
||||
Object[] table = c.addendum.annotationTable;
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
Object[] a = (Object[]) table[i];
|
||||
if (a[1] == class_) {
|
||||
return (T) c.getAnnotation(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
throw new UnsupportedOperationException();
|
||||
if (addendum != null && addendum.annotationTable != null) {
|
||||
link(loader);
|
||||
|
||||
Object[] table = addendum.annotationTable;
|
||||
Annotation[] array = new Annotation[table.length];
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
array[i] = getAnnotation((Object[]) table[i]);
|
||||
}
|
||||
return array;
|
||||
} else {
|
||||
return new Annotation[0];
|
||||
}
|
||||
}
|
||||
|
||||
private int countAnnotations() {
|
||||
int count = 0;
|
||||
for (Class c = this; c != null; c = c.super_) {
|
||||
if (c.addendum != null && c.addendum.annotationTable != null) {
|
||||
count += c.addendum.annotationTable.length;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public Annotation[] getAnnotations() {
|
||||
Annotation[] array = new Annotation[countMethods(true)];
|
||||
int i = 0;
|
||||
for (Class c = this; c != null; c = c.super_) {
|
||||
if (c.addendum != null && c.addendum.annotationTable != null) {
|
||||
Object[] table = c.addendum.annotationTable;
|
||||
for (int j = 0; j < table.length; ++j) {
|
||||
array[i++] = getAnnotation((Object[]) table[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public boolean isEnum() {
|
||||
@ -612,10 +840,6 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public <A extends Annotation> A getAnnotation(Class<A> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ProtectionDomain getProtectionDomain() {
|
||||
Permissions p = new Permissions();
|
||||
p.add(new AllPermission());
|
||||
@ -625,11 +849,15 @@ public final class Class <T> implements Type, GenericDeclaration {
|
||||
// for GNU Classpath compatibility:
|
||||
void setSigners(Object[] signers) {
|
||||
if (signers != null && signers.length > 0) {
|
||||
Static.signers.put(this, signers);
|
||||
if (addendum == null) {
|
||||
addendum = new Addendum();
|
||||
}
|
||||
addendum.signers = signers;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Static {
|
||||
public static final Map<Class,Object[]> signers = new HashMap();
|
||||
private static class Addendum {
|
||||
public Object[] annotationTable;
|
||||
public Object[] signers;
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,9 @@ public abstract class ClassLoader {
|
||||
return c;
|
||||
}
|
||||
|
||||
protected native void resolveClass(Class c);
|
||||
protected void resolveClass(Class c) {
|
||||
c.link(this);
|
||||
}
|
||||
|
||||
private ClassLoader getParent() {
|
||||
return parent;
|
||||
|
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;
|
||||
|
||||
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);
|
||||
|
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;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public class Constructor<T> extends AccessibleObject
|
||||
implements Member, GenericDeclaration
|
||||
{
|
||||
@ -52,6 +54,18 @@ public class Constructor<T> extends AccessibleObject
|
||||
return method.isSynthetic();
|
||||
}
|
||||
|
||||
public <T extends Annotation> T getAnnotation(Class<T> class_) {
|
||||
return method.getAnnotation(class_);
|
||||
}
|
||||
|
||||
public Annotation[] getAnnotations() {
|
||||
return method.getAnnotations();
|
||||
}
|
||||
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return method.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
public TypeVariable<Constructor<T>>[] getTypeParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -10,6 +10,10 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
import avian.AnnotationInvocationHandler;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public class Field<T> extends AccessibleObject {
|
||||
private static final int VoidField = 0;
|
||||
private static final int ByteField = 1;
|
||||
@ -27,7 +31,8 @@ public class Field<T> extends AccessibleObject {
|
||||
private short flags;
|
||||
private short offset;
|
||||
private byte[] name;
|
||||
private byte[] spec;
|
||||
public byte[] spec;
|
||||
public Addendum addendum;
|
||||
private Class<T> class_;
|
||||
|
||||
private Field() { }
|
||||
@ -195,6 +200,45 @@ public class Field<T> extends AccessibleObject {
|
||||
}
|
||||
}
|
||||
|
||||
private Annotation getAnnotation(Object[] a) {
|
||||
if (a[0] == null) {
|
||||
a[0] = Proxy.newProxyInstance
|
||||
(class_.getClassLoader(), new Class[] { (Class) a[1] },
|
||||
new AnnotationInvocationHandler(a));
|
||||
}
|
||||
return (Annotation) a[0];
|
||||
}
|
||||
|
||||
public <T extends Annotation> T getAnnotation(Class<T> class_) {
|
||||
if (addendum != null && addendum.annotationTable != null) {
|
||||
Object[] table = addendum.annotationTable;
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
Object[] a = (Object[]) table[i];
|
||||
if (a[1] == class_) {
|
||||
return (T) getAnnotation(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Annotation[] getAnnotations() {
|
||||
if (addendum != null && addendum.annotationTable != null) {
|
||||
Object[] table = addendum.annotationTable;
|
||||
Annotation[] array = new Annotation[table.length];
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
array[i] = getAnnotation((Object[]) table[i]);
|
||||
}
|
||||
return array;
|
||||
} else {
|
||||
return new Annotation[0];
|
||||
}
|
||||
}
|
||||
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return getAnnotations();
|
||||
}
|
||||
|
||||
public boolean isEnumConstant() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@ -210,4 +254,8 @@ public class Field<T> extends AccessibleObject {
|
||||
|
||||
private static native void setObject
|
||||
(Object instance, int offset, Object value);
|
||||
|
||||
public static class Addendum {
|
||||
public Object[] annotationTable;
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
|
||||
import avian.AnnotationInvocationHandler;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public class Method<T> extends AccessibleObject
|
||||
implements Member, GenericDeclaration
|
||||
{
|
||||
@ -21,7 +25,8 @@ public class Method<T> extends AccessibleObject
|
||||
private short offset;
|
||||
private int nativeID;
|
||||
private byte[] name;
|
||||
private byte[] spec;
|
||||
public byte[] spec;
|
||||
public Addendum addendum;
|
||||
private Class<T> class_;
|
||||
private Object code;
|
||||
private long compiled;
|
||||
@ -142,6 +147,45 @@ public class Method<T> extends AccessibleObject
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
private Annotation getAnnotation(Object[] a) {
|
||||
if (a[0] == null) {
|
||||
a[0] = Proxy.newProxyInstance
|
||||
(class_.getClassLoader(), new Class[] { (Class) a[1] },
|
||||
new AnnotationInvocationHandler(a));
|
||||
}
|
||||
return (Annotation) a[0];
|
||||
}
|
||||
|
||||
public <T extends Annotation> T getAnnotation(Class<T> class_) {
|
||||
if (addendum != null && addendum.annotationTable != null) {
|
||||
Object[] table = addendum.annotationTable;
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
Object[] a = (Object[]) table[i];
|
||||
if (a[1] == class_) {
|
||||
return (T) getAnnotation(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Annotation[] getAnnotations() {
|
||||
if (addendum != null && addendum.annotationTable != null) {
|
||||
Object[] table = addendum.annotationTable;
|
||||
Annotation[] array = new Annotation[table.length];
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
array[i] = getAnnotation((Object[]) table[i]);
|
||||
}
|
||||
return array;
|
||||
} else {
|
||||
return new Annotation[0];
|
||||
}
|
||||
}
|
||||
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return getAnnotations();
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@ -165,4 +209,8 @@ public class Method<T> extends AccessibleObject
|
||||
public TypeVariable<Method<T>>[] getTypeParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static class Addendum {
|
||||
public Object[] annotationTable;
|
||||
}
|
||||
}
|
||||
|
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
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
@ -199,16 +435,6 @@ Avian_java_lang_ClassLoader_defineClass
|
||||
return reinterpret_cast<int64_t>(c);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_ClassLoader_resolveClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object loader = reinterpret_cast<object>(arguments[0]);
|
||||
object class_ = reinterpret_cast<object>(arguments[1]);
|
||||
|
||||
linkClass(t, loader, class_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_avian_SystemClassLoader_findLoadedClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
@ -302,13 +528,17 @@ Avian_java_lang_Class_initialize
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Class_link
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
Avian_java_lang_Class_acquireClassLock
|
||||
(Thread* t, object)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
object loader = reinterpret_cast<object>(arguments[1]);
|
||||
acquire(t, t->m->classLock);
|
||||
}
|
||||
|
||||
linkClass(t, loader, this_);
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Class_releaseClassLock
|
||||
(Thread* t, object)
|
||||
{
|
||||
release(t, t->m->classLock);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
@ -499,6 +729,195 @@ Avian_java_lang_reflect_Array_makeObjectArray
|
||||
(makeObjectArray(t, classLoader(t, elementType), elementType, length));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Proxy_makeClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object loader = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, loader);
|
||||
|
||||
object interfaces = allInterfaces(t, reinterpret_cast<object>(arguments[1]));
|
||||
PROTECT(t, interfaces);
|
||||
|
||||
object name = reinterpret_cast<object>(arguments[2]);
|
||||
PROTECT(t, name);
|
||||
|
||||
object virtualMap = makeHashMap(t, 0, 0);
|
||||
PROTECT(t, virtualMap);
|
||||
|
||||
object superVtable = classVirtualTable
|
||||
(t, arrayBody(t, t->m->types, Machine::ProxyType));
|
||||
PROTECT(t, superVtable);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, superVtable); ++i) {
|
||||
object method = arrayBody(t, superVtable, i);
|
||||
hashMapInsert(t, virtualMap, method, method, methodHash);
|
||||
}
|
||||
|
||||
unsigned virtualCount = arrayLength(t, superVtable);
|
||||
|
||||
object newVirtuals = makeList(t, 0, 0, 0);
|
||||
PROTECT(t, newVirtuals);
|
||||
|
||||
object ivtable = 0;
|
||||
PROTECT(t, ivtable);
|
||||
|
||||
object method = 0;
|
||||
PROTECT(t, method);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, interfaces); ++i) {
|
||||
ivtable = classVirtualTable(t, arrayBody(t, interfaces, i));
|
||||
|
||||
if (ivtable) {
|
||||
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
||||
method = arrayBody(t, ivtable, j);
|
||||
|
||||
method = makeMethod
|
||||
(t,
|
||||
methodVmFlags(t, method) | FastNative,
|
||||
methodReturnCode(t, method),
|
||||
methodParameterCount(t, method),
|
||||
methodParameterFootprint(t, method),
|
||||
methodFlags(t, method) | ACC_NATIVE,
|
||||
0,
|
||||
0,
|
||||
methodName(t, method),
|
||||
methodSpec(t, method),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
reinterpret_cast<int64_t>(proxyInvoke));
|
||||
|
||||
object p = hashMapFindNode
|
||||
(t, virtualMap, method, methodHash, methodEqual);
|
||||
|
||||
if (p) {
|
||||
methodOffset(t, method) = methodOffset(t, tripleFirst(t, p));
|
||||
|
||||
set(t, p, TripleSecond, method);
|
||||
} else {
|
||||
methodOffset(t, method) = virtualCount++;
|
||||
|
||||
listAppend(t, newVirtuals, method);
|
||||
|
||||
hashMapInsert(t, virtualMap, method, method, methodHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object vtable = makeArray(t, virtualCount);
|
||||
PROTECT(t, vtable);
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < arrayLength(t, superVtable); ++i) {
|
||||
method = hashMapFind
|
||||
(t, virtualMap, arrayBody(t, superVtable, i), methodHash, methodEqual);
|
||||
|
||||
set(t, vtable, ArrayBody + (i * BytesPerWord), method);
|
||||
}
|
||||
|
||||
object methodTable = makeArray(t, listSize(t, newVirtuals) + 1);
|
||||
PROTECT(t, methodTable);
|
||||
|
||||
unsigned mti = 0;
|
||||
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
|
||||
set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p));
|
||||
++ i;
|
||||
|
||||
set(t, methodTable, ArrayBody + (mti * BytesPerWord), pairFirst(t, p));
|
||||
++ mti;
|
||||
}
|
||||
|
||||
#define NAME "<init>"
|
||||
object constructorName = makeByteArray(t, sizeof(NAME));
|
||||
PROTECT(t, constructorName);
|
||||
memcpy(&byteArrayBody(t, constructorName, 0), NAME, sizeof(NAME));
|
||||
|
||||
#define SPEC "(Ljava/lang/reflect/InvocationHandler;)V"
|
||||
object constructorSpec = makeByteArray(t, sizeof(SPEC));
|
||||
PROTECT(t, constructorSpec);
|
||||
memcpy(&byteArrayBody(t, constructorSpec, 0), SPEC, sizeof(SPEC));
|
||||
|
||||
object constructor = makeMethod
|
||||
(t,
|
||||
methodVmFlags(t, method) | FastNative,
|
||||
VoidField,
|
||||
1,
|
||||
2,
|
||||
methodFlags(t, method) | ACC_NATIVE,
|
||||
0,
|
||||
0,
|
||||
constructorName,
|
||||
constructorSpec,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
reinterpret_cast<int64_t>(proxyConstruct));
|
||||
|
||||
set(t, methodTable, ArrayBody + (mti * BytesPerWord), constructor);
|
||||
++ mti;
|
||||
|
||||
assert(t, arrayLength(t, vtable) == i);
|
||||
assert(t, arrayLength(t, methodTable) == mti);
|
||||
|
||||
object itable = makeArray(t, arrayLength(t, interfaces) * 2);
|
||||
PROTECT(t, itable);
|
||||
|
||||
object newIVTable = 0;
|
||||
PROTECT(t, newIVTable);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, interfaces); ++i) {
|
||||
object interface = arrayBody(t, interfaces, i);
|
||||
|
||||
set(t, itable, ArrayBody + ((i * 2) * BytesPerWord), interface);
|
||||
|
||||
ivtable = classVirtualTable(t, interface);
|
||||
if (ivtable) {
|
||||
newIVTable = makeArray(t, arrayLength(t, ivtable));
|
||||
|
||||
set(t, itable, ArrayBody + (((i * 2) + 1) * BytesPerWord), newIVTable);
|
||||
|
||||
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
||||
method = hashMapFind
|
||||
(t, virtualMap, arrayBody(t, ivtable, j), methodHash, methodEqual);
|
||||
assert(t, method);
|
||||
|
||||
set(t, newIVTable, ArrayBody + (j * BytesPerWord), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object c = t->m->processor->makeClass
|
||||
(t,
|
||||
0,
|
||||
0,
|
||||
classFixedSize(t, arrayBody(t, t->m->types, Machine::ProxyType)),
|
||||
0,
|
||||
0,
|
||||
classObjectMask(t, arrayBody(t, t->m->types, Machine::ProxyType)),
|
||||
name,
|
||||
0,
|
||||
arrayBody(t, t->m->types, Machine::ProxyType),
|
||||
itable,
|
||||
vtable,
|
||||
0,
|
||||
methodTable,
|
||||
0,
|
||||
0,
|
||||
loader,
|
||||
arrayLength(t, vtable));
|
||||
PROTECT(t, c);
|
||||
|
||||
t->m->processor->initVtable(t, c);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
||||
set(t, arrayBody(t, methodTable, i), MethodClass, c);
|
||||
}
|
||||
|
||||
return reinterpret_cast<int64_t>(c);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_floatToRawIntBits
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
|
@ -6331,7 +6331,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
|
||||
|
||||
default:
|
||||
abort(t);
|
||||
};
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -6450,12 +6450,13 @@ class MyProcessor: public Processor {
|
||||
uint16_t offset,
|
||||
object name,
|
||||
object spec,
|
||||
object addendum,
|
||||
object class_,
|
||||
object code)
|
||||
{
|
||||
return vm::makeMethod
|
||||
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
||||
offset, 0, name, spec, class_, code,
|
||||
offset, 0, name, spec, addendum, class_, code,
|
||||
local::defaultThunk(static_cast<MyThread*>(t)));
|
||||
}
|
||||
|
||||
@ -6475,13 +6476,14 @@ class MyProcessor: public Processor {
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object staticTable,
|
||||
object addendum,
|
||||
object loader,
|
||||
unsigned vtableLength)
|
||||
{
|
||||
return vm::makeClass
|
||||
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions,
|
||||
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
|
||||
fieldTable, methodTable, staticTable, loader, vtableLength);
|
||||
fieldTable, methodTable, staticTable, addendum, loader, vtableLength);
|
||||
}
|
||||
|
||||
virtual void
|
||||
@ -7656,6 +7658,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext,
|
||||
methodNativeID(t, method),
|
||||
methodName(t, method),
|
||||
methodSpec(t, method),
|
||||
methodAddendum(t, method),
|
||||
methodClass(t, method),
|
||||
methodCode(t, method),
|
||||
reinterpret_cast<intptr_t>(compiled));
|
||||
|
@ -3093,11 +3093,12 @@ class MyProcessor: public Processor {
|
||||
object name,
|
||||
object spec,
|
||||
object class_,
|
||||
object addendum,
|
||||
object code)
|
||||
{
|
||||
return vm::makeMethod
|
||||
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
||||
offset, 0, name, spec, class_, code, 0);
|
||||
offset, 0, name, spec, addendum, class_, code, 0);
|
||||
}
|
||||
|
||||
virtual object
|
||||
@ -3116,13 +3117,14 @@ class MyProcessor: public Processor {
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object staticTable,
|
||||
object addendum,
|
||||
object loader,
|
||||
unsigned vtableLength UNUSED)
|
||||
{
|
||||
return vm::makeClass
|
||||
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions,
|
||||
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
|
||||
fieldTable, methodTable, staticTable, loader, 0);
|
||||
fieldTable, methodTable, addendum, staticTable, loader, 0);
|
||||
}
|
||||
|
||||
virtual void
|
||||
|
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));
|
||||
|
||||
unsigned c = count(t->m->rootThread, o);
|
||||
Thread** threads = static_cast<Thread**>
|
||||
(allocate(t->m->system, c * sizeof(Thread*)));
|
||||
fill(t->m->rootThread, o, threads);
|
||||
RUNTIME_ARRAY(Thread*, threads, c);
|
||||
fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
|
||||
#endif
|
||||
|
||||
if (o->parent) {
|
||||
@ -115,7 +114,7 @@ dispose(Thread* t, Thread* o, bool remove)
|
||||
expect(t, not find(t->m->rootThread, o));
|
||||
|
||||
for (unsigned i = 0; i < c; ++i) {
|
||||
expect(t, find(t->m->rootThread, threads[i]));
|
||||
expect(t, find(t->m->rootThread, RUNTIME_ARRAY_BODY(threads)[i]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -604,51 +603,6 @@ makeByteArray(Thread* t, const char* format, va_list a)
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned
|
||||
resolveSpec(Thread* t, object loader, object spec, unsigned offset)
|
||||
{
|
||||
int8_t* s = &byteArrayBody(t, spec, offset);
|
||||
unsigned result;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
++ offset;
|
||||
while (*s and *s != ';') ++ s;
|
||||
result = s + 1 - &byteArrayBody(t, spec, 0);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
result = s - &byteArrayBody(t, spec, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
PROTECT(t, spec);
|
||||
PROTECT(t, loader);
|
||||
|
||||
unsigned length = s - &byteArrayBody(t, spec, offset);
|
||||
|
||||
object name = makeByteArray(t, length + 1);
|
||||
memcpy(&byteArrayBody(t, name, 0),
|
||||
&byteArrayBody(t, spec, offset),
|
||||
length);
|
||||
resolveClass(t, loader, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned
|
||||
readByte(Stream& s, unsigned* value)
|
||||
{
|
||||
@ -983,7 +937,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
object interfaceTable = 0;
|
||||
if (hashMapSize(t, map)) {
|
||||
unsigned length = hashMapSize(t, map) ;
|
||||
unsigned length = hashMapSize(t, map);
|
||||
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
||||
length *= 2;
|
||||
}
|
||||
@ -1016,6 +970,122 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
||||
set(t, class_, ClassInterfaceTable, interfaceTable);
|
||||
}
|
||||
|
||||
object
|
||||
parseAnnotation(Thread* t, Stream& s, object pool);
|
||||
|
||||
object
|
||||
parseAnnotationValue(Thread* t, Stream& s, object pool)
|
||||
{
|
||||
unsigned tag = s.read1();
|
||||
switch (tag) {
|
||||
case 'Z':
|
||||
return makeBoolean(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'B':
|
||||
return makeByte(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'C':
|
||||
return makeChar(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'S':
|
||||
return makeShort(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'I':
|
||||
return makeInt(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'F':
|
||||
return makeFloat(t, bitsToFloat(singletonValue(t, pool, s.read2() - 1)));
|
||||
|
||||
case 'J': {
|
||||
int64_t v; memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
|
||||
return makeLong(t, v);
|
||||
}
|
||||
|
||||
case 'D': {
|
||||
double v; memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
|
||||
return makeDouble(t, v);
|
||||
}
|
||||
|
||||
case 's': {
|
||||
object value = singletonObject(t, pool, s.read2() - 1);
|
||||
return intern
|
||||
(t, makeString(t, value, 0, byteArrayLength(t, value) - 1, 0));
|
||||
}
|
||||
|
||||
case 'e': {
|
||||
unsigned typeNameIndex = s.read2() - 1;
|
||||
unsigned nameIndex = s.read2() - 1;
|
||||
return makePair(t, singletonObject(t, pool, typeNameIndex),
|
||||
singletonObject(t, pool, nameIndex));
|
||||
}
|
||||
|
||||
case 'c':
|
||||
return singletonObject(t, pool, s.read2() - 1);
|
||||
|
||||
case '@':
|
||||
return parseAnnotation(t, s, pool);
|
||||
|
||||
case '[': {
|
||||
unsigned count = s.read2();
|
||||
object array = makeObjectArray(t, count);
|
||||
PROTECT(t, array);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
object value = parseAnnotationValue(t, s, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, array, ArrayBody + (i * BytesPerWord), value);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
parseAnnotation(Thread* t, Stream& s, object pool)
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
unsigned typeIndex = s.read2() - 1;
|
||||
unsigned elementCount = s.read2();
|
||||
object array = makeObjectArray(t, (elementCount * 2) + 2);
|
||||
PROTECT(t, array);
|
||||
|
||||
set(t, array, ArrayBody + BytesPerWord, singletonObject(t, pool, typeIndex));
|
||||
|
||||
for (unsigned i = 0; i < elementCount; ++i) {
|
||||
set(t, array, ArrayBody + (((i * 2) + 2) * BytesPerWord),
|
||||
singletonObject(t, pool, s.read2() - 1));
|
||||
|
||||
object value = parseAnnotationValue(t, s, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, array, ArrayBody + (((i * 2) + 3) * BytesPerWord), value);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
object
|
||||
parseAnnotationTable(Thread* t, Stream& s, object pool)
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
unsigned annotationCount = s.read2();
|
||||
object annotations = makeArray(t, annotationCount);
|
||||
PROTECT(t, annotations);
|
||||
|
||||
for (unsigned i = 0; i < annotationCount; ++i) {
|
||||
object annotation = parseAnnotation(t, s, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, annotations, ArrayBody + (i * BytesPerWord), annotation);
|
||||
}
|
||||
|
||||
return annotations;
|
||||
}
|
||||
|
||||
void
|
||||
parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
{
|
||||
@ -1038,6 +1108,9 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object staticValueTable = makeIntArray(t, count);
|
||||
PROTECT(t, staticValueTable);
|
||||
|
||||
object addendum = 0;
|
||||
PROTECT(t, addendum);
|
||||
|
||||
RUNTIME_ARRAY(uint8_t, staticTypes, count);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
@ -1059,6 +1132,11 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
value = s.read2();
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
addendum = makeFieldAddendum(t, parseAnnotationTable(t, s, pool));
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1072,6 +1150,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
0, // offset
|
||||
singletonObject(t, pool, name - 1),
|
||||
singletonObject(t, pool, spec - 1),
|
||||
addendum,
|
||||
class_);
|
||||
|
||||
if (flags & ACC_STATIC) {
|
||||
@ -1318,6 +1397,7 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap,
|
||||
0,
|
||||
methodName(t, method),
|
||||
methodSpec(t, method),
|
||||
0,
|
||||
class_,
|
||||
0,
|
||||
0);
|
||||
@ -1380,12 +1460,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object methodTable = makeArray(t, count);
|
||||
PROTECT(t, methodTable);
|
||||
|
||||
object addendum = 0;
|
||||
PROTECT(t, addendum);
|
||||
|
||||
object code = 0;
|
||||
PROTECT(t, code);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
unsigned flags = s.read2();
|
||||
unsigned name = s.read2();
|
||||
unsigned spec = s.read2();
|
||||
|
||||
object code = 0;
|
||||
code = 0;
|
||||
|
||||
unsigned attributeCount = s.read2();
|
||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
||||
object name = singletonObject(t, pool, s.read2() - 1);
|
||||
@ -1395,6 +1482,11 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
code = parseCode(t, s, pool);
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
addendum = makeMethodAddendum(t, parseAnnotationTable(t, s, pool));
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1417,6 +1509,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
0, // offset
|
||||
singletonObject(t, pool, name - 1),
|
||||
singletonObject(t, pool, spec - 1),
|
||||
addendum,
|
||||
class_,
|
||||
code);
|
||||
|
||||
@ -1493,7 +1586,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
if (classInterfaceTable(t, classSuper(t, class_))
|
||||
and arrayLength(t, classInterfaceTable(t, class_))
|
||||
== arrayLength(t, classInterfaceTable(t, classSuper(t, class_))))
|
||||
== arrayLength
|
||||
(t, classInterfaceTable(t, classSuper(t, class_))))
|
||||
{
|
||||
// inherit interface table from superclass
|
||||
set(t, class_, ClassInterfaceTable,
|
||||
@ -1541,6 +1635,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
|
||||
if (abstractVirtuals) {
|
||||
PROTECT(t, vtable);
|
||||
PROTECT(t, abstractVirtuals);
|
||||
|
||||
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
|
||||
@ -1592,7 +1687,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
(t, virtualMap, method, methodHash, methodEqual);
|
||||
assert(t, method);
|
||||
|
||||
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
||||
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1612,6 +1707,14 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1));
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
object addendum = makeClassAddendum
|
||||
(t, parseAnnotationTable(t, s, pool), 0);
|
||||
|
||||
set(t, class_, ClassAddendum, addendum);
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1702,6 +1805,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
|
||||
vtable,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
elementClass,
|
||||
loader,
|
||||
arrayLength(t, vtable));
|
||||
@ -1832,7 +1936,7 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
||||
|
||||
object class_ = t->m->processor->makeClass
|
||||
(t, 0, BootstrapFlag, fixedSize, arrayElementSize, 0, mask, 0, 0, super, 0,
|
||||
0, 0, 0, 0, t->m->loader, vtableLength);
|
||||
0, 0, 0, 0, 0, t->m->loader, vtableLength);
|
||||
|
||||
set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_);
|
||||
}
|
||||
@ -1945,7 +2049,7 @@ boot(Thread* t)
|
||||
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1);
|
||||
codeBody(t, bootCode, 0) = impdep1;
|
||||
object bootMethod = makeMethod
|
||||
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
|
||||
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
|
||||
PROTECT(t, bootMethod);
|
||||
|
||||
#include "type-java-initializations.cpp"
|
||||
@ -2084,6 +2188,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
tenuredWeakReferences(0),
|
||||
shutdownHooks(0),
|
||||
objectsToFinalize(0),
|
||||
invokeMethod(0),
|
||||
unsafe(false),
|
||||
triedBuiltinOnLoad(false),
|
||||
heapPoolIndex(0)
|
||||
@ -2824,12 +2929,13 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
|
||||
0, // object mask
|
||||
referenceName
|
||||
(t, singletonObject(t, pool, name - 1)),
|
||||
0,
|
||||
0, // source file
|
||||
0, // super
|
||||
0, // interfaces
|
||||
0, // vtable
|
||||
0, // fields
|
||||
0, // methods
|
||||
0, // addendum
|
||||
0, // static table
|
||||
loader,
|
||||
0);// vtable length
|
||||
@ -2878,6 +2984,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
|
||||
classVirtualTable(t, class_),
|
||||
classFieldTable(t, class_),
|
||||
classMethodTable(t, class_),
|
||||
classAddendum(t, class_),
|
||||
classStaticTable(t, class_),
|
||||
classLoader(t, class_),
|
||||
vtableLength);
|
||||
@ -3032,60 +3139,6 @@ resolveClass(Thread* t, object loader, object spec)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
linkClass(Thread* t, object loader, object class_)
|
||||
{
|
||||
PROTECT(t, loader);
|
||||
PROTECT(t, class_);
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
if ((classVmFlags(t, class_) & LinkFlag) == 0) {
|
||||
if (classSuper(t, class_)) {
|
||||
linkClass(t, loader, classSuper(t, class_));
|
||||
}
|
||||
|
||||
if (classInterfaceTable(t, class_)) {
|
||||
unsigned increment = 2;
|
||||
if (classFlags(t, class_) & ACC_INTERFACE) {
|
||||
increment = 1;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, classInterfaceTable(t, class_));
|
||||
i += increment)
|
||||
{
|
||||
linkClass(t, loader, arrayBody(t, classInterfaceTable(t, class_), i));
|
||||
}
|
||||
}
|
||||
|
||||
if (classMethodTable(t, class_)) {
|
||||
for (unsigned i = 0;
|
||||
i < arrayLength(t, classMethodTable(t, class_)); ++i)
|
||||
{
|
||||
object spec = methodSpec
|
||||
(t, arrayBody(t, classMethodTable(t, class_), i));
|
||||
PROTECT(t, spec);
|
||||
|
||||
for (unsigned j = 1; j < byteArrayLength(t, spec);) {
|
||||
j = resolveSpec(t, loader, spec, j);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classFieldTable(t, class_)) {
|
||||
for (unsigned i = 0; i < arrayLength(t, classFieldTable(t, class_)); ++i)
|
||||
{
|
||||
resolveSpec(t, loader, fieldSpec
|
||||
(t, arrayBody(t, classFieldTable(t, class_), i)), 0);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
}
|
||||
}
|
||||
|
||||
classVmFlags(t, class_) |= LinkFlag;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
resolveMethod(Thread* t, object class_, const char* methodName,
|
||||
const char* methodSpec)
|
||||
@ -3573,6 +3626,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
|
||||
v->visit(&(m->jniMethodTable));
|
||||
v->visit(&(m->shutdownHooks));
|
||||
v->visit(&(m->objectsToFinalize));
|
||||
v->visit(&(m->invokeMethod));
|
||||
|
||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||
::visitRoots(t, v);
|
||||
|
@ -1204,6 +1204,7 @@ class Machine {
|
||||
object tenuredWeakReferences;
|
||||
object shutdownHooks;
|
||||
object objectsToFinalize;
|
||||
object invokeMethod;
|
||||
bool unsafe;
|
||||
bool triedBuiltinOnLoad;
|
||||
JavaVMVTable javaVMVTable;
|
||||
@ -1846,6 +1847,12 @@ makeExceptionInInitializerError(Thread* t, object cause)
|
||||
return makeExceptionInInitializerError(t, 0, trace, cause, cause);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIncompatibleClassChangeError(Thread* t)
|
||||
{
|
||||
return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNew(Thread* t, object class_)
|
||||
{
|
||||
@ -2194,6 +2201,13 @@ initClass(Thread* t, object c);
|
||||
object
|
||||
makeObjectArray(Thread* t, object loader, object elementClass, unsigned count);
|
||||
|
||||
inline object
|
||||
makeObjectArray(Thread* t, unsigned count)
|
||||
{
|
||||
return makeObjectArray
|
||||
(t, t->m->loader, arrayBody(t, t->m->types, Machine::JobjectType), count);
|
||||
}
|
||||
|
||||
object
|
||||
findInTable(Thread* t, object table, object name, object spec,
|
||||
object& (*getName)(Thread*, object),
|
||||
@ -2232,6 +2246,22 @@ findVirtualMethod(Thread* t, object method, object class_)
|
||||
methodOffset(t, method));
|
||||
}
|
||||
|
||||
inline object
|
||||
findInterfaceMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
|
||||
|
||||
object interface = methodClass(t, method);
|
||||
object itable = classInterfaceTable(t, class_);
|
||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||
if (arrayBody(t, itable, i) == interface) {
|
||||
return arrayBody(t, arrayBody(t, itable, i + 1),
|
||||
methodOffset(t, method));
|
||||
}
|
||||
}
|
||||
abort(t);
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
objectArrayLength(Thread* t UNUSED, object array)
|
||||
{
|
||||
@ -2248,7 +2278,7 @@ objectArrayBody(Thread* t UNUSED, object array, unsigned index)
|
||||
assert(t, classObjectMask(t, objectClass(t, array))
|
||||
== classObjectMask(t, arrayBody
|
||||
(t, t->m->types, Machine::ArrayType)));
|
||||
return cast<object>(array, (2 + index) * BytesPerWord);
|
||||
return cast<object>(array, ArrayBody + (index * BytesPerWord));
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -59,22 +59,6 @@ isSpecialMethod(Thread* t, object method, object class_)
|
||||
void*
|
||||
resolveNativeMethod(Thread* t, object method);
|
||||
|
||||
inline object
|
||||
findInterfaceMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
|
||||
|
||||
object interface = methodClass(t, method);
|
||||
object itable = classInterfaceTable(t, class_);
|
||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||
if (arrayBody(t, itable, i) == interface) {
|
||||
return arrayBody(t, arrayBody(t, itable, i + 1),
|
||||
methodOffset(t, method));
|
||||
}
|
||||
}
|
||||
abort(t);
|
||||
}
|
||||
|
||||
inline void
|
||||
populateMultiArray(Thread* t, object array, int32_t* counts,
|
||||
unsigned index, unsigned dimensions)
|
||||
|
@ -54,6 +54,7 @@ class Processor {
|
||||
uint16_t offset,
|
||||
object name,
|
||||
object spec,
|
||||
object addendum,
|
||||
object class_,
|
||||
object code) = 0;
|
||||
|
||||
@ -72,6 +73,7 @@ class Processor {
|
||||
object virtualTable,
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object addendum,
|
||||
object staticTable,
|
||||
object loader,
|
||||
unsigned vtableLength) = 0;
|
||||
|
@ -13,10 +13,20 @@
|
||||
|
||||
(type accessibleObject java/lang/reflect/AccessibleObject)
|
||||
|
||||
(type classAddendum java/lang/Class$Addendum)
|
||||
|
||||
(type field java/lang/reflect/Field)
|
||||
|
||||
(type fieldAddendum java/lang/reflect/Field$Addendum)
|
||||
|
||||
(type method java/lang/reflect/Method)
|
||||
|
||||
(type methodAddendum java/lang/reflect/Method$Addendum)
|
||||
|
||||
(type proxy java/lang/reflect/Proxy)
|
||||
|
||||
(type pair avian/Pair)
|
||||
|
||||
(type nativeMethodData
|
||||
(void* function)
|
||||
(uint16_t argumentTableSize)
|
||||
@ -54,10 +64,6 @@
|
||||
(object name)
|
||||
(object spec))
|
||||
|
||||
(type pair
|
||||
(object first)
|
||||
(object second))
|
||||
|
||||
(type triple
|
||||
(object first)
|
||||
(object second)
|
||||
|
49
test/Annotations.java
Normal file
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