From 953cb69e5e8d32ce0cd9c5456eeaad0e3d4d9842 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Sep 2009 16:21:15 -0600 Subject: [PATCH] move proxy and annotation code from C++ to Java This allows code shrinkers to remove it if it's not used by the application. --- classpath/avian/Addendum.java | 16 + .../avian/{Pair.java => ClassAddendum.java} | 5 +- classpath/avian/Singleton.java | 17 + classpath/avian/Stream.java | 74 +++ classpath/avian/SystemClassLoader.java | 234 +++++++ classpath/java/lang/Class.java | 204 +----- classpath/java/lang/ClassLoader.java | 7 +- classpath/java/lang/reflect/Field.java | 9 +- classpath/java/lang/reflect/Method.java | 18 +- classpath/java/lang/reflect/Proxy.java | 619 +++++++++++++++++- src/builtin.cpp | 481 ++------------ src/compiler.cpp | 6 - src/machine.cpp | 134 +--- src/machine.h | 1 - src/types.def | 14 +- 15 files changed, 1056 insertions(+), 783 deletions(-) create mode 100644 classpath/avian/Addendum.java rename classpath/avian/{Pair.java => ClassAddendum.java} (83%) create mode 100644 classpath/avian/Singleton.java create mode 100644 classpath/avian/Stream.java diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java new file mode 100644 index 0000000000..80f3df6f8e --- /dev/null +++ b/classpath/avian/Addendum.java @@ -0,0 +1,16 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public class Addendum { + public Object pool; + public Object annotationTable; +} diff --git a/classpath/avian/Pair.java b/classpath/avian/ClassAddendum.java similarity index 83% rename from classpath/avian/Pair.java rename to classpath/avian/ClassAddendum.java index 028aa17f9a..6958a7a3ca 100644 --- a/classpath/avian/Pair.java +++ b/classpath/avian/ClassAddendum.java @@ -10,7 +10,6 @@ package avian; -public class Pair { - public A first; - public B second; +public class ClassAddendum extends Addendum { + public Object[] signers; } diff --git a/classpath/avian/Singleton.java b/classpath/avian/Singleton.java new file mode 100644 index 0000000000..0d29f4d00f --- /dev/null +++ b/classpath/avian/Singleton.java @@ -0,0 +1,17 @@ +/* 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 abstract class Singleton { + public static native int getInt(Object singleton, int offset); + public static native long getLong(Object singleton, int offset); + public static native Object getObject(Object singleton, int offset); +} diff --git a/classpath/avian/Stream.java b/classpath/avian/Stream.java new file mode 100644 index 0000000000..c7f54bb912 --- /dev/null +++ b/classpath/avian/Stream.java @@ -0,0 +1,74 @@ +/* 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.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.EOFException; + +public abstract class Stream { + public static void write1(OutputStream out, int v) throws IOException { + out.write(v & 0xFF); + } + + public static int read1(InputStream in) throws IOException { + return in.read(); + } + + public static void write2(OutputStream out, int v) throws IOException { + out.write((v >>> 8) & 0xFF); + out.write((v ) & 0xFF); + } + + public static int read2(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + if (b2 == -1) throw new EOFException(); + return ((b1 << 8) | (b2 & 0xFF)); + } + + public static void write4(OutputStream out, int v) throws IOException { + out.write((v >>> 24) & 0xFF); + out.write((v >>> 16) & 0xFF); + out.write((v >>> 8) & 0xFF); + out.write((v ) & 0xFF); + } + + public static int read4(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + if (b4 == -1) throw new EOFException(); + return ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + public static void write8(OutputStream out, long v) throws IOException { + write4(out, (int) (v >>> 32) & 0xFFFFFFFF); + write4(out, (int) (v ) & 0xFFFFFFFF); + } + + public static long read8(InputStream in) throws IOException { + long b1 = in.read(); + long b2 = in.read(); + long b3 = in.read(); + long b4 = in.read(); + long b5 = in.read(); + long b6 = in.read(); + long b7 = in.read(); + long b8 = in.read(); + if (b8 == -1) throw new EOFException(); + return ((b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) | + (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); + } + +} diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index e85d240a85..0703459115 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -10,10 +10,23 @@ package avian; +import static avian.Stream.read1; +import static avian.Stream.read2; + +import java.lang.reflect.Method; +import java.lang.reflect.Field; import java.net.URL; import java.net.MalformedURLException; +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; public class SystemClassLoader extends ClassLoader { + private static final int LinkFlag = 1 << 8; + + public static native Class defineClass + (ClassLoader loader, byte[] b, int offset, int length); + protected native Class findClass(String name) throws ClassNotFoundException; protected native Class findLoadedClass(String name); @@ -28,4 +41,225 @@ public class SystemClassLoader extends ClassLoader { } return null; } + + 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 parseAnnotationValue(ClassLoader loader, + Object pool, + InputStream in) + throws IOException + { + switch (read1(in)) { + case 'Z': + return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0); + + case 'B': + return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1)); + + case 'C': + return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1)); + + case 'S': + return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1)); + + case 'I': + return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1)); + + case 'F': + return Float.valueOf + (Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1))); + + case 'J': { + return Long.valueOf(Singleton.getLong(pool, read2(in) - 1)); + } + + case 'D': { + return Double.valueOf + (Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1))); + } + + case 's': { + byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1); + + return new String(data, 0, data.length - 1, false); + } + + case 'e': { + byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); + byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); + + return Enum.valueOf + (loadClass(loader, typeName, 1, typeName.length - 3), + new String(name, 0, name.length - 1, false)); + } + + case 'c':{ + byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); + + return loadClass(loader, name, 1, name.length - 3); + } + + case '@': + return parseAnnotation(loader, pool, in); + + case '[': { + Object[] array = new Object[read2(in)]; + for (int i = 0; i < array.length; ++i) { + array[i] = parseAnnotationValue(loader, pool, in); + } + return array; + } + + default: throw new AssertionError(); + } + } + + private static Object[] parseAnnotation(ClassLoader loader, + Object pool, + InputStream in) + throws IOException + { + byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); + Object[] annotation = new Object[(read2(in) + 1) * 2]; + annotation[1] = loadClass(loader, typeName, 1, typeName.length - 3); + + for (int i = 2; i < annotation.length; i += 2) { + byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); + annotation[i] = new String(name, 0, name.length - 1, false); + annotation[i + 1] = parseAnnotationValue(loader, pool, in); + } + + return annotation; + } + + private static Object[] parseAnnotationTable(ClassLoader loader, + Object pool, + InputStream in) + throws IOException + { + Object[] table = new Object[read2(in)]; + for (int i = 0; i < table.length; ++i) { + table[i] = parseAnnotation(loader, pool, in); + } + return table; + } + + private static void parseAnnotationTable(ClassLoader loader, + Addendum addendum) + { + if (addendum != null && addendum.annotationTable != null) { + try { + addendum.annotationTable = parseAnnotationTable + (loader, addendum.pool, new ByteArrayInputStream + ((byte[]) addendum.annotationTable)); + } catch (IOException e) { + AssertionError error = new AssertionError(); + error.initCause(e); + throw error; + } + + addendum.pool = null; + } + } + + 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(); + + public static void link(Class c, ClassLoader loader) { + acquireClassLock(); + try { + if ((c.vmFlags & LinkFlag) == 0) { + if (c.super_ != null) { + link(c.super_, loader); + } + + parseAnnotationTable(loader, c.addendum); + + if (c.interfaceTable != null) { + int stride = (c.isInterface() ? 1 : 2); + for (int i = 0; i < c.interfaceTable.length; i += stride) { + link((Class) c.interfaceTable[i], loader); + } + } + + if (c.methodTable != null) { + for (int i = 0; i < c.methodTable.length; ++i) { + Method m = c.methodTable[i]; + + for (int j = 1; j < m.spec.length;) { + j = resolveSpec(loader, m.spec, j); + } + + parseAnnotationTable(loader, m.addendum); + } + } + + if (c.fieldTable != null) { + for (int i = 0; i < c.fieldTable.length; ++i) { + Field f = c.fieldTable[i]; + + resolveSpec(loader, f.spec, 0); + + parseAnnotationTable(loader, f.addendum); + } + } + + c.vmFlags |= LinkFlag; + } + } finally { + releaseClassLock(); + } + } + + public static void link(Class c) { + link(c, c.getClassLoader()); + } } diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 138f272b78..77d7691094 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -11,7 +11,6 @@ package java.lang; import avian.AnnotationInvocationHandler; -import avian.Pair; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -38,22 +37,21 @@ public final class Class implements Type, GenericDeclaration, AnnotatedElement { private static final int PrimitiveFlag = 1 << 5; - private static final int LinkFlag = 1 << 8; private short flags; - private short vmFlags; + public short vmFlags; private short fixedSize; private byte arrayElementSize; private byte arrayDimensions; private int[] objectMask; private byte[] name; private byte[] sourceFile; - private Class super_; - private Object[] interfaceTable; - private Method[] virtualTable; - private Field[] fieldTable; - private Method[] methodTable; - private Addendum addendum; + public Class super_; + public Object[] interfaceTable; + public Method[] virtualTable; + public Field[] fieldTable; + public Method[] methodTable; + public avian.ClassAddendum addendum; private Object staticTable; private ClassLoader loader; @@ -149,157 +147,6 @@ public final class Class } } - 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 p = (Pair) 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()); @@ -313,7 +160,7 @@ public final class Class loader = Class.class.loader; } Class c = loader.loadClass(name); - c.link(loader); + avian.SystemClassLoader.link(c, loader); if (initialize) { c.initialize(); } @@ -378,7 +225,7 @@ public final class Class private Field findField(String name) { if (fieldTable != null) { - link(loader); + avian.SystemClassLoader.link(this); for (int i = 0; i < fieldTable.length; ++i) { if (fieldTable[i].getName().equals(name)) { @@ -423,7 +270,7 @@ public final class Class private Method findMethod(String name, Class[] parameterTypes) { if (methodTable != null) { - link(loader); + avian.SystemClassLoader.link(this); if (parameterTypes == null) { parameterTypes = new Class[0]; @@ -517,7 +364,7 @@ public final class Class public Constructor[] getDeclaredConstructors() { Constructor[] array = new Constructor[countConstructors(false)]; if (methodTable != null) { - link(loader); + avian.SystemClassLoader.link(this); int index = 0; for (int i = 0; i < methodTable.length; ++i) { @@ -533,7 +380,7 @@ public final class Class public Constructor[] getConstructors() { Constructor[] array = new Constructor[countConstructors(true)]; if (methodTable != null) { - link(loader); + avian.SystemClassLoader.link(this); int index = 0; for (int i = 0; i < methodTable.length; ++i) { @@ -573,7 +420,7 @@ public final class Class public Field[] getFields() { Field[] array = new Field[countPublicFields()]; if (fieldTable != null) { - link(loader); + avian.SystemClassLoader.link(this); int ai = 0; for (int i = 0; i < fieldTable.length; ++i) { @@ -603,7 +450,7 @@ public final class Class public Method[] getDeclaredMethods() { Method[] array = new Method[countMethods(false)]; if (methodTable != null) { - link(loader); + avian.SystemClassLoader.link(this); int ai = 0; for (int i = 0; i < methodTable.length; ++i) { @@ -619,7 +466,7 @@ public final class Class public Method[] getMethods() { Method[] array = new Method[countMethods(true)]; if (methodTable != null) { - link(loader); + avian.SystemClassLoader.link(this); int index = 0; for (int i = 0; i < methodTable.length; ++i) { @@ -636,7 +483,7 @@ public final class Class public Class[] getInterfaces() { if (interfaceTable != null) { - link(loader); + avian.SystemClassLoader.link(this); int stride = (isInterface() ? 1 : 2); Class[] array = new Class[interfaceTable.length / stride]; @@ -762,9 +609,9 @@ public final class Class public T getAnnotation(Class class_) { for (Class c = this; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { - link(c.loader); + avian.SystemClassLoader.link(c, c.loader); - Object[] table = c.addendum.annotationTable; + Object[] table = (Object[]) c.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -778,9 +625,9 @@ public final class Class public Annotation[] getDeclaredAnnotations() { if (addendum != null && addendum.annotationTable != null) { - link(loader); + avian.SystemClassLoader.link(this); - Object[] table = addendum.annotationTable; + Object[] table = (Object[]) addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); @@ -795,7 +642,7 @@ public final class Class 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; + count += ((Object[]) c.addendum.annotationTable).length; } } return count; @@ -806,7 +653,7 @@ public final class Class 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; + Object[] table = (Object[]) c.addendum.annotationTable; for (int j = 0; j < table.length; ++j) { array[i++] = getAnnotation((Object[]) table[j]); } @@ -850,14 +697,9 @@ public final class Class void setSigners(Object[] signers) { if (signers != null && signers.length > 0) { if (addendum == null) { - addendum = new Addendum(); + addendum = new avian.ClassAddendum(); } addendum.signers = signers; } } - - private static class Addendum { - public Object[] annotationTable; - public Object[] signers; - } } diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 46f9f67954..67004099e9 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -33,9 +33,6 @@ public abstract class ClassLoader { return ClassLoader.class.getClassLoader(); } - private static native Class defineClass - (ClassLoader loader, byte[] b, int offset, int length); - protected Class defineClass(String name, byte[] b, int offset, int length) { if (b == null) { throw new NullPointerException(); @@ -45,7 +42,7 @@ public abstract class ClassLoader { throw new IndexOutOfBoundsException(); } - return defineClass(this, b, offset, length); + return avian.SystemClassLoader.defineClass(this, b, offset, length); } protected Class findClass(String name) throws ClassNotFoundException { @@ -84,7 +81,7 @@ public abstract class ClassLoader { } protected void resolveClass(Class c) { - c.link(this); + avian.SystemClassLoader.link(c, this); } private ClassLoader getParent() { diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index a8e70a28e1..a660ea4b8e 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -32,7 +32,7 @@ public class Field extends AccessibleObject { private short offset; private byte[] name; public byte[] spec; - public Addendum addendum; + public avian.Addendum addendum; private Class class_; private Field() { } @@ -211,7 +211,7 @@ public class Field extends AccessibleObject { public T getAnnotation(Class class_) { if (addendum != null && addendum.annotationTable != null) { - Object[] table = addendum.annotationTable; + Object[] table = (Object[]) addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -224,7 +224,7 @@ public class Field extends AccessibleObject { public Annotation[] getAnnotations() { if (addendum != null && addendum.annotationTable != null) { - Object[] table = addendum.annotationTable; + Object[] table = (Object[]) addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); @@ -256,6 +256,7 @@ public class Field extends AccessibleObject { (Object instance, int offset, Object value); public static class Addendum { - public Object[] annotationTable; + public Object pool; + public Object annotationTable; } } diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index d9413c4700..2447f346b9 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -19,14 +19,14 @@ public class Method extends AccessibleObject { private byte vmFlags; private byte returnCode; - private byte parameterCount; - private byte parameterFootprint; + public byte parameterCount; + public byte parameterFootprint; private short flags; private short offset; private int nativeID; private byte[] name; public byte[] spec; - public Addendum addendum; + public avian.Addendum addendum; private Class class_; private Object code; private long compiled; @@ -55,6 +55,10 @@ public class Method extends AccessibleObject return new String(name, 0, name.length - 1, false); } + String getSpec() { + return new String(spec, 0, spec.length - 1, false); + } + private static int next(char c, String s, int start) { for (int i = start; i < s.length(); ++i) { if (s.charAt(i) == c) return i; @@ -158,7 +162,7 @@ public class Method extends AccessibleObject public T getAnnotation(Class class_) { if (addendum != null && addendum.annotationTable != null) { - Object[] table = addendum.annotationTable; + Object[] table = (Object[]) addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -171,7 +175,7 @@ public class Method extends AccessibleObject public Annotation[] getAnnotations() { if (addendum != null && addendum.annotationTable != null) { - Object[] table = addendum.annotationTable; + Object[] table = (Object[]) addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); @@ -209,8 +213,4 @@ public class Method extends AccessibleObject public TypeVariable>[] getTypeParameters() { throw new UnsupportedOperationException(); } - - public static class Addendum { - public Object[] annotationTable; - } } diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index 0313eafe4b..cdbb883ff7 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -10,7 +10,51 @@ package java.lang.reflect; +import static avian.Stream.write1; +import static avian.Stream.write2; +import static avian.Stream.write4; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.io.OutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + public class Proxy { + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_Class = 7; + private static final int CONSTANT_NameAndType = 12; + private static final int CONSTANT_Fieldref = 9; + private static final int CONSTANT_Methodref = 10; + + private static final int aaload = 0x32; + private static final int aastore = 0x53; + private static final int aload = 0x19; + private static final int aload_0 = 0x2a; + private static final int aload_1 = 0x2b; + private static final int anewarray = 0xbd; + private static final int areturn = 0xb0; + private static final int dload = 0x18; + private static final int dreturn = 0xaf; + private static final int dup = 0x59; + private static final int fload = 0x17; + private static final int freturn = 0xae; + private static final int getfield = 0xb4; + private static final int iload = 0x15; + private static final int invokeinterface = 0xb9; + private static final int invokestatic = 0xb8; + private static final int invokevirtual = 0xb6; + private static final int ireturn = 0xac; + private static final int ldc_w = 0x13; + private static final int lload = 0x16; + private static final int lreturn = 0xad; + private static final int pop = 0x57; + private static final int putfield = 0xb5; + private static final int return_ = 0xb1; + private static int nextNumber; protected InvocationHandler h; @@ -29,13 +73,429 @@ public class Proxy { number = nextNumber++; } - return makeClass - (loader, interfaces, ("Proxy-" + number + "\0").getBytes()); + try { + return makeClass(loader, interfaces, "Proxy-" + number); + } catch (IOException e) { + AssertionError error = new AssertionError(); + error.initCause(e); + throw error; + } } - private static native Class makeClass(ClassLoader loader, - Class[] interfaces, - byte[] name); + private static void set4(byte[] array, int offset, int v) { + array[offset ] = (byte) ((v >>> 24) & 0xFF); + array[offset + 1] = (byte) ((v >>> 16) & 0xFF); + array[offset + 2] = (byte) ((v >>> 8) & 0xFF); + array[offset + 3] = (byte) ((v ) & 0xFF); + } + + private static int poolAdd(List pool, PoolEntry e) { + int i = 0; + for (PoolEntry existing: pool) { + if (existing.equals(e)) { + return i; + } else { + ++i; + } + } + pool.add(e); + return pool.size() - 1; + } + + private static int poolAddInteger(List pool, int value) { + return poolAdd(pool, new IntegerPoolEntry(value)); + } + + private static int poolAddUtf8(List pool, String value) { + return poolAdd(pool, new Utf8PoolEntry(value)); + } + + private static int poolAddClass(List pool, String name) { + return poolAdd(pool, new ClassPoolEntry(poolAddUtf8(pool, name))); + } + + private static int poolAddNameAndType(List pool, + String name, + String type) + { + return poolAdd(pool, new NameAndTypePoolEntry + (poolAddUtf8(pool, name), + poolAddUtf8(pool, type))); + } + + private static int poolAddFieldRef(List pool, + String className, + String name, + String spec) + { + return poolAdd(pool, new FieldRefPoolEntry + (poolAddClass(pool, className), + poolAddNameAndType(pool, name, spec))); + } + + private static int poolAddMethodRef(List pool, + String className, + String name, + String spec) + { + return poolAdd(pool, new MethodRefPoolEntry + (poolAddClass(pool, className), + poolAddNameAndType(pool, name, spec))); + } + + private static byte[] makeInvokeCode(List pool, + String className, + byte[] spec, + int parameterCount, + int parameterFootprint, + int index) + throws IOException + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + write2(out, 8); // max stack + write2(out, parameterFootprint); // max locals + write4(out, 0); // length (we'll set the real value later) + + write1(out, aload_0); + write1(out, getfield); + write2(out, poolAddFieldRef + (pool, "java/lang/reflect/Proxy", + "h", "Ljava/lang/reflect/InvocationHandler;") + 1); + + write1(out, aload_0); + + write1(out, ldc_w); + write2(out, poolAddClass(pool, className) + 1); + write1(out, getfield); + write2(out, poolAddFieldRef + (pool, "java/lang/Class", + "methodTable", "[Ljava/lang/reflect/Method;") + 1); + write1(out, ldc_w); + write2(out, poolAddInteger(pool, index) + 1); + write1(out, aaload); + + write1(out, ldc_w); + write2(out, poolAddInteger(pool, parameterCount) + 1); + write1(out, anewarray); + write2(out, poolAddClass(pool, "java/lang/Object") + 1); + + int ai = 0; + int si; + for (si = 1; spec[si] != ')'; ++si) { + write1(out, dup); + + write1(out, ldc_w); + write2(out, poolAddInteger(pool, ai) + 1); + + switch (spec[si]) { + case 'L': + ++ si; + while (spec[si] != ';') ++si; + + write1(out, aload); + write1(out, ai + 1); + break; + + case '[': + ++ si; + while (spec[si] == '[') ++si; + switch (spec[si]) { + case 'L': + ++ si; + while (spec[si] != ';') ++si; + break; + + default: + break; + } + + write1(out, aload); + write1(out, ai + 1); + break; + + case 'Z': + write1(out, iload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Boolean", + "valueOf", "(Z)Ljava/lang/Boolean;") + 1); + break; + + case 'B': + write1(out, iload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Byte", + "valueOf", "(B)Ljava/lang/Byte;") + 1); + break; + + case 'S': + write1(out, iload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Short", + "valueOf", "(S)Ljava/lang/Short;") + 1); + break; + + case 'C': + write1(out, iload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Character", + "valueOf", "(C)Ljava/lang/Character;") + 1); + break; + + case 'I': + write1(out, iload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Integer", + "valueOf", "(I)Ljava/lang/Integer;") + 1); + break; + + case 'F': + write1(out, fload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Float", + "valueOf", "(F)Ljava/lang/Float;") + 1); + break; + + case 'J': + write1(out, lload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Long", + "valueOf", "(J)Ljava/lang/Long;") + 1); + ++ ai; + break; + + case 'D': + write1(out, dload); + write1(out, ai + 1); + + write1(out, invokestatic); + write2(out, poolAddMethodRef + (pool, "java/lang/Double", + "valueOf", "(D)Ljava/lang/Double;") + 1); + ++ ai; + break; + + default: throw new IllegalArgumentException(); + } + + write1(out, aastore); + + ++ ai; + } + + write1(out, invokeinterface); + write2(out, poolAddMethodRef + (pool, "java/lang/reflect/InvocationHandler", + "invoke", + "(Ljava/lang/Object;" + + "Ljava/lang/reflect/Method;" + + "[Ljava/lang/Object;)" + + "Ljava/lang/Object;") + 1); + write2(out, 0); // this will be ignored by the VM + + switch (spec[si + 1]) { + case 'L': + case '[': + write1(out, areturn); + break; + + case 'Z': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Boolean", "booleanValue", "()Z") + 1); + write1(out, ireturn); + break; + + case 'B': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Byte", "byteValue", "()B") + 1); + write1(out, ireturn); + break; + + case 'C': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Character", "charValue", "()B") + 1); + write1(out, ireturn); + break; + + case 'S': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Short", "shortValue", "()S") + 1); + write1(out, ireturn); + break; + + case 'I': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Integer", "intValue", "()I") + 1); + write1(out, ireturn); + break; + + case 'F': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Float", "floatValue", "()F") + 1); + write1(out, freturn); + break; + + case 'J': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Long", "longValue", "()J") + 1); + write1(out, lreturn); + break; + + case 'D': + write1(out, invokevirtual); + write2(out, poolAddMethodRef + (pool, "java/lang/Double", "doubleValue", "()D") + 1); + write1(out, dreturn); + break; + + case 'V': + write1(out, pop); + write1(out, return_); + break; + + default: throw new IllegalArgumentException(); + } + + write2(out, 0); // exception handler table length + write2(out, 0); // attribute count + + byte[] result = out.toByteArray(); + set4(result, 4, result.length - 12); + + return result; + } + + private static byte[] makeConstructorCode(List pool) + throws IOException + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + write2(out, 2); // max stack + write2(out, 2); // max locals + write4(out, 6); // length + + write1(out, aload_0); + write1(out, aload_1); + write1(out, putfield); + write2(out, poolAddFieldRef + (pool, "java/lang/reflect/Proxy", + "h", "Ljava/lang/reflect/InvocationHandler;") + 1); + write1(out, return_); + + write2(out, 0); // exception handler table length + write2(out, 0); // attribute count + + return out.toByteArray(); + } + + private static Class makeClass(ClassLoader loader, + Class[] interfaces, + String name) + throws IOException + { + List pool = new ArrayList(); + + int[] interfaceIndexes = new int[interfaces.length]; + for (int i = 0; i < interfaces.length; ++i) { + interfaceIndexes[i] = poolAddClass(pool, interfaces[i].getName()); + } + + Map virtualMap = new HashMap(); + for (Class c: interfaces) { + Method[] ivtable = c.virtualTable; + if (ivtable != null) { + for (Method m: ivtable) { + virtualMap.put(m.getName() + m.getSpec(), m); + } + } + } + + MethodData[] methodTable = new MethodData[virtualMap.size() + 1]; + { int i = 0; + for (Method m: virtualMap.values()) { + methodTable[i] = new MethodData + (poolAddUtf8(pool, m.getName()), + poolAddUtf8(pool, m.getSpec()), + makeInvokeCode(pool, name, m.spec, m.parameterCount, + m.parameterFootprint, i)); + ++ i; + } + + methodTable[i++] = new MethodData + (poolAddUtf8(pool, ""), + poolAddUtf8(pool, "(Ljava/lang/reflect/InvocationHandler;)V"), + makeConstructorCode(pool)); + } + + int nameIndex = poolAddClass(pool, name); + int superIndex = poolAddClass(pool, "java/lang/reflect/Proxy"); + int codeAttributeNameIndex = poolAddUtf8(pool, "Code"); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + write4(out, 0xCAFEBABE); + write2(out, 0); // minor version + write2(out, 0); // major version + + write2(out, pool.size() + 1); + for (PoolEntry e: pool) { + e.writeTo(out); + } + + write2(out, 0); // flags + write2(out, nameIndex + 1); + write2(out, superIndex + 1); + + write2(out, interfaces.length); + for (int i: interfaceIndexes) { + write2(out, i + 1); + } + + write2(out, 0); // field count + + write2(out, methodTable.length); + for (MethodData m: methodTable) { + write2(out, 0); // flags + write2(out, m.nameIndex + 1); + write2(out, m.specIndex + 1); + + write2(out, 1); // attribute count + write2(out, codeAttributeNameIndex + 1); + write4(out, m.code.length); + out.write(m.code); + } + + write2(out, 0); // attribute count + + byte[] classData = out.toByteArray(); + return avian.SystemClassLoader.defineClass + (loader, classData, 0, classData.length); + } public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, @@ -51,4 +511,153 @@ public class Proxy { throw error; } } + + private static class MethodData { + public final int nameIndex; + public final int specIndex; + public final byte[] code; + + public MethodData(int nameIndex, int specIndex, byte[] code) { + this.nameIndex = nameIndex; + this.specIndex = specIndex; + this.code = code; + } + } + + public interface PoolEntry { + public void writeTo(OutputStream out) throws IOException; + } + + public static class IntegerPoolEntry implements PoolEntry { + private final int value; + + public IntegerPoolEntry(int value) { + this.value = value; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Integer); + write4(out, value); + } + + public boolean equals(Object o) { + return o instanceof IntegerPoolEntry + && ((IntegerPoolEntry) o).value == value; + } + } + + public static class Utf8PoolEntry implements PoolEntry { + private final String data; + + public Utf8PoolEntry(String data) { + this.data = data; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Utf8); + byte[] bytes = data.getBytes(); + write2(out, bytes.length); + out.write(bytes); + } + + public boolean equals(Object o) { + return o instanceof Utf8PoolEntry + && ((Utf8PoolEntry) o).data.equals(data); + } + } + + public static class ClassPoolEntry implements PoolEntry { + private final int nameIndex; + + public ClassPoolEntry(int nameIndex) { + this.nameIndex = nameIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Class); + write2(out, nameIndex + 1); + } + + public boolean equals(Object o) { + return o instanceof ClassPoolEntry + && ((ClassPoolEntry) o).nameIndex == nameIndex; + } + } + + public static class NameAndTypePoolEntry implements PoolEntry { + private final int nameIndex; + private final int typeIndex; + + public NameAndTypePoolEntry(int nameIndex, int typeIndex) { + this.nameIndex = nameIndex; + this.typeIndex = typeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_NameAndType); + write2(out, nameIndex + 1); + write2(out, typeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof NameAndTypePoolEntry) { + NameAndTypePoolEntry other = (NameAndTypePoolEntry) o; + return other.nameIndex == nameIndex && other.typeIndex == typeIndex; + } else { + return false; + } + } + } + + public static class FieldRefPoolEntry implements PoolEntry { + private final int classIndex; + private final int nameAndTypeIndex; + + public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Fieldref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof FieldRefPoolEntry) { + FieldRefPoolEntry other = (FieldRefPoolEntry) o; + return other.classIndex == classIndex + && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } + + public static class MethodRefPoolEntry implements PoolEntry { + private final int classIndex; + private final int nameAndTypeIndex; + + public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Methodref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof MethodRefPoolEntry) { + MethodRefPoolEntry other = (MethodRefPoolEntry) o; + return other.classIndex == classIndex + && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } } diff --git a/src/builtin.cpp b/src/builtin.cpp index 0665a40be2..9861371d75 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -79,242 +79,6 @@ runOnLoadIfFound(Thread* t, System::Library* library) } } -void JNICALL -proxyConstruct(Thread* t, object, uintptr_t* arguments) -{ - set(t, reinterpret_cast(arguments[0]), ProxyH, - reinterpret_cast(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 - (&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(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 - (&byteArrayBody(t, methodSpec(t, method), 0))); - it.hasNext();) - { - object a; - unsigned size; - switch (*it.next()) { - case 'L': - case '[': - a = reinterpret_cast(arguments[ai]); - size = 1; - break; - - case 'Z': - a = makeBoolean(t, static_cast(arguments[ai])); - size = 1; - break; - - case 'B': - a = makeByte(t, static_cast(arguments[ai])); - size = 1; - break; - - case 'S': - a = makeShort(t, static_cast(arguments[ai])); - size = 1; - break; - - case 'C': - a = makeChar(t, static_cast(arguments[ai])); - size = 1; - break; - - case 'I': - a = makeInt(t, static_cast(arguments[ai])); - size = 1; - break; - - case 'F': - a = makeFloat(t, bitsToFloat(static_cast(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(arguments[0])))); - PROTECT(t, invoke); - - object result = t->m->processor->invoke - (t, invoke, proxyH(t, reinterpret_cast(arguments[0])), - reinterpret_cast(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(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 @@ -404,8 +168,22 @@ Avian_java_lang_Object_clone return reinterpret_cast(clone); } +extern "C" JNIEXPORT void JNICALL +Avian_avian_SystemClassLoader_acquireClassLock +(Thread* t, object) +{ + acquire(t, t->m->classLock); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_SystemClassLoader_releaseClassLock +(Thread* t, object) +{ + release(t, t->m->classLock); +} + extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_ClassLoader_defineClass +Avian_avian_SystemClassLoader_defineClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); @@ -527,20 +305,6 @@ Avian_java_lang_Class_initialize initClass(t, this_); } -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Class_acquireClassLock -(Thread* t, object) -{ - acquire(t, t->m->classLock); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Class_releaseClassLock -(Thread* t, object) -{ - release(t, t->m->classLock); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Class_isAssignableFrom (Thread* t, object, uintptr_t* arguments) @@ -729,195 +493,6 @@ 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(arguments[0]); - PROTECT(t, loader); - - object interfaces = allInterfaces(t, reinterpret_cast(arguments[1])); - PROTECT(t, interfaces); - - object name = reinterpret_cast(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(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 "" - 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(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(c); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Float_floatToRawIntBits (Thread*, object, uintptr_t* arguments) @@ -1469,3 +1044,29 @@ Avian_avian_Continuations_00024Continuation_handleException abort(t); } + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Singleton_getObject +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (singletonObject(t, reinterpret_cast(arguments[0]), arguments[1])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Singleton_getInt +(Thread* t, object, uintptr_t* arguments) +{ + return singletonValue + (t, reinterpret_cast(arguments[0]), arguments[1]); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Singleton_getLong +(Thread* t, object, uintptr_t* arguments) +{ + int64_t v; + memcpy(&singletonValue + (t, reinterpret_cast(arguments[0]), arguments[1]), &v, 8); + return v; +} diff --git a/src/compiler.cpp b/src/compiler.cpp index 15a82a12f8..30441bfa07 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -134,12 +134,6 @@ class Site { Site* next; }; -class SitePair { - public: - Site* low; - Site* high; -}; - class Stack { public: Stack(unsigned index, Value* value, Stack* next): diff --git a/src/machine.cpp b/src/machine.cpp index 1886715942..3929d853b1 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -970,122 +970,6 @@ 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) { @@ -1136,7 +1020,10 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { - addendum = makeFieldAddendum(t, parseAnnotationTable(t, s, pool)); + object body = makeByteArray(t, length); + s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), + length); + addendum = makeAddendum(t, pool, body); } else { s.skip(length); } @@ -1486,7 +1373,10 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { - addendum = makeMethodAddendum(t, parseAnnotationTable(t, s, pool)); + object body = makeByteArray(t, length); + s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), + length); + addendum = makeAddendum(t, pool, body); } else { s.skip(length); } @@ -1711,8 +1601,10 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { - object addendum = makeClassAddendum - (t, parseAnnotationTable(t, s, pool), 0); + object body = makeByteArray(t, length); + s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); + + object addendum = makeClassAddendum(t, pool, body, 0); set(t, class_, ClassAddendum, addendum); } else { @@ -2189,7 +2081,6 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, tenuredWeakReferences(0), shutdownHooks(0), objectsToFinalize(0), - invokeMethod(0), unsafe(false), triedBuiltinOnLoad(false), heapPoolIndex(0) @@ -3627,7 +3518,6 @@ 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); diff --git a/src/machine.h b/src/machine.h index ebdee216a7..125198745b 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1204,7 +1204,6 @@ class Machine { object tenuredWeakReferences; object shutdownHooks; object objectsToFinalize; - object invokeMethod; bool unsafe; bool triedBuiltinOnLoad; JavaVMVTable javaVMVTable; diff --git a/src/types.def b/src/types.def index 1050486aa8..9a704c3b91 100644 --- a/src/types.def +++ b/src/types.def @@ -13,19 +13,15 @@ (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 addendum avian/Addendum) + +(type classAddendum avian/ClassAddendum) (type nativeMethodData (void* function) @@ -111,6 +107,10 @@ (type array (noassert array object body)) +(type pair + (object first) + (object second)) + (type continuationContext (object next) (object before)