diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java index 80f3df6f8e..248ee68ec1 100644 --- a/classpath/avian/Addendum.java +++ b/classpath/avian/Addendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -12,5 +12,5 @@ package avian; public class Addendum { public Object pool; - public Object annotationTable; + public Object annotationTable; } diff --git a/classpath/avian/Assembler.java b/classpath/avian/Assembler.java new file mode 100644 index 0000000000..3e1eae271b --- /dev/null +++ b/classpath/avian/Assembler.java @@ -0,0 +1,116 @@ +/* Copyright (c) 2011, 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 static avian.Stream.write1; +import static avian.Stream.write2; +import static avian.Stream.write4; + +import avian.ConstantPool.PoolEntry; + +import java.util.List; +import java.io.OutputStream; +import java.io.IOException; + +public class Assembler { + public static final int ACC_PUBLIC = 1 << 0; + public static final int ACC_STATIC = 1 << 3; + + public static final int aaload = 0x32; + public static final int aastore = 0x53; + public static final int aload = 0x19; + public static final int aload_0 = 0x2a; + public static final int aload_1 = 0x2b; + public static final int astore_0 = 0x4b; + public static final int anewarray = 0xbd; + public static final int areturn = 0xb0; + public static final int dload = 0x18; + public static final int dreturn = 0xaf; + public static final int dup = 0x59; + public static final int fload = 0x17; + public static final int freturn = 0xae; + public static final int getfield = 0xb4; + public static final int goto_ = 0xa7; + public static final int iload = 0x15; + public static final int invokeinterface = 0xb9; + public static final int invokespecial = 0xb7; + public static final int invokestatic = 0xb8; + public static final int invokevirtual = 0xb6; + public static final int ireturn = 0xac; + public static final int jsr = 0xa8; + public static final int ldc_w = 0x13; + public static final int lload = 0x16; + public static final int lreturn = 0xad; + public static final int new_ = 0xbb; + public static final int pop = 0x57; + public static final int putfield = 0xb5; + public static final int ret = 0xa9; + public static final int return_ = 0xb1; + + public static void writeClass(OutputStream out, + List pool, + int name, + int super_, + int[] interfaces, + MethodData[] methods) + throws IOException + { + int codeAttributeName = ConstantPool.addUtf8(pool, "Code"); + + 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, ACC_PUBLIC); // flags + write2(out, name + 1); + write2(out, super_ + 1); + + write2(out, interfaces.length); + for (int i: interfaces) { + write2(out, i + 1); + } + + write2(out, 0); // field count + + write2(out, methods.length); + for (MethodData m: methods) { + write2(out, m.flags); + write2(out, m.nameIndex + 1); + write2(out, m.specIndex + 1); + + write2(out, 1); // attribute count + write2(out, codeAttributeName + 1); + write4(out, m.code.length); + out.write(m.code); + } + + write2(out, 0); // attribute count + } + + public static class MethodData { + public final int flags; + public final int nameIndex; + public final int specIndex; + public final byte[] code; + + public MethodData(int flags, int nameIndex, int specIndex, byte[] code) { + this.flags = flags; + this.nameIndex = nameIndex; + this.specIndex = specIndex; + this.code = code; + } + } +} diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index 6958a7a3ca..4382e7f717 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,6 +10,4 @@ package avian; -public class ClassAddendum extends Addendum { - public Object[] signers; -} +public class ClassAddendum extends Addendum { } diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java new file mode 100644 index 0000000000..3e18f4c0df --- /dev/null +++ b/classpath/avian/Classes.java @@ -0,0 +1,270 @@ +/* Copyright (c) 2010, 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 static avian.Stream.read1; +import static avian.Stream.read2; + +import java.lang.reflect.Modifier; +import java.lang.reflect.Method; +import java.lang.reflect.Field; +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public class Classes { + private static final int LinkFlag = 1 << 8; + + public static native VMClass defineVMClass + (ClassLoader loader, byte[] b, int offset, int length); + + public static native VMClass vmClass(Object o); + + public static native VMClass primitiveClass(char name); + + public static native void initialize(VMClass vmClass); + + public static native boolean isAssignableFrom(VMClass a, VMClass b); + + public static native VMClass getVMClass(Object o); + + private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) + throws ClassNotFoundException; + + private static VMClass loadVMClass(ClassLoader loader, + byte[] nameBytes, int offset, int length) + { + byte[] spec = new byte[length + 1]; + System.arraycopy(nameBytes, offset, spec, 0, length); + + try { + VMClass c = resolveVMClass(loader, spec); + if (c == null) { + throw new NoClassDefFoundError(); + } + return c; + } catch (ClassNotFoundException e) { + NoClassDefFoundError error = new NoClassDefFoundError + (new String(nameBytes, offset, length, false)); + 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 + (SystemClassLoader.getClass + (loadVMClass(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 SystemClassLoader.getClass + (loadVMClass(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] = SystemClassLoader.getClass + (loadVMClass(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 instanceof byte[]) { + try { + addendum.annotationTable = parseAnnotationTable + (loader, addendum.pool, new ByteArrayInputStream + ((byte[]) addendum.annotationTable)); + } catch (IOException e) { + AssertionError error = new AssertionError(); + error.initCause(e); + throw error; + } + } + } + + 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; + } + + loadVMClass(loader, spec, start, end - start); + + return result; + } + + public static void link(VMClass 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.flags & Modifier.INTERFACE) != 0 ? 1 : 2); + for (int i = 0; i < c.interfaceTable.length; i += stride) { + link((VMClass) c.interfaceTable[i], loader); + } + } + + if (c.methodTable != null) { + for (int i = 0; i < c.methodTable.length; ++i) { + VMMethod 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) { + VMField f = c.fieldTable[i]; + + resolveSpec(loader, f.spec, 0); + + parseAnnotationTable(loader, f.addendum); + } + } + + c.vmFlags |= LinkFlag; + } + } finally { + releaseClassLock(); + } + } + + public static void link(VMClass c) { + link(c, c.loader); + } + + private static native void acquireClassLock(); + + private static native void releaseClassLock(); +} diff --git a/classpath/avian/ConstantPool.java b/classpath/avian/ConstantPool.java new file mode 100644 index 0000000000..3a1e273c24 --- /dev/null +++ b/classpath/avian/ConstantPool.java @@ -0,0 +1,242 @@ +/* Copyright (c) 2011, 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 static avian.Stream.write1; +import static avian.Stream.write2; +import static avian.Stream.write4; + +import java.util.List; +import java.io.OutputStream; +import java.io.IOException; + +public class ConstantPool { + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_String = 8; + 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; + + public static int add(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; + } + + public static int addInteger(List pool, int value) { + return add(pool, new IntegerPoolEntry(value)); + } + + public static int addUtf8(List pool, String value) { + return add(pool, new Utf8PoolEntry(value)); + } + + public static int addString(List pool, String value) { + return add(pool, new StringPoolEntry(addUtf8(pool, value))); + } + + public static int addClass(List pool, String name) { + return add(pool, new ClassPoolEntry(addUtf8(pool, name))); + } + + public static int addNameAndType(List pool, + String name, + String type) + { + return add(pool, new NameAndTypePoolEntry + (addUtf8(pool, name), + addUtf8(pool, type))); + } + + public static int addFieldRef(List pool, + String className, + String name, + String spec) + { + return add(pool, new FieldRefPoolEntry + (addClass(pool, className), + addNameAndType(pool, name, spec))); + } + + public static int addMethodRef(List pool, + String className, + String name, + String spec) + { + return add(pool, new MethodRefPoolEntry + (addClass(pool, className), + addNameAndType(pool, name, spec))); + } + + public interface PoolEntry { + public void writeTo(OutputStream out) throws IOException; + } + + private 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; + } + } + + private 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); + } + } + + private static class StringPoolEntry implements PoolEntry { + private final int valueIndex; + + public StringPoolEntry(int valueIndex) { + this.valueIndex = valueIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_String); + write2(out, valueIndex + 1); + } + + public boolean equals(Object o) { + return o instanceof StringPoolEntry + && ((StringPoolEntry) o).valueIndex == valueIndex; + } + } + + private 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; + } + } + + private 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; + } + } + } + + private 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; + } + } + } + + private 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/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index ecec10b348..387ebd31ac 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -53,8 +53,8 @@ import java.util.concurrent.Callable; * causes the current continuation to be replaced with the calling * continuation. When the last method in this new continuation * returns, it returns to the native frame which created the current - * context, which may not be the same as the context in which that - * continuation was created. + * context, which may or may not be the same as the context in which + * that continuation was created. * *

We define the return type of a continuation context as the * return type of the first method called in that context. A @@ -128,7 +128,7 @@ public class Continuations { * receiver.receive(Callback), propagate the exception * thrown by that method, return the result passed to the * handleResult(T) method of the continuation, or throw the - * exception passed to the handleException(Throwable) of the + * exception passed to the handleException(Throwable) method of the * continuation. */ public static native T callWithCurrentContinuation diff --git a/classpath/avian/FieldAddendum.java b/classpath/avian/FieldAddendum.java new file mode 100644 index 0000000000..5e97e8a95b --- /dev/null +++ b/classpath/avian/FieldAddendum.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2010, 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 FieldAddendum extends Addendum { } diff --git a/classpath/java/lang/reflect/GenericDeclaration.java b/classpath/avian/MethodAddendum.java similarity index 66% rename from classpath/java/lang/reflect/GenericDeclaration.java rename to classpath/avian/MethodAddendum.java index 61914661bb..a2e40a5261 100644 --- a/classpath/java/lang/reflect/GenericDeclaration.java +++ b/classpath/avian/MethodAddendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,8 +8,8 @@ There is NO WARRANTY for this software. See license.txt for details. */ -package java.lang.reflect; +package avian; -public interface GenericDeclaration { - public TypeVariable[] getTypeParameters(); +public class MethodAddendum extends Addendum { + public Object exceptionTable; } diff --git a/classpath/avian/OpenJDK.java b/classpath/avian/OpenJDK.java new file mode 100644 index 0000000000..877a7c2289 --- /dev/null +++ b/classpath/avian/OpenJDK.java @@ -0,0 +1,23 @@ +/* Copyright (c) 2010, 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.security.AllPermission; +import java.security.Permissions; +import java.security.ProtectionDomain; + +public class OpenJDK { + public static ProtectionDomain getProtectionDomain() { + Permissions p = new Permissions(); + p.add(new AllPermission()); + return new ProtectionDomain(null, p); + } +} diff --git a/classpath/avian/PersistentSet.java b/classpath/avian/PersistentSet.java index c5efdad641..5683327aee 100644 --- a/classpath/avian/PersistentSet.java +++ b/classpath/avian/PersistentSet.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/Stream.java b/classpath/avian/Stream.java index c7f54bb912..14e6fc5773 100644 --- a/classpath/avian/Stream.java +++ b/classpath/avian/Stream.java @@ -71,4 +71,10 @@ public abstract class Stream { (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); } + public 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); + } } diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 2257a9b66e..6edd8b7a68 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,32 +10,32 @@ 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; +import java.util.Collection; +import java.util.Collections; +import java.util.ArrayList; +import java.util.Enumeration; public class SystemClassLoader extends ClassLoader { - private static final int LinkFlag = 1 << 8; + private native VMClass findVMClass(String name) + throws ClassNotFoundException; - public static native Class defineClass - (ClassLoader loader, byte[] b, int offset, int length); + protected Class findClass(String name) throws ClassNotFoundException { + return getClass(findVMClass(name)); + } - protected native Class findClass(String name) throws ClassNotFoundException; + public static native Class getClass(VMClass vmClass); - protected native Class reallyFindLoadedClass(String name); + private native VMClass findLoadedVMClass(String name); + + protected Class reallyFindLoadedClass(String name){ + VMClass c = findLoadedVMClass(name); + return c == null ? null : getClass(c); + } private native boolean resourceExists(String name); - private static native Class resolveClass(ClassLoader loader, byte[] spec) - throws ClassNotFoundException; - protected URL findResource(String name) { if (resourceExists(name)) { try { @@ -45,231 +45,12 @@ public class SystemClassLoader extends ClassLoader { return null; } - private static Class loadClass(ClassLoader loader, - byte[] nameBytes, int offset, int length) - { - byte[] spec = new byte[length + 1]; - System.arraycopy(nameBytes, offset, spec, 0, length); - - try { - Class c = resolveClass(loader, spec); - if (c == null) { - throw new NoClassDefFoundError(); - } - return c; - } catch (ClassNotFoundException e) { - NoClassDefFoundError error = new NoClassDefFoundError - (new String(nameBytes, offset, length, false)); - error.initCause(e); - throw error; + protected Enumeration findResources(String name) { + Collection urls = new ArrayList(1); + URL url = findResource(name); + if (url != null) { + urls.add(url); } - } - - 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 instanceof byte[]) { - 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()); + return Collections.enumeration(urls); } } diff --git a/classpath/avian/VMClass.java b/classpath/avian/VMClass.java new file mode 100644 index 0000000000..b32ff7f689 --- /dev/null +++ b/classpath/avian/VMClass.java @@ -0,0 +1,31 @@ +/* Copyright (c) 2008-2010, 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 VMClass { + public short flags; + public short vmFlags; + public short fixedSize; + public byte arrayElementSize; + public byte arrayDimensions; + public int runtimeDataIndex; + public int[] objectMask; + public byte[] name; + public byte[] sourceFile; + public VMClass super_; + public Object[] interfaceTable; + public VMMethod[] virtualTable; + public VMField[] fieldTable; + public VMMethod[] methodTable; + public avian.ClassAddendum addendum; + public Object staticTable; + public ClassLoader loader; +} diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java new file mode 100644 index 0000000000..699a68e5f8 --- /dev/null +++ b/classpath/avian/VMField.java @@ -0,0 +1,22 @@ +/* Copyright (c) 2008-2010, 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 VMField { + public byte vmFlags; + public byte code; + public short flags; + public short offset; + public byte[] name; + public byte[] spec; + public FieldAddendum addendum; + public VMClass class_; +} diff --git a/classpath/avian/VMMethod.java b/classpath/avian/VMMethod.java new file mode 100644 index 0000000000..e68d725242 --- /dev/null +++ b/classpath/avian/VMMethod.java @@ -0,0 +1,27 @@ +/* Copyright (c) 2008-2010, 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 VMMethod { + public byte vmFlags; + public byte returnCode; + public byte parameterCount; + public byte parameterFootprint; + public short flags; + public short offset; + public int nativeID; + public int runtimeDataIndex; + public byte[] name; + public byte[] spec; + public MethodAddendum addendum; + public VMClass class_; + public Object code; +} diff --git a/classpath/avian/resource/Handler.java b/classpath/avian/resource/Handler.java index a10e575a85..51e8d1a838 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/resource/Handler.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -34,6 +34,10 @@ public class Handler extends URLStreamHandler { public InputStream getInputStream() throws IOException { return new ResourceInputStream(url.getFile()); } + + public void connect() { + // ignore + } } private static class ResourceInputStream extends InputStream { @@ -59,6 +63,12 @@ public class Handler extends URLStreamHandler { public static native void close(long peer) throws IOException; + public static native int available(long peer, int position); + + public int available() { + return available(peer, position); + } + public int read() throws IOException { if (peer != 0) { int c = read(peer, position); diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 22880146ac..abc7684634 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -25,6 +25,7 @@ # include # include +# define ACCESS _waccess # define CLOSE _close # define READ _read # define WRITE _write @@ -36,10 +37,12 @@ # define OPEN_MASK O_BINARY # ifdef _MSC_VER -# define S_ISREG(x) ((x) | _S_IFREG) -# define S_ISDIR(x) ((x) | _S_IFDIR) +# define S_ISREG(x) ((x) & _S_IFREG) +# define S_ISDIR(x) ((x) & _S_IFDIR) # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE +# define W_OK 2 +# define R_OK 4 # else # define OPEN _wopen # define CREAT _wcreat @@ -56,6 +59,7 @@ typedef wchar_t char_t; # include # include "sys/mman.h" +# define ACCESS access # define OPEN open # define CLOSE close # define READ read @@ -323,13 +327,13 @@ Java_java_io_File_length(JNIEnv* e, jclass, jstring path) if (chars) { STRUCT_STAT s; int r = STAT(chars, &s); + releaseChars(e, path, chars); if (r == 0) { return s.st_size; } - releaseChars(e, path, chars); } - return -1; + return 0; } extern "C" JNIEXPORT void JNICALL @@ -377,6 +381,31 @@ Java_java_io_File_delete(JNIEnv* e, jclass, jstring path) } } +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canRead(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = ACCESS(chars, R_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = ACCESS(chars, W_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + + extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_rename(JNIEnv* e, jclass, jstring old, jstring new_) { @@ -593,11 +622,13 @@ Java_java_io_FileInputStream_close(JNIEnv* e, jclass, jint fd) } extern "C" JNIEXPORT jint JNICALL -Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path) +Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path, jboolean append) { string_t chars = getChars(e, path); if (chars) { - int fd = doOpen(e, chars, O_WRONLY | O_CREAT | O_TRUNC); + int fd = doOpen(e, chars, append + ? (O_WRONLY | O_CREAT | O_APPEND) + : (O_WRONLY | O_CREAT | O_TRUNC)); releaseChars(e, path, chars); return fd; } else { diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 59f7acc8da..48fdacc01a 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -11,7 +11,6 @@ #include "math.h" #include "stdlib.h" #include "time.h" -#include "time.h" #include "string.h" #include "stdio.h" #include "jni.h" @@ -37,9 +36,6 @@ # define isnan _isnan # define isfinite _finite # define strtof strtod -# define FTIME _ftime_s -# else -# define FTIME _ftime # endif #else // not PLATFORM_WINDOWS @@ -224,17 +220,17 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, SetHandleInformation(in[0], HANDLE_FLAG_INHERIT, 0); jlong inDescriptor = static_cast(descriptor(e, in[0])); if(e->ExceptionCheck()) return; - e->SetLongArrayRegion(process, 1, 1, &inDescriptor); + e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); SetHandleInformation(out[1], HANDLE_FLAG_INHERIT, 0); jlong outDescriptor = static_cast(descriptor(e, out[1])); if(e->ExceptionCheck()) return; - e->SetLongArrayRegion(process, 2, 1, &outDescriptor); + e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); SetHandleInformation(err[0], HANDLE_FLAG_INHERIT, 0); jlong errDescriptor = static_cast(descriptor(e, err[0])); if(e->ExceptionCheck()) return; - e->SetLongArrayRegion(process, 3, 1, &errDescriptor); + e->SetLongArrayRegion(process, 4, 1, &errDescriptor); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); @@ -250,6 +246,10 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, BOOL success = CreateProcess(0, (LPSTR) RUNTIME_ARRAY_BODY(line), 0, 0, 1, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, 0, 0, &si, &pi); + + CloseHandle(in[1]); + CloseHandle(out[0]); + CloseHandle(err[1]); if (not success) { throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); @@ -258,24 +258,12 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jlong pid = reinterpret_cast(pi.hProcess); e->SetLongArrayRegion(process, 0, 1, &pid); - + jlong tid = reinterpret_cast(pi.hThread); + e->SetLongArrayRegion(process, 1, 1, &tid); } extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_exitValue(JNIEnv* e, jclass, jlong pid) -{ - DWORD exitCode; - BOOL success = GetExitCodeProcess(reinterpret_cast(pid), &exitCode); - if(not success){ - throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); - } else if(exitCode == STILL_ACTIVE){ - throwNew(e, "java/lang/IllegalThreadStateException", "Process is still active"); - } - return exitCode; -} - -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) +Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid) { DWORD exitCode; WaitForSingleObject(reinterpret_cast(pid), INFINITE); @@ -283,6 +271,10 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) if(not success){ throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); } + + CloseHandle(reinterpret_cast(pid)); + CloseHandle(reinterpret_cast(tid)); + return exitCode; } @@ -366,7 +358,8 @@ extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { - char** argv = static_cast(malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); + char** argv = static_cast + (malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); int i; for(i = 0; i < e->GetArrayLength(command); i++){ jstring element = (jstring) e->GetObjectArrayElement(command, i); @@ -383,15 +376,15 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, makePipe(e, in); if(e->ExceptionCheck()) return; jlong inDescriptor = static_cast(in[0]); - e->SetLongArrayRegion(process, 1, 1, &inDescriptor); + e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); if(e->ExceptionCheck()) return; jlong outDescriptor = static_cast(out[1]); - e->SetLongArrayRegion(process, 1, 1, &outDescriptor); + e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); if(e->ExceptionCheck()) return; jlong errDescriptor = static_cast(err[0]); - e->SetLongArrayRegion(process, 1, 1, &errDescriptor); + e->SetLongArrayRegion(process, 4, 1, &errDescriptor); makePipe(e, msg); if(e->ExceptionCheck()) return; if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { @@ -452,21 +445,7 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, } extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_exitValue(JNIEnv* e, jclass, jlong pid) -{ - int status; - pid_t returned = waitpid(pid, &status, WNOHANG); - if(returned == 0){ - throwNewErrno(e, "java/lang/IllegalThreadStateException"); - } else if(returned == -1){ - throwNewErrno(e, "java/lang/Exception"); - } - - return WEXITSTATUS(status); -} - -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) +Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid, jlong) { bool finished = false; int status; @@ -548,6 +527,10 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, TCHAR buffer[MAX_PATH]; GetTempPath(MAX_PATH, buffer); r = e->NewStringUTF(buffer); + } else if (strcmp(chars, "user.dir") == 0) { + TCHAR buffer[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, buffer); + r = e->NewStringUTF(buffer); } else if (strcmp(chars, "user.home") == 0) { # ifdef _MSC_VER WCHAR buffer[MAX_PATH]; @@ -606,6 +589,8 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, #endif } else if (strcmp(chars, "java.io.tmpdir") == 0) { r = e->NewStringUTF("/tmp"); + } else if (strcmp(chars, "user.dir") == 0) { + r = e->NewStringUTF(getenv("PWD")); } else if (strcmp(chars, "user.home") == 0) { r = e->NewStringUTF(getenv("HOME")); } @@ -633,9 +618,13 @@ extern "C" JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis(JNIEnv*, jclass) { #ifdef PLATFORM_WINDOWS - _timeb tb; - FTIME(&tb); - return (static_cast(tb.time) * 1000) + static_cast(tb.millitm); + // We used to use _ftime here, but that only gives us 1-second + // resolution on Windows 7. _ftime_s might work better, but MinGW + // doesn't have it as of this writing. So we use this mess instead: + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((static_cast(time.dwHighDateTime) << 32) + | time.dwLowDateTime) / 10000) - 11644473600000LL; #else timeval tv = { 0, 0 }; gettimeofday(&tv, 0); diff --git a/classpath/java-net.cpp b/classpath/java-net.cpp index bd94f3e52c..20d853adc2 100644 --- a/classpath/java-net.cpp +++ b/classpath/java-net.cpp @@ -29,6 +29,8 @@ Java_java_net_Socket_init(JNIEnv* ONLY_ON_WINDOWS(e), jclass) int r = WSAStartup(MAKEWORD(2, 2), &data); if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { throwNew(e, "java/io/IOException", "WSAStartup failed"); + } else { + wsaInitialized = true; } } #endif diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 25d2d673b0..9a7656db91 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -279,7 +279,7 @@ doListen(JNIEnv* e, int s, sockaddr_in* address) } } -bool +void doFinishConnect(JNIEnv* e, int socket) { int error; @@ -289,12 +289,9 @@ doFinishConnect(JNIEnv* e, int socket) if (r != 0 or size != sizeof(int)) { throwIOException(e); - } else if (einProgress(error)) { - return false; - } else if (error != 0) { + } else if (error and not einProgress(error)) { throwIOException(e, socketErrorString(e, error)); } - return true; } bool @@ -426,12 +423,12 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e, return s; } -extern "C" JNIEXPORT jboolean JNICALL +extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e, jclass, jint socket) { - return doFinishConnect(e, socket); + doFinishConnect(e, socket); } extern "C" JNIEXPORT jint JNICALL diff --git a/classpath/java/io/BufferedInputStream.java b/classpath/java/io/BufferedInputStream.java index b1bdec24a0..67ac256a21 100644 --- a/classpath/java/io/BufferedInputStream.java +++ b/classpath/java/io/BufferedInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -58,14 +58,21 @@ public class BufferedInputStream extends InputStream { length -= remaining; } - if (length > 0) { + while (length > 0) { int c = in.read(b, offset, length); if (c == -1) { if (count == 0) { count = -1; } + break; } else { + offset += c; count += c; + length -= c; + + if (in.available() <= 0) { + break; + } } } diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index c3fa42932f..3c97db5e4a 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -60,7 +60,19 @@ public class File { public boolean isFile() { return isFile(path); } + + private static native boolean canRead(String path); + + public boolean canRead() { + return canRead(path); + } + private static native boolean canWrite(String path); + + public boolean canWrite() { + return canWrite(path); + } + public String getName() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java index 4c0d576368..9c614e2f7e 100644 --- a/classpath/java/io/FileInputStream.java +++ b/classpath/java/io/FileInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java index d61d44e136..60190e0757 100644 --- a/classpath/java/io/FileOutputStream.java +++ b/classpath/java/io/FileOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -22,14 +22,19 @@ public class FileOutputStream extends OutputStream { } public FileOutputStream(String path) throws IOException { - fd = open(path); + this(path, false); } + public FileOutputStream(String path, boolean append) throws IOException { + fd = open(path, append); + } + + public FileOutputStream(File file) throws IOException { this(file.getPath()); } - private static native int open(String path) throws IOException; + private static native int open(String path, boolean append) throws IOException; private static native void write(int fd, int c) throws IOException; diff --git a/classpath/java/io/InputStreamReader.java b/classpath/java/io/InputStreamReader.java index a2049b1b62..98f145cd92 100644 --- a/classpath/java/io/InputStreamReader.java +++ b/classpath/java/io/InputStreamReader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/ObjectInputStream.java b/classpath/java/io/ObjectInputStream.java index 001a192a73..20fa5cdfb8 100644 --- a/classpath/java/io/ObjectInputStream.java +++ b/classpath/java/io/ObjectInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -79,6 +79,10 @@ public class ObjectInputStream extends InputStream { read('d'); return readDoubleToken(); } + + public void defaultReadObject() throws IOException { + throw new UnsupportedOperationException(); + } private void skipSpace() throws IOException { int c; diff --git a/classpath/java/io/ObjectOutputStream.java b/classpath/java/io/ObjectOutputStream.java index 42d080f676..80cac7857b 100644 --- a/classpath/java/io/ObjectOutputStream.java +++ b/classpath/java/io/ObjectOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -82,6 +82,10 @@ public class ObjectOutputStream extends OutputStream { out.print(v); } + public void defaultWriteObject() throws IOException { + throw new UnsupportedOperationException(); + } + private void writeObject(Object o, IdentityHashMap map, int nextId) throws IOException diff --git a/classpath/java/io/OutputStreamWriter.java b/classpath/java/io/OutputStreamWriter.java index 1c94a774ac..3cd061f9b4 100644 --- a/classpath/java/io/OutputStreamWriter.java +++ b/classpath/java/io/OutputStreamWriter.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index d4aa83eceb..a720fac6a0 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -31,6 +31,7 @@ public class PrintStream extends OutputStream { public synchronized void print(String s) { try { out.write(s.getBytes()); + if (autoFlush) flush(); } catch (IOException e) { } } @@ -38,10 +39,34 @@ public class PrintStream extends OutputStream { print(String.valueOf(o)); } + public void print(boolean v) { + print(String.valueOf(v)); + } + public void print(char c) { print(String.valueOf(c)); } + public void print(int v) { + print(String.valueOf(v)); + } + + public void print(long v) { + print(String.valueOf(v)); + } + + public void print(float v) { + print(String.valueOf(v)); + } + + public void print(double v) { + print(String.valueOf(v)); + } + + public void print(char[] s) { + print(String.valueOf(s)); + } + public synchronized void println(String s) { try { out.write(s.getBytes()); @@ -61,9 +86,33 @@ public class PrintStream extends OutputStream { println(String.valueOf(o)); } + public void println(boolean v) { + println(String.valueOf(v)); + } + public void println(char c) { println(String.valueOf(c)); } + + public void println(int v) { + println(String.valueOf(v)); + } + + public void println(long v) { + println(String.valueOf(v)); + } + + public void println(float v) { + println(String.valueOf(v)); + } + + public void println(double v) { + println(String.valueOf(v)); + } + + public void println(char[] s) { + println(String.valueOf(s)); + } public void write(int c) throws IOException { out.write(c); diff --git a/classpath/java/io/Reader.java b/classpath/java/io/Reader.java index acbf42ffd2..a09c8a24e9 100644 --- a/classpath/java/io/Reader.java +++ b/classpath/java/io/Reader.java @@ -28,5 +28,17 @@ public abstract class Reader { public abstract int read(char[] buffer, int offset, int length) throws IOException; + public boolean markSupported() { + return false; + } + + public void mark(int readAheadLimit) throws IOException { + throw new IOException("mark not supported"); + } + + public void reset() throws IOException { + throw new IOException("reset not supported"); + } + public abstract void close() throws IOException; } diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java index f696037561..88025280e8 100644 --- a/classpath/java/lang/Character.java +++ b/classpath/java/lang/Character.java @@ -109,6 +109,15 @@ public final class Character implements Comparable { } } + public static char forDigit(int digit, int radix) { + if (MIN_RADIX <= radix && radix <= MAX_RADIX) { + if (0 <= digit && digit < radix) { + return (char) (digit < 10 ? digit + '0' : digit + 'a' - 10); + } + } + return 0; + } + public static boolean isLetter(int c) { return canCastToChar(c) && isLetter((char) c); } diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index de7d3b0fc8..b550ae5509 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,18 +10,20 @@ package java.lang; +import avian.VMClass; +import avian.ClassAddendum; import avian.AnnotationInvocationHandler; +import avian.SystemClassLoader; +import avian.Classes; 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; @@ -33,29 +35,14 @@ import java.security.ProtectionDomain; import java.security.Permissions; import java.security.AllPermission; -public final class Class - implements Type, GenericDeclaration, AnnotatedElement -{ +public final class Class implements Type, AnnotatedElement { private static final int PrimitiveFlag = 1 << 5; - private short flags; - public short vmFlags; - private short fixedSize; - private byte arrayElementSize; - private byte arrayDimensions; - private int[] objectMask; - private byte[] name; - private byte[] sourceFile; - 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; + public final VMClass vmClass; - private Class() { } + public Class(VMClass vmClass) { + this.vmClass = vmClass; + } public String toString() { return getName(); @@ -73,26 +60,30 @@ public final class Class } public String getName() { - if (name == null) { - if ((vmFlags & PrimitiveFlag) != 0) { - if (this == primitiveClass('V')) { - name = "void\0".getBytes(); - } else if (this == primitiveClass('Z')) { - name = "boolean\0".getBytes(); - } else if (this == primitiveClass('B')) { - name = "byte\0".getBytes(); - } else if (this == primitiveClass('C')) { - name = "char\0".getBytes(); - } else if (this == primitiveClass('S')) { - name = "short\0".getBytes(); - } else if (this == primitiveClass('I')) { - name = "int\0".getBytes(); - } else if (this == primitiveClass('F')) { - name = "float\0".getBytes(); - } else if (this == primitiveClass('J')) { - name = "long\0".getBytes(); - } else if (this == primitiveClass('D')) { - name = "double\0".getBytes(); + return getName(vmClass); + } + + public static String getName(VMClass c) { + if (c.name == null) { + if ((c.vmFlags & PrimitiveFlag) != 0) { + if (c == Classes.primitiveClass('V')) { + c.name = "void\0".getBytes(); + } else if (c == Classes.primitiveClass('Z')) { + c.name = "boolean\0".getBytes(); + } else if (c == Classes.primitiveClass('B')) { + c.name = "byte\0".getBytes(); + } else if (c == Classes.primitiveClass('C')) { + c.name = "char\0".getBytes(); + } else if (c == Classes.primitiveClass('S')) { + c.name = "short\0".getBytes(); + } else if (c == Classes.primitiveClass('I')) { + c.name = "int\0".getBytes(); + } else if (c == Classes.primitiveClass('F')) { + c.name = "float\0".getBytes(); + } else if (c == Classes.primitiveClass('J')) { + c.name = "long\0".getBytes(); + } else if (c == Classes.primitiveClass('D')) { + c.name = "double\0".getBytes(); } else { throw new AssertionError(); } @@ -102,11 +93,12 @@ public final class Class } return new String - (replace('/', '.', name, 0, name.length - 1), 0, name.length - 1, false); + (replace('/', '.', c.name, 0, c.name.length - 1), 0, c.name.length - 1, + false); } public String getCanonicalName() { - if ((vmFlags & PrimitiveFlag) != 0) { + if ((vmClass.vmFlags & PrimitiveFlag) != 0) { return getName(); } else if (isArray()) { return getComponentType().getCanonicalName() + "[]"; @@ -116,7 +108,7 @@ public final class Class } public String getSimpleName() { - if ((vmFlags & PrimitiveFlag) != 0) { + if ((vmClass.vmFlags & PrimitiveFlag) != 0) { return getName(); } else if (isArray()) { return getComponentType().getSimpleName() + "[]"; @@ -131,10 +123,6 @@ public final class Class } } - public Object staticTable() { - return staticTable; - } - public T newInstance() throws IllegalAccessException, InstantiationException { @@ -148,8 +136,7 @@ public final class Class } public static Class forName(String name) throws ClassNotFoundException { - return forName - (name, true, Method.getCaller().getDeclaringClass().getClassLoader()); + return forName(name, true, Method.getCaller().class_.loader); } public static Class forName(String name, boolean initialize, @@ -157,20 +144,16 @@ public final class Class throws ClassNotFoundException { if (loader == null) { - loader = Class.class.loader; + loader = Class.class.vmClass.loader; } Class c = loader.loadClass(name); - avian.SystemClassLoader.link(c, loader); + Classes.link(c.vmClass, loader); if (initialize) { - c.initialize(); + Classes.initialize(c.vmClass); } return c; } - private static native Class primitiveClass(char name); - - private native void initialize(); - public static Class forCanonicalName(String name) { return forCanonicalName(null, name); } @@ -183,7 +166,8 @@ public final class Class return forName(name.substring(1, name.length() - 1), true, loader); } else { if (name.length() == 1) { - return primitiveClass(name.charAt(0)); + return SystemClassLoader.getClass + (Classes.primitiveClass(name.charAt(0))); } else { throw new ClassNotFoundException(name); } @@ -197,39 +181,41 @@ public final class Class if (isArray()) { String n = getName(); if ("[Z".equals(n)) { - return primitiveClass('Z'); + return SystemClassLoader.getClass(Classes.primitiveClass('Z')); } else if ("[B".equals(n)) { - return primitiveClass('B'); + return SystemClassLoader.getClass(Classes.primitiveClass('B')); } else if ("[S".equals(n)) { - return primitiveClass('S'); + return SystemClassLoader.getClass(Classes.primitiveClass('S')); } else if ("[C".equals(n)) { - return primitiveClass('C'); + return SystemClassLoader.getClass(Classes.primitiveClass('C')); } else if ("[I".equals(n)) { - return primitiveClass('I'); + return SystemClassLoader.getClass(Classes.primitiveClass('I')); } else if ("[F".equals(n)) { - return primitiveClass('F'); + return SystemClassLoader.getClass(Classes.primitiveClass('F')); } else if ("[J".equals(n)) { - return primitiveClass('J'); + return SystemClassLoader.getClass(Classes.primitiveClass('J')); } else if ("[D".equals(n)) { - return primitiveClass('D'); + return SystemClassLoader.getClass(Classes.primitiveClass('D')); } - if (staticTable == null) throw new AssertionError(name); - return (Class) staticTable; + if (vmClass.staticTable == null) throw new AssertionError(); + return SystemClassLoader.getClass((VMClass) vmClass.staticTable); } else { return null; } } - public native boolean isAssignableFrom(Class c); + public boolean isAssignableFrom(Class c) { + return Classes.isAssignableFrom(vmClass, c.vmClass); + } - private Field findField(String name) { - if (fieldTable != null) { - avian.SystemClassLoader.link(this); + private static Field findField(VMClass vmClass, String name) { + if (vmClass.fieldTable != null) { + Classes.link(vmClass); - for (int i = 0; i < fieldTable.length; ++i) { - if (fieldTable[i].getName().equals(name)) { - return fieldTable[i]; + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (Field.getName(vmClass.fieldTable[i]).equals(name)) { + return new Field(vmClass.fieldTable[i]); } } } @@ -237,7 +223,7 @@ public final class Class } public Field getDeclaredField(String name) throws NoSuchFieldException { - Field f = findField(name); + Field f = findField(vmClass, name); if (f == null) { throw new NoSuchFieldException(name); } else { @@ -246,8 +232,8 @@ public final class Class } public Field getField(String name) throws NoSuchFieldException { - for (Class c = this; c != null; c = c.super_) { - Field f = c.findField(name); + for (VMClass c = vmClass; c != null; c = c.super_) { + Field f = findField(c, name); if (f != null) { return f; } @@ -268,19 +254,22 @@ public final class Class } } - private Method findMethod(String name, Class[] parameterTypes) { - if (methodTable != null) { - avian.SystemClassLoader.link(this); + private static Method findMethod(VMClass vmClass, String name, + Class[] parameterTypes) + { + if (vmClass.methodTable != null) { + Classes.link(vmClass); if (parameterTypes == null) { parameterTypes = new Class[0]; } - for (int i = 0; i < methodTable.length; ++i) { - if (methodTable[i].getName().equals(name) - && match(parameterTypes, methodTable[i].getParameterTypes())) + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (Method.getName(vmClass.methodTable[i]).equals(name) + && match(parameterTypes, + Method.getParameterTypes(vmClass.methodTable[i]))) { - return methodTable[i]; + return new Method(vmClass.methodTable[i]); } } } @@ -293,7 +282,7 @@ public final class Class if (name.startsWith("<")) { throw new NoSuchMethodException(name); } - Method m = findMethod(name, parameterTypes); + Method m = findMethod(vmClass, name, parameterTypes); if (m == null) { throw new NoSuchMethodException(name); } else { @@ -307,8 +296,8 @@ public final class Class if (name.startsWith("<")) { throw new NoSuchMethodException(name); } - for (Class c = this; c != null; c = c.super_) { - Method m = c.findMethod(name, parameterTypes); + for (VMClass c = vmClass; c != null; c = c.super_) { + Method m = findMethod(c, name, parameterTypes); if (m != null) { return m; } @@ -319,7 +308,7 @@ public final class Class public Constructor getConstructor(Class ... parameterTypes) throws NoSuchMethodException { - Method m = findMethod("", parameterTypes); + Method m = findMethod(vmClass, "", parameterTypes); if (m == null) { throw new NoSuchMethodException(); } else { @@ -348,11 +337,12 @@ public final class Class private int countConstructors(boolean publicOnly) { int count = 0; - if (methodTable != null) { - for (int i = 0; i < methodTable.length; ++i) { + if (vmClass.methodTable != null) { + for (int i = 0; i < vmClass.methodTable.length; ++i) { if (((! publicOnly) - || ((methodTable[i].getModifiers() & Modifier.PUBLIC)) != 0) - && methodTable[i].getName().equals("")) + || ((vmClass.methodTable[i].flags & Modifier.PUBLIC)) + != 0) + && Method.getName(vmClass.methodTable[i]).equals("")) { ++ count; } @@ -363,13 +353,13 @@ public final class Class public Constructor[] getDeclaredConstructors() { Constructor[] array = new Constructor[countConstructors(false)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + Classes.link(vmClass); int index = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (methodTable[i].getName().equals("")) { - array[index++] = new Constructor(methodTable[i]); + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (Method.getName(vmClass.methodTable[i]).equals("")) { + array[index++] = new Constructor(new Method(vmClass.methodTable[i])); } } } @@ -379,15 +369,15 @@ public final class Class public Constructor[] getConstructors() { Constructor[] array = new Constructor[countConstructors(true)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + Classes.link(vmClass); int index = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (((methodTable[i].getModifiers() & Modifier.PUBLIC) != 0) - && methodTable[i].getName().equals("")) + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (((vmClass.methodTable[i].flags & Modifier.PUBLIC) != 0) + && Method.getName(vmClass.methodTable[i]).equals("")) { - array[index++] = new Constructor(methodTable[i]); + array[index++] = new Constructor(new Method(vmClass.methodTable[i])); } } } @@ -396,9 +386,11 @@ public final class Class } public Field[] getDeclaredFields() { - if (fieldTable != null) { - Field[] array = new Field[fieldTable.length]; - System.arraycopy(fieldTable, 0, array, 0, fieldTable.length); + if (vmClass.fieldTable != null) { + Field[] array = new Field[vmClass.fieldTable.length]; + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + array[i] = new Field(vmClass.fieldTable[i]); + } return array; } else { return new Field[0]; @@ -407,9 +399,9 @@ public final class Class private int countPublicFields() { int count = 0; - if (fieldTable != null) { - for (int i = 0; i < fieldTable.length; ++i) { - if (((fieldTable[i].getModifiers() & Modifier.PUBLIC)) != 0) { + if (vmClass.fieldTable != null) { + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { ++ count; } } @@ -419,13 +411,13 @@ public final class Class public Field[] getFields() { Field[] array = new Field[countPublicFields()]; - if (fieldTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.fieldTable != null) { + Classes.link(vmClass); int ai = 0; - for (int i = 0; i < fieldTable.length; ++i) { - if (((fieldTable[i].getModifiers() & Modifier.PUBLIC)) != 0) { - array[ai++] = fieldTable[i]; + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { + array[ai++] = new Field(vmClass.fieldTable[i]); } } } @@ -434,11 +426,12 @@ public final class Class private int countMethods(boolean publicOnly) { int count = 0; - if (methodTable != null) { - for (int i = 0; i < methodTable.length; ++i) { + if (vmClass.methodTable != null) { + for (int i = 0; i < vmClass.methodTable.length; ++i) { if (((! publicOnly) - || ((methodTable[i].getModifiers() & Modifier.PUBLIC)) != 0) - && (! methodTable[i].getName().startsWith("<"))) + || ((vmClass.methodTable[i].flags & Modifier.PUBLIC)) + != 0) + && (! Method.getName(vmClass.methodTable[i]).startsWith("<"))) { ++ count; } @@ -449,13 +442,13 @@ public final class Class public Method[] getDeclaredMethods() { Method[] array = new Method[countMethods(false)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + Classes.link(vmClass); int ai = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (! methodTable[i].getName().startsWith("<")) { - array[ai++] = methodTable[i]; + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (! Method.getName(vmClass.methodTable[i]).startsWith("<")) { + array[ai++] = new Method(vmClass.methodTable[i]); } } } @@ -465,15 +458,15 @@ public final class Class public Method[] getMethods() { Method[] array = new Method[countMethods(true)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + Classes.link(vmClass); int index = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (((methodTable[i].getModifiers() & Modifier.PUBLIC) != 0) - && (! methodTable[i].getName().startsWith("<"))) + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (((vmClass.methodTable[i].flags & Modifier.PUBLIC) != 0) + && (! Method.getName(vmClass.methodTable[i]).startsWith("<"))) { - array[index++] = methodTable[i]; + array[index++] = new Method(vmClass.methodTable[i]); } } } @@ -482,13 +475,14 @@ public final class Class } public Class[] getInterfaces() { - if (interfaceTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.interfaceTable != null) { + Classes.link(vmClass); int stride = (isInterface() ? 1 : 2); - Class[] array = new Class[interfaceTable.length / stride]; + Class[] array = new Class[vmClass.interfaceTable.length / stride]; for (int i = 0; i < array.length; ++i) { - array[i] = (Class) interfaceTable[i * stride]; + array[i] = SystemClassLoader.getClass + ((VMClass) vmClass.interfaceTable[i * stride]); } return array; } else { @@ -509,36 +503,42 @@ public final class Class } public ClassLoader getClassLoader() { - return loader; + return vmClass.loader; } public int getModifiers() { - return flags; + return vmClass.flags; } public boolean isInterface() { - return (flags & Modifier.INTERFACE) != 0; + return (vmClass.flags & Modifier.INTERFACE) != 0; } public Class getSuperclass() { - return super_; + return SystemClassLoader.getClass(vmClass.super_); } public boolean isArray() { - return arrayDimensions != 0; + return vmClass.arrayDimensions != 0; + } + + public static boolean isInstance(VMClass c, Object o) { + return o != null && Classes.isAssignableFrom + (c, Classes.getVMClass(o)); } public boolean isInstance(Object o) { - return o != null && isAssignableFrom(o.getClass()); + return isInstance(vmClass, o); } public boolean isPrimitive() { - return (vmFlags & PrimitiveFlag) != 0; + return (vmClass.vmFlags & PrimitiveFlag) != 0; } public URL getResource(String path) { if (! path.startsWith("/")) { - String name = new String(this.name, 0, this.name.length - 1, false); + String name = new String + (vmClass.name, 0, vmClass.name.length - 1, false); int index = name.lastIndexOf('/'); if (index >= 0) { path = name.substring(0, index) + "/" + path; @@ -572,12 +572,8 @@ public final class Class return (T) o; } - public Object[] getSigners() { - return addendum == null ? null : addendum.signers; - } - public Package getPackage() { - if ((vmFlags & PrimitiveFlag) != 0 || isArray()) { + if ((vmClass.vmFlags & PrimitiveFlag) != 0 || isArray()) { return null; } else { String name = getCanonicalName(); @@ -597,25 +593,25 @@ public final class Class return getAnnotation(class_) != null; } - private Annotation getAnnotation(Object[] a) { + private static Annotation getAnnotation(VMClass c, Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance - (loader, new Class[] { (Class) a[1] }, + (c.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { - for (Class c = this; c != null; c = c.super_) { + for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { - avian.SystemClassLoader.link(c, c.loader); + Classes.link(c, c.loader); Object[] table = (Object[]) 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 (T) getAnnotation(c, a); } } } @@ -624,13 +620,13 @@ public final class Class } public Annotation[] getDeclaredAnnotations() { - if (addendum != null && addendum.annotationTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.addendum.annotationTable != null) { + Classes.link(vmClass); - Object[] table = (Object[]) addendum.annotationTable; + Object[] table = (Object[]) vmClass.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { - array[i] = getAnnotation((Object[]) table[i]); + array[i] = getAnnotation(vmClass, (Object[]) table[i]); } return array; } else { @@ -640,7 +636,7 @@ public final class Class private int countAnnotations() { int count = 0; - for (Class c = this; c != null; c = c.super_) { + for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { count += ((Object[]) c.addendum.annotationTable).length; } @@ -651,11 +647,11 @@ public final class Class public Annotation[] getAnnotations() { Annotation[] array = new Annotation[countMethods(true)]; int i = 0; - for (Class c = this; c != null; c = c.super_) { + for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { Object[] table = (Object[]) c.addendum.annotationTable; for (int j = 0; j < table.length; ++j) { - array[i++] = getAnnotation((Object[]) table[j]); + array[i++] = getAnnotation(vmClass, (Object[]) table[j]); } } } @@ -663,43 +659,9 @@ public final class Class return array; } - public boolean isEnum() { - throw new UnsupportedOperationException(); - } - - public TypeVariable>[] getTypeParameters() { - throw new UnsupportedOperationException(); - } - - public Method getEnclosingMethod() { - throw new UnsupportedOperationException(); - } - - public Constructor getEnclosingConstructor() { - throw new UnsupportedOperationException(); - } - - public Class getEnclosingClass() { - throw new UnsupportedOperationException(); - } - - public Class[] getDeclaredClasses() { - throw new UnsupportedOperationException(); - } - public ProtectionDomain getProtectionDomain() { Permissions p = new Permissions(); p.add(new AllPermission()); return new ProtectionDomain(null, p); } - - // for GNU Classpath compatibility: - void setSigners(Object[] signers) { - if (signers != null && signers.length > 0) { - if (addendum == null) { - addendum = new avian.ClassAddendum(); - } - addendum.signers = signers; - } - } } diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 9cb5b0e664..b2ee0b7f75 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -13,6 +13,10 @@ package java.lang; import java.io.InputStream; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; public abstract class ClassLoader { private final ClassLoader parent; @@ -42,14 +46,17 @@ public abstract class ClassLoader { throw new IndexOutOfBoundsException(); } - return avian.SystemClassLoader.defineClass(this, b, offset, length); + return avian.SystemClassLoader.getClass + (avian.Classes.defineVMClass(this, b, offset, length)); } protected Class findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(); } - protected abstract Class reallyFindLoadedClass(String name); + protected Class reallyFindLoadedClass(String name) { + return null; + } protected final Class findLoadedClass(String name) { return reallyFindLoadedClass(name); @@ -83,7 +90,7 @@ public abstract class ClassLoader { } protected void resolveClass(Class c) { - avian.SystemClassLoader.link(c, this); + avian.Classes.link(c.vmClass, this); } private ClassLoader getParent() { @@ -94,6 +101,10 @@ public abstract class ClassLoader { return null; } + protected Enumeration findResources(String name) throws IOException { + return Collections.enumeration(new ArrayList(0)); + } + public URL getResource(String path) { URL url = null; if (parent != null) { @@ -123,4 +134,24 @@ public abstract class ClassLoader { public static InputStream getSystemResourceAsStream(String path) { return getSystemClassLoader().getResourceAsStream(path); } + + public static Enumeration getSystemResources(String name) throws IOException { + return getSystemClassLoader().getResources(name); + } + + public Enumeration getResources(String name) + throws IOException { + Collection resources = collectResources(name); + return Collections.enumeration(resources); + } + + private Collection collectResources(String name) { + Collection urls = parent != null ? parent.collectResources(name) : new ArrayList(5); + URL url = findResource(name); + if (url != null) { + urls.add(url); + } + return urls; + } + } diff --git a/classpath/java/lang/Enum.java b/classpath/java/lang/Enum.java index 3e7fb49282..e09bd73c2c 100644 --- a/classpath/java/lang/Enum.java +++ b/classpath/java/lang/Enum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -34,7 +34,7 @@ public abstract class Enum> implements Comparable { try { Method method = enumType.getMethod("values"); - Enum values[] = (Enum[]) (method.invoke(null)); + Enum values[] = (Enum[]) method.invoke(null); for (Enum value: values) { if (name.equals(value.name)) { return (T) value; diff --git a/classpath/java/lang/IllegalAccessError.java b/classpath/java/lang/IllegalAccessError.java new file mode 100644 index 0000000000..4e0cf6e399 --- /dev/null +++ b/classpath/java/lang/IllegalAccessError.java @@ -0,0 +1,26 @@ +/* Copyright (c) 2010, 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; + +/** + * TODO : current Avian runtime doesn't check, need to be implemented. + * + */ +public class IllegalAccessError extends IncompatibleClassChangeError { + + public IllegalAccessError(String message) { + super(message); + } + + public IllegalAccessError() { + } + +} diff --git a/classpath/java/lang/InstantiationError.java b/classpath/java/lang/InstantiationError.java new file mode 100644 index 0000000000..82cf51bc41 --- /dev/null +++ b/classpath/java/lang/InstantiationError.java @@ -0,0 +1,26 @@ +/* Copyright (c) 2010, 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; + +/** + * TODO : current Avian runtime doesn't check, need to be implemented. + * + */ +public class InstantiationError extends IncompatibleClassChangeError { + + public InstantiationError(String message) { + super(message); + } + + public InstantiationError() { + } + +} diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index c7c9767380..033ca8b111 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Object.java b/classpath/java/lang/Object.java index bfd2da9eea..6a0a00937b 100644 --- a/classpath/java/lang/Object.java +++ b/classpath/java/lang/Object.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -27,7 +27,11 @@ public class Object { protected void finalize() throws Throwable { } - public native final Class getClass(); + public final Class getClass() { + return avian.SystemClassLoader.getClass(getVMClass(this)); + } + + private static native avian.VMClass getVMClass(Object o); public native int hashCode(); diff --git a/classpath/java/lang/OutOfMemoryError.java b/classpath/java/lang/OutOfMemoryError.java index 50848a9ae4..138897399c 100644 --- a/classpath/java/lang/OutOfMemoryError.java +++ b/classpath/java/lang/OutOfMemoryError.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,9 +10,9 @@ package java.lang; -public class OutOfMemoryError extends Error { +public class OutOfMemoryError extends VirtualMachineError { public OutOfMemoryError(String message) { - super(message, null); + super(message); } public OutOfMemoryError() { diff --git a/classpath/java/lang/Package.java b/classpath/java/lang/Package.java index 507a240a3e..5cd9b9547e 100644 --- a/classpath/java/lang/Package.java +++ b/classpath/java/lang/Package.java @@ -43,4 +43,8 @@ public class Package { this.sealed = sealed; this.loader = loader; } + + public String getName() { + return name; + } } diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index d1accb33fd..30dc0b6612 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -44,28 +44,80 @@ public class Runtime { } public Process exec(String command) throws IOException { - long[] process = new long[4]; StringTokenizer t = new StringTokenizer(command); String[] cmd = new String[t.countTokens()]; for (int i = 0; i < cmd.length; i++) cmd[i] = t.nextToken(); - exec(cmd, process); - return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); + + return exec(cmd); } - public Process exec(String[] command) { - long[] process = new long[4]; - exec(command, process); - return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); + public Process exec(final String[] command) throws IOException { + final MyProcess[] process = new MyProcess[1]; + final Throwable[] exception = new Throwable[1]; + + synchronized (process) { + Thread t = new Thread() { + public void run() { + synchronized (process) { + try { + long[] info = new long[5]; + exec(command, info); + process[0] = new MyProcess + (info[0], info[1], (int) info[2], (int) info[3], + (int) info[4]); + } catch (Throwable e) { + exception[0] = e; + } finally { + process.notifyAll(); + } + } + + MyProcess p = process[0]; + if (p != null) { + synchronized (p) { + try { + if (p.pid != 0) { + p.exitCode = Runtime.waitFor(p.pid, p.tid); + p.pid = 0; + p.tid = 0; + } + } finally { + p.notifyAll(); + } + } + } + } + }; + t.setDaemon(true); + t.start(); + + while (process[0] == null && exception[0] == null) { + try { + process.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + if (exception[0] != null) { + if (exception[0] instanceof IOException) { + throw new IOException(exception[0]); + } else { + throw new RuntimeException(exception[0]); + } + } + + return process[0]; } public native void addShutdownHook(Thread t); - private static native void exec(String[] command, long[] process); + private static native void exec(String[] command, long[] process) + throws IOException; - private static native int exitValue(long pid); - - private static native int waitFor(long pid); + private static native int waitFor(long pid, long tid); private static native void load(String name, boolean mapName); @@ -79,13 +131,15 @@ public class Runtime { private static class MyProcess extends Process { private long pid; + private long tid; private final int in; private final int out; private final int err; private int exitCode; - public MyProcess(long pid, int in, int out, int err) { + public MyProcess(long pid, long tid, int in, int out, int err) { this.pid = pid; + this.tid = tid; this.in = in; this.out = out; this.err = err; @@ -95,13 +149,6 @@ public class Runtime { throw new RuntimeException("not implemented"); } - public int exitValue() { - if (pid != 0) { - exitCode = Runtime.exitValue(pid); - } - return exitCode; - } - public InputStream getInputStream() { return new FileInputStream(new FileDescriptor(in)); } @@ -114,11 +161,19 @@ public class Runtime { return new FileInputStream(new FileDescriptor(err)); } - public int waitFor() throws InterruptedException { + public synchronized int exitValue() { if (pid != 0) { - exitCode = Runtime.waitFor(pid); - pid = 0; + throw new IllegalThreadStateException(); } + + return exitCode; + } + + public synchronized int waitFor() throws InterruptedException { + while (pid != 0) { + wait(); + } + return exitCode; } } diff --git a/classpath/java/lang/SecurityManager.java b/classpath/java/lang/SecurityManager.java new file mode 100644 index 0000000000..0b522c5bfb --- /dev/null +++ b/classpath/java/lang/SecurityManager.java @@ -0,0 +1,30 @@ +/* Copyright (c) 2010, 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; + +import java.security.AccessController; +import java.security.Permission; +import java.security.SecurityPermission; + +public class SecurityManager { + + public SecurityManager() { + } + + public void checkPermission(Permission perm) { + AccessController.checkPermission(perm); + } + + public void checkSecurityAccess(String target) { + checkPermission(new SecurityPermission(target)); + } + +} diff --git a/classpath/java/lang/StackTraceElement.java b/classpath/java/lang/StackTraceElement.java index db16585c73..87dd6d7897 100644 --- a/classpath/java/lang/StackTraceElement.java +++ b/classpath/java/lang/StackTraceElement.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -56,7 +56,7 @@ public class StackTraceElement { } public String getClassName() { - return class_.replace('/', '.'); + return class_; } public String getMethodName() { diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 143c60fd72..788400dbac 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -13,7 +13,6 @@ package java.lang; import java.io.UnsupportedEncodingException; import java.util.regex.Pattern; import java.util.Comparator; -import java.util.Formatter; import java.util.Locale; import java.io.Serializable; import avian.Utf8; @@ -236,19 +235,31 @@ public final class String } public String toLowerCase() { - char[] b = new char[length]; - for (int i = 0; i < length; ++i) { - b[i] = Character.toLowerCase(charAt(i)); + for (int j = 0; j < length; ++j) { + char ch = charAt(j); + if (Character.toLowerCase(ch) != ch) { + char[] b = new char[length]; + for (int i = 0; i < length; ++i) { + b[i] = Character.toLowerCase(charAt(i)); + } + return new String(b, 0, length, false); + } } - return new String(b, 0, length, false); + return this; } public String toUpperCase() { - char[] b = new char[length]; - for (int i = 0; i < length; ++i) { - b[i] = Character.toUpperCase(charAt(i)); + for (int j = 0; j < length; ++j) { + char ch = charAt(j); + if (Character.toUpperCase(ch) != ch) { + char[] b = new char[length]; + for (int i = 0; i < length; ++i) { + b[i] = Character.toUpperCase(charAt(i)); + } + return new String(b, 0, length, false); + } } - return new String(b, 0, length, false); + return this; } public int indexOf(int c) { @@ -507,9 +518,7 @@ public final class String } public static String valueOf(int v) { - // use Integer.toString(int, int), because GNU Classpath's - // Integer.toString(int) just calls String.valueOf(int): - return Integer.toString(v, 10); + return Integer.toString(v); } public static String valueOf(long v) { @@ -576,36 +585,19 @@ public final class String return Character.codePointCount(this, start, end); } - public String replace(CharSequence match, CharSequence replacement) { - throw new UnsupportedOperationException(); - } - public String toUpperCase(Locale locale) { - throw new UnsupportedOperationException(); + if (locale == Locale.ENGLISH) { + return toUpperCase(); + } else { + throw new UnsupportedOperationException("toUpperCase("+locale+')'); + } } public String toLowerCase(Locale locale) { - throw new UnsupportedOperationException(); - } - - public static String format(Locale locale, String format, Object ... args) { - return new Formatter(locale).format(format, args).toString(); - } - - public static String format(String format, Object ... args) { - return format(Locale.getDefault(), format, args); - } - - // for GNU Classpath compatibility: - static char[] zeroBasedStringValue(String s) { - if (s.offset == 0) { - if (s.data instanceof char[]) { - char[] data = (char[]) s.data; - if (data.length == s.length) { - return data; - } - } + if (locale == Locale.ENGLISH) { + return toLowerCase(); + } else { + throw new UnsupportedOperationException("toLowerCase("+locale+')'); } - return s.toCharArray(); } } diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index ac3ee11b3a..954c62d116 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -22,6 +22,7 @@ import java.util.Properties; public abstract class System { private static Property properties; + private static SecurityManager securityManager; // static { // loadLibrary("natives"); // } @@ -118,6 +119,14 @@ public abstract class System { public static void exit(int code) { Runtime.getRuntime().exit(code); } + + public static SecurityManager getSecurityManager() { + return securityManager; + } + + public static void setSecurityManager(SecurityManager securityManager) { + System.securityManager = securityManager; + } private static class Property { public final String name; diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index fec432b34e..2d321193a0 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -15,7 +15,8 @@ import java.util.WeakHashMap; public class Thread implements Runnable { private long peer; - private boolean interrupted; + private volatile boolean interrupted; + private volatile boolean unparked; private boolean daemon; private byte state; private byte priority; @@ -24,11 +25,8 @@ public class Thread implements Runnable { private Object sleepLock; private ClassLoader classLoader; private UncaughtExceptionHandler exceptionHandler; - - // package private for GNU Classpath, which inexplicably bypasses - // the accessor methods: - String name; - ThreadGroup group; + private String name; + private ThreadGroup group; private static UncaughtExceptionHandler defaultExceptionHandler; @@ -141,25 +139,9 @@ public class Thread implements Runnable { public static native Thread currentThread(); - private static native void interrupt(long peer); + public native void interrupt(); - public synchronized void interrupt() { - if (peer != 0) { - interrupt(peer); - } else { - interrupted = true; - } - } - - public static boolean interrupted() { - Thread t = currentThread(); - - synchronized (t) { - boolean v = t.interrupted; - t.interrupted = false; - return v; - } - } + public native boolean interrupted(); public static boolean isInterrupted() { return currentThread().interrupted; @@ -257,12 +239,12 @@ public class Thread implements Runnable { } public synchronized void setDaemon(boolean v) { - if (v != daemon) { - setDaemon(this, v); + if (getState() != State.NEW) { + throw new IllegalStateException(); } - } - private static native void setDaemon(Thread t, boolean increment); + daemon = v; + } public static native void yield(); @@ -303,22 +285,6 @@ public class Thread implements Runnable { return peer; } - public void stop() { - throw new UnsupportedOperationException(); - } - - public void stop(Throwable t) { - throw new UnsupportedOperationException(); - } - - public void suspend() { - throw new UnsupportedOperationException(); - } - - public void resume() { - throw new UnsupportedOperationException(); - } - public interface UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e); } diff --git a/classpath/java/lang/ThreadGroup.java b/classpath/java/lang/ThreadGroup.java index 5145f0e865..a08c73f9ec 100644 --- a/classpath/java/lang/ThreadGroup.java +++ b/classpath/java/lang/ThreadGroup.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -13,7 +13,7 @@ package java.lang; import avian.Cell; public class ThreadGroup implements Thread.UncaughtExceptionHandler { - final ThreadGroup parent; // package private for GNU Classpath compatibility + private final ThreadGroup parent; private final String name; private Cell subgroups; diff --git a/classpath/java/lang/ref/ReferenceQueue.java b/classpath/java/lang/ref/ReferenceQueue.java index 46eb1f26ce..8650f15d6e 100644 --- a/classpath/java/lang/ref/ReferenceQueue.java +++ b/classpath/java/lang/ref/ReferenceQueue.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -12,13 +12,12 @@ package java.lang.ref; public class ReferenceQueue { private Reference front; - private Reference rear; public Reference poll() { Reference r = front; if (front != null) { if (front == front.jNext) { - front = rear = null; + front = null; } else { front = front.jNext; } @@ -27,12 +26,11 @@ public class ReferenceQueue { } void add(Reference r) { - r.jNext = r; if (front == null) { - front = r; + r.jNext = r; } else { - rear.jNext = r; + r.jNext = front; } - rear = r; + front = r; } } diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index ac42178373..908e84b452 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -12,9 +12,7 @@ package java.lang.reflect; import java.lang.annotation.Annotation; -public class Constructor extends AccessibleObject - implements Member, GenericDeclaration -{ +public class Constructor extends AccessibleObject implements Member { private Method method; public Constructor(Method method) { @@ -42,10 +40,6 @@ public class Constructor extends AccessibleObject return method.getParameterTypes(); } - public Class[] getExceptionTypes() { - return method.getExceptionTypes(); - } - public int getModifiers() { return method.getModifiers(); } @@ -54,10 +48,6 @@ public class Constructor extends AccessibleObject return method.getName(); } - public boolean isSynthetic() { - return method.isSynthetic(); - } - public T getAnnotation(Class class_) { return method.getAnnotation(class_); } @@ -70,21 +60,13 @@ public class Constructor extends AccessibleObject return method.getDeclaredAnnotations(); } - public TypeVariable>[] getTypeParameters() { - throw new UnsupportedOperationException(); - } - - public Type[] getGenericParameterTypes() { - return method.getGenericParameterTypes(); - } - - private static native T make(Class c); + private static native Object make(avian.VMClass c); public T newInstance(Object ... arguments) throws InvocationTargetException, InstantiationException, IllegalAccessException { - T v = make(method.getDeclaringClass()); + T v = (T) make(method.getDeclaringClass().vmClass); method.invoke(v, arguments); return v; } diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 0d015b8254..4638c61990 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,7 +10,10 @@ package java.lang.reflect; +import avian.VMField; import avian.AnnotationInvocationHandler; +import avian.SystemClassLoader; +import avian.Classes; import java.lang.annotation.Annotation; @@ -26,81 +29,90 @@ public class Field extends AccessibleObject { private static final int BooleanField = 8; private static final int ObjectField = 9; - private byte vmFlags; - private byte code; - private short flags; - private short offset; - private byte[] name; - public byte[] spec; - public avian.Addendum addendum; - private Class class_; + private final VMField vmField; + private boolean accessible = true; - private Field() { } + public Field(VMField vmField) { + this.vmField = vmField; + } public boolean isAccessible() { - return (vmFlags & Accessible) != 0; + return accessible; } public void setAccessible(boolean v) { - if (v) vmFlags |= Accessible; else vmFlags &= ~Accessible; + accessible = v; } public Class getDeclaringClass() { - return class_; + return SystemClassLoader.getClass(vmField.class_); } public int getModifiers() { - return flags; + return vmField.flags; } public String getName() { - return new String(name, 0, name.length - 1, false); + return getName(vmField); + } + + public static String getName(VMField vmField) { + return new String(vmField.name, 0, vmField.name.length - 1, false); } public Class getType() { - return Class.forCanonicalName(class_.getClassLoader(), - new String(spec, 0, spec.length - 1, false)); + return Class.forCanonicalName + (vmField.class_.loader, + new String(vmField.spec, 0, vmField.spec.length - 1, false)); } public Object get(Object instance) throws IllegalAccessException { Object target; - if ((flags & Modifier.STATIC) != 0) { - target = class_.staticTable(); - } else if (class_.isInstance(instance)) { + if ((vmField.flags & Modifier.STATIC) != 0) { + target = vmField.class_.staticTable; + } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } - switch (code) { + switch (vmField.code) { case ByteField: - return Byte.valueOf((byte) getPrimitive(target, code, offset)); + return Byte.valueOf + ((byte) getPrimitive(target, vmField.code, vmField.offset)); case BooleanField: - return Boolean.valueOf(getPrimitive(target, code, offset) != 0); + return Boolean.valueOf + (getPrimitive(target, vmField.code, vmField.offset) != 0); case CharField: - return Character.valueOf((char) getPrimitive(target, code, offset)); + return Character.valueOf + ((char) getPrimitive(target, vmField.code, vmField.offset)); case ShortField: - return Short.valueOf((short) getPrimitive(target, code, offset)); + return Short.valueOf + ((short) getPrimitive(target, vmField.code, vmField.offset)); case IntField: - return Integer.valueOf((int) getPrimitive(target, code, offset)); + return Integer.valueOf + ((int) getPrimitive(target, vmField.code, vmField.offset)); case LongField: - return Long.valueOf((int) getPrimitive(target, code, offset)); + return Long.valueOf + ((int) getPrimitive(target, vmField.code, vmField.offset)); case FloatField: return Float.valueOf - (Float.intBitsToFloat((int) getPrimitive(target, code, offset))); + (Float.intBitsToFloat + ((int) getPrimitive(target, vmField.code, vmField.offset))); case DoubleField: return Double.valueOf - (Double.longBitsToDouble(getPrimitive(target, code, offset))); + (Double.longBitsToDouble + (getPrimitive(target, vmField.code, vmField.offset))); case ObjectField: - return getObject(target, offset); + return getObject(target, vmField.offset); default: throw new Error(); @@ -143,56 +155,58 @@ public class Field extends AccessibleObject { throws IllegalAccessException { Object target; - if ((flags & Modifier.STATIC) != 0) { - target = class_.staticTable(); - } else if (class_.isInstance(instance)) { + if ((vmField.flags & Modifier.STATIC) != 0) { + target = vmField.class_.staticTable; + } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } - switch (code) { + switch (vmField.code) { case ByteField: - setPrimitive(target, code, offset, (Byte) value); + setPrimitive(target, vmField.code, vmField.offset, (Byte) value); break; case BooleanField: - setPrimitive(target, code, offset, ((Boolean) value) ? 1 : 0); + setPrimitive + (target, vmField.code, vmField.offset, ((Boolean) value) ? 1 : 0); break; case CharField: - setPrimitive(target, code, offset, (Character) value); + setPrimitive(target, vmField.code, vmField.offset, (Character) value); break; case ShortField: - setPrimitive(target, code, offset, (Short) value); + setPrimitive(target, vmField.code, vmField.offset, (Short) value); break; case IntField: - setPrimitive(target, code, offset, (Integer) value); + setPrimitive(target, vmField.code, vmField.offset, (Integer) value); break; case LongField: - setPrimitive(target, code, offset, (Long) value); + setPrimitive(target, vmField.code, vmField.offset, (Long) value); break; case FloatField: - setPrimitive(target, code, offset, + setPrimitive(target, vmField.code, vmField.offset, Float.floatToRawIntBits((Float) value)); break; case DoubleField: - setPrimitive(target, code, offset, + setPrimitive(target, vmField.code, vmField.offset, Double.doubleToRawLongBits((Double) value)); break; case ObjectField: if (value == null || getType().isInstance(value)) { - setObject(target, offset, value); + setObject(target, vmField.offset, value); } else { throw new IllegalArgumentException - ("needed " + getType() + ", got " + value.getClass().getName() + - " when setting " + class_.getName() + "." + getName()); + ("needed " + getType() + ", got " + + Class.getName(Classes.vmClass(target)) + + " when setting " + Class.getName(vmField.class_) + "." + getName()); } break; @@ -204,15 +218,15 @@ public class Field extends AccessibleObject { private Annotation getAnnotation(Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance - (class_.getClassLoader(), new Class[] { (Class) a[1] }, + (vmField.class_.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmField.addendum.annotationTable != null) { + Object[] table = (Object[]) vmField.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -224,8 +238,8 @@ public class Field extends AccessibleObject { } public Annotation[] getAnnotations() { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmField.addendum.annotationTable != null) { + Object[] table = (Object[]) vmField.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); @@ -240,10 +254,6 @@ public class Field extends AccessibleObject { return getAnnotations(); } - public boolean isEnumConstant() { - throw new UnsupportedOperationException(); - } - private static native long getPrimitive (Object instance, int code, int offset); @@ -255,9 +265,4 @@ public class Field extends AccessibleObject { private static native void setObject (Object instance, int offset, Object value); - - public static class Addendum { - public Object pool; - public Object annotationTable; - } } diff --git a/classpath/java/lang/reflect/Member.java b/classpath/java/lang/reflect/Member.java index cfe00749bb..e5e74042c6 100644 --- a/classpath/java/lang/reflect/Member.java +++ b/classpath/java/lang/reflect/Member.java @@ -19,6 +19,4 @@ public interface Member { public int getModifiers(); public String getName(); - - public boolean isSynthetic(); } diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index 8a8e383cfb..2c0addfaae 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,53 +10,52 @@ package java.lang.reflect; +import avian.VMMethod; import avian.AnnotationInvocationHandler; +import avian.SystemClassLoader; import java.lang.annotation.Annotation; -public class Method extends AccessibleObject - implements Member, GenericDeclaration -{ - private byte vmFlags; - private byte returnCode; - public byte parameterCount; - public byte parameterFootprint; - private short flags; - private short offset; - private int nativeID; - private byte[] name; - public byte[] spec; - public avian.Addendum addendum; - private Class class_; - private Object code; - private long compiled; +public class Method extends AccessibleObject implements Member { + private final VMMethod vmMethod; + private boolean accessible; - private Method() { } + public Method(VMMethod vmMethod) { + this.vmMethod = vmMethod; + } public boolean isAccessible() { - return (vmFlags & Accessible) != 0; + return accessible; } public void setAccessible(boolean v) { - if (v) vmFlags |= Accessible; else vmFlags &= ~Accessible; + accessible = v; } - public static native Method getCaller(); + public static native VMMethod getCaller(); public Class getDeclaringClass() { - return class_; + return SystemClassLoader.getClass(vmMethod.class_); } public int getModifiers() { - return flags; + return vmMethod.flags; } public String getName() { - return new String(name, 0, name.length - 1, false); + return getName(vmMethod); } - String getSpec() { - return new String(spec, 0, spec.length - 1, false); + public static String getName(VMMethod vmMethod) { + return new String(vmMethod.name, 0, vmMethod.name.length - 1, false); + } + + private String getSpec() { + return getSpec(vmMethod); + } + + public static String getSpec(VMMethod vmMethod) { + return new String(vmMethod.spec, 0, vmMethod.spec.length - 1, false); } private static int next(char c, String s, int start) { @@ -67,12 +66,17 @@ public class Method extends AccessibleObject } public Class[] getParameterTypes() { - int count = parameterCount; + return getParameterTypes(vmMethod); + } + + public static Class[] getParameterTypes(VMMethod vmMethod) { + int count = vmMethod.parameterCount; Class[] types = new Class[count]; int index = 0; - String spec = new String(this.spec, 1, this.spec.length - 1, false); + String spec = new String + (vmMethod.spec, 1, vmMethod.spec.length - 1, false); try { for (int i = 0; i < spec.length(); ++i) { @@ -83,7 +87,7 @@ public class Method extends AccessibleObject int start = i + 1; i = next(';', spec, start); String name = spec.substring(start, i).replace('/', '.'); - types[index++] = Class.forName(name, true, class_.getClassLoader()); + types[index++] = Class.forName(name, true, vmMethod.class_.loader); } else if (c == '[') { int start = i; while (spec.charAt(i) == '[') ++i; @@ -92,16 +96,16 @@ public class Method extends AccessibleObject i = next(';', spec, i + 1); String name = spec.substring(start, i).replace('/', '.'); types[index++] = Class.forName - (name, true, class_.getClassLoader()); + (name, true, vmMethod.class_.loader); } else { String name = spec.substring(start, i + 1); types[index++] = Class.forCanonicalName - (class_.getClassLoader(), name); + (vmMethod.class_.loader, name); } } else { String name = spec.substring(i, i + 1); types[index++] = Class.forCanonicalName - (class_.getClassLoader(), name); + (vmMethod.class_.loader, name); } } } catch (ClassNotFoundException e) { @@ -114,38 +118,43 @@ public class Method extends AccessibleObject public Object invoke(Object instance, Object ... arguments) throws InvocationTargetException, IllegalAccessException { - if ((flags & Modifier.STATIC) != 0 || class_.isInstance(instance)) { - if ((flags & Modifier.STATIC) != 0) { + if ((vmMethod.flags & Modifier.STATIC) != 0 + || Class.isInstance(vmMethod.class_, instance)) + { + if ((vmMethod.flags & Modifier.STATIC) != 0) { instance = null; } if (arguments == null) { - if (parameterCount > 0) { + if (vmMethod.parameterCount > 0) { throw new NullPointerException(); } arguments = new Object[0]; } - if (arguments.length == parameterCount) { - return invoke(this, instance, arguments); + if (arguments.length == vmMethod.parameterCount) { + return invoke(vmMethod, instance, arguments); } else { throw new ArrayIndexOutOfBoundsException(); } } else { +// System.out.println +// (getDeclaringClass() + "." + getName() + " flags: " + vmMethod.flags + " vm flags: " + vmMethod.vmFlags + " return code: " + vmMethod.returnCode); throw new IllegalArgumentException(); } } - private static native Object invoke(Method method, Object instance, + private static native Object invoke(VMMethod method, Object instance, Object ... arguments) throws InvocationTargetException, IllegalAccessException; public Class getReturnType() { - for (int i = 0; i < spec.length - 1; ++i) { - if (spec[i] == ')') { + for (int i = 0; i < vmMethod.spec.length - 1; ++i) { + if (vmMethod.spec[i] == ')') { return Class.forCanonicalName - (class_.getClassLoader(), - new String(spec, i + 1, spec.length - i - 2, false)); + (vmMethod.class_.loader, + new String + (vmMethod.spec, i + 1, vmMethod.spec.length - i - 2, false)); } } throw new RuntimeException(); @@ -154,15 +163,15 @@ public class Method extends AccessibleObject private Annotation getAnnotation(Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance - (class_.getClassLoader(), new Class[] { (Class) a[1] }, + (vmMethod.class_.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmMethod.addendum.annotationTable != null) { + Object[] table = (Object[]) vmMethod.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -174,8 +183,8 @@ public class Method extends AccessibleObject } public Annotation[] getAnnotations() { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmMethod.addendum.annotationTable != null) { + Object[] table = (Object[]) vmMethod.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); @@ -189,28 +198,4 @@ public class Method extends AccessibleObject public Annotation[] getDeclaredAnnotations() { return getAnnotations(); } - - public boolean isSynthetic() { - throw new UnsupportedOperationException(); - } - - public Object getDefaultValue() { - throw new UnsupportedOperationException(); - } - - public Type[] getGenericParameterTypes() { - throw new UnsupportedOperationException(); - } - - public Type getGenericReturnType() { - throw new UnsupportedOperationException(); - } - - public Class[] getExceptionTypes() { - throw new UnsupportedOperationException(); - } - - public TypeVariable>[] getTypeParameters() { - throw new UnsupportedOperationException(); - } } diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index aca0351217..2801f96618 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -13,6 +13,14 @@ package java.lang.reflect; import static avian.Stream.write1; import static avian.Stream.write2; import static avian.Stream.write4; +import static avian.Stream.set4; +import static avian.Assembler.*; + +import avian.ConstantPool; +import avian.ConstantPool.PoolEntry; + +import avian.Assembler; +import avian.Assembler.MethodData; import java.util.List; import java.util.ArrayList; @@ -23,38 +31,6 @@ 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; @@ -90,67 +66,6 @@ public class Proxy { return ((Proxy) proxy).h; } - 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, @@ -166,26 +81,37 @@ public class Proxy { write1(out, aload_0); write1(out, getfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;") + 1); write1(out, aload_0); + write1(out, new_); + write2(out, ConstantPool.addClass(pool, "java/lang/reflect/Method") + 1); + write1(out, dup); write1(out, ldc_w); - write2(out, poolAddClass(pool, className) + 1); + write2(out, ConstantPool.addClass(pool, className) + 1); write1(out, getfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "java/lang/Class", - "methodTable", "[Ljava/lang/reflect/Method;") + 1); + "vmClass", "Lavian/VMClass;") + 1); + write1(out, getfield); + write2(out, ConstantPool.addFieldRef + (pool, "avian/VMClass", + "methodTable", "[Lavian/VMMethod;") + 1); write1(out, ldc_w); - write2(out, poolAddInteger(pool, index) + 1); + write2(out, ConstantPool.addInteger(pool, index) + 1); write1(out, aaload); + write1(out, invokespecial); + write2(out, ConstantPool.addMethodRef + (pool, "java/lang/reflect/Method", + "", "(Lavian/VMMethod;)V") + 1); write1(out, ldc_w); - write2(out, poolAddInteger(pool, parameterCount) + 1); + write2(out, ConstantPool.addInteger(pool, parameterCount) + 1); write1(out, anewarray); - write2(out, poolAddClass(pool, "java/lang/Object") + 1); + write2(out, ConstantPool.addClass(pool, "java/lang/Object") + 1); int ai = 0; int si; @@ -193,7 +119,7 @@ public class Proxy { write1(out, dup); write1(out, ldc_w); - write2(out, poolAddInteger(pool, ai) + 1); + write2(out, ConstantPool.addInteger(pool, ai) + 1); switch (spec[si]) { case 'L': @@ -226,7 +152,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;") + 1); break; @@ -236,7 +162,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;") + 1); break; @@ -246,7 +172,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;") + 1); break; @@ -256,7 +182,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;") + 1); break; @@ -266,7 +192,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;") + 1); break; @@ -276,7 +202,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;") + 1); break; @@ -286,7 +212,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;") + 1); ++ ai; @@ -297,7 +223,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;") + 1); ++ ai; @@ -312,7 +238,7 @@ public class Proxy { } write1(out, invokeinterface); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;" @@ -329,56 +255,56 @@ public class Proxy { case 'Z': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Boolean", "booleanValue", "()Z") + 1); write1(out, ireturn); break; case 'B': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Byte", "byteValue", "()B") + 1); write1(out, ireturn); break; case 'C': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Character", "charValue", "()C") + 1); write1(out, ireturn); break; case 'S': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Short", "shortValue", "()S") + 1); write1(out, ireturn); break; case 'I': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Integer", "intValue", "()I") + 1); write1(out, ireturn); break; case 'F': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Float", "floatValue", "()F") + 1); write1(out, freturn); break; case 'J': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Long", "longValue", "()J") + 1); write1(out, lreturn); break; case 'D': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Double", "doubleValue", "()D") + 1); write1(out, dreturn); break; @@ -411,7 +337,7 @@ public class Proxy { write1(out, aload_0); write1(out, aload_1); write1(out, putfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;") + 1); write1(out, return_); @@ -431,78 +357,50 @@ public class Proxy { int[] interfaceIndexes = new int[interfaces.length]; for (int i = 0; i < interfaces.length; ++i) { - interfaceIndexes[i] = poolAddClass(pool, interfaces[i].getName()); + interfaceIndexes[i] = ConstantPool.addClass + (pool, interfaces[i].getName()); } - Map virtualMap = new HashMap(); + Map virtualMap = new HashMap(); for (Class c: interfaces) { - Method[] ivtable = c.virtualTable; + avian.VMMethod[] ivtable = c.vmClass.virtualTable; if (ivtable != null) { - for (Method m: ivtable) { - virtualMap.put(m.getName() + m.getSpec(), m); + for (avian.VMMethod m: ivtable) { + virtualMap.put(Method.getName(m) + Method.getSpec(m), m); } } } MethodData[] methodTable = new MethodData[virtualMap.size() + 1]; { int i = 0; - for (Method m: virtualMap.values()) { + for (avian.VMMethod m: virtualMap.values()) { methodTable[i] = new MethodData - (poolAddUtf8(pool, m.getName()), - poolAddUtf8(pool, m.getSpec()), + (0, + ConstantPool.addUtf8(pool, Method.getName(m)), + ConstantPool.addUtf8(pool, Method.getSpec(m)), makeInvokeCode(pool, name, m.spec, m.parameterCount, m.parameterFootprint, i)); ++ i; } methodTable[i++] = new MethodData - (poolAddUtf8(pool, ""), - poolAddUtf8(pool, "(Ljava/lang/reflect/InvocationHandler;)V"), + (0, + ConstantPool.addUtf8(pool, ""), + ConstantPool.addUtf8 + (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"); + int nameIndex = ConstantPool.addClass(pool, name); + int superIndex = ConstantPool.addClass(pool, "java/lang/reflect/Proxy"); 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 + Assembler.writeClass + (out, pool, nameIndex, superIndex, interfaceIndexes, methodTable); byte[] classData = out.toByteArray(); - return avian.SystemClassLoader.defineClass - (loader, classData, 0, classData.length); + return avian.SystemClassLoader.getClass + (avian.Classes.defineVMClass(loader, classData, 0, classData.length)); } public static Object newProxyInstance(ClassLoader loader, @@ -519,153 +417,4 @@ 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/classpath/java/net/Socket.java b/classpath/java/net/Socket.java index 9fbc1e4523..0f3a39ea6e 100644 --- a/classpath/java/net/Socket.java +++ b/classpath/java/net/Socket.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/net/URLConnection.java b/classpath/java/net/URLConnection.java index ab8f5619e4..0219fbe688 100644 --- a/classpath/java/net/URLConnection.java +++ b/classpath/java/net/URLConnection.java @@ -16,6 +16,9 @@ import java.io.OutputStream; public abstract class URLConnection { protected final URL url; + protected boolean doInput = true; + protected boolean doOutput = false; + protected boolean useCaches = true; protected URLConnection(URL url) { this.url = url; @@ -29,6 +32,8 @@ public abstract class URLConnection { return -1; } + public abstract void connect() throws IOException; + public InputStream getInputStream() throws IOException { throw new UnknownServiceException(); } @@ -36,4 +41,24 @@ public abstract class URLConnection { public OutputStream getOutputStream() throws IOException { throw new UnknownServiceException(); } + + public boolean getDoInput() { + return doInput; + } + + public boolean getDoOutput() { + return doOutput; + } + + public void setDoInput(boolean v) { + doInput = v; + } + + public void setDoOutput(boolean v) { + doInput = v; + } + + public void setUseCaches(boolean v) { + useCaches = v; + } } diff --git a/classpath/java/nio/channels/Channels.java b/classpath/java/nio/channels/Channels.java index 3f7fe63eaa..849a16dffc 100644 --- a/classpath/java/nio/channels/Channels.java +++ b/classpath/java/nio/channels/Channels.java @@ -24,6 +24,14 @@ public class Channels { return new MyOutputStream(channel); } + public static ReadableByteChannel newChannel(InputStream stream) { + return new InputStreamChannel(stream); + } + + public static WritableByteChannel newChannel(OutputStream stream) { + return new OutputStreamChannel(stream); + } + private static class MyInputStream extends InputStream { private final ReadableByteChannel channel; @@ -72,4 +80,63 @@ public class Channels { channel.close(); } } + + private static class InputStreamChannel implements ReadableByteChannel { + private InputStream stream; + + public InputStreamChannel(InputStream stream) { + this.stream = stream; + } + + public void close() throws IOException { + if (stream != null) { + stream.close(); + stream = null; + } + } + + public boolean isOpen() { + return stream != null; + } + + public int read(ByteBuffer b) throws IOException { + int c = stream.read + (b.array(), b.arrayOffset() + b.position(), b.remaining()); + + if (c > 0) { + b.position(b.position() + c); + } + + return c; + } + } + + private static class OutputStreamChannel implements WritableByteChannel { + private OutputStream stream; + + public OutputStreamChannel(OutputStream stream) { + this.stream = stream; + } + + public void close() throws IOException { + if (stream != null) { + stream.close(); + stream = null; + } + } + + public boolean isOpen() { + return stream != null; + } + + public int write(ByteBuffer b) throws IOException { + stream.write(b.array(), b.arrayOffset() + b.position(), b.remaining()); + + int c = b.remaining(); + + b.position(b.limit()); + + return c; + } + } } diff --git a/classpath/java/nio/channels/GatheringByteChannel.java b/classpath/java/nio/channels/GatheringByteChannel.java new file mode 100644 index 0000000000..5696f5e980 --- /dev/null +++ b/classpath/java/nio/channels/GatheringByteChannel.java @@ -0,0 +1,20 @@ +/* Copyright (c) 2011, 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.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public interface GatheringByteChannel extends WritableByteChannel { + public long write(ByteBuffer[] srcs) throws IOException; + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; +} diff --git a/classpath/java/nio/channels/SelectableChannel.java b/classpath/java/nio/channels/SelectableChannel.java index 7cec3b69aa..734bce9fc8 100644 --- a/classpath/java/nio/channels/SelectableChannel.java +++ b/classpath/java/nio/channels/SelectableChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -19,6 +19,8 @@ public abstract class SelectableChannel implements Channel { abstract int socketFD(); + abstract void handleReadyOps(int ops); + public abstract SelectableChannel configureBlocking(boolean v) throws IOException; diff --git a/classpath/java/nio/channels/Selector.java b/classpath/java/nio/channels/Selector.java index 942357c773..f3be166d8b 100644 --- a/classpath/java/nio/channels/Selector.java +++ b/classpath/java/nio/channels/Selector.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index c8a691c5c5..53e6eec36d 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -32,6 +32,10 @@ public class ServerSocketChannel extends SelectableChannel { return channel.socketFD(); } + public void handleReadyOps(int ops) { + channel.handleReadyOps(ops); + } + public SelectableChannel configureBlocking(boolean v) throws IOException { return channel.configureBlocking(v); } @@ -40,7 +44,7 @@ public class ServerSocketChannel extends SelectableChannel { channel.close(); } - public SocketChannel accept() throws Exception { + public SocketChannel accept() throws IOException { SocketChannel c = new SocketChannel(); c.socket = doAccept(); c.connected = true; diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index db20896f1c..65c9768d88 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -18,12 +18,13 @@ import java.net.Socket; import java.nio.ByteBuffer; public class SocketChannel extends SelectableChannel - implements ReadableByteChannel, WritableByteChannel + implements ReadableByteChannel, GatheringByteChannel { public static final int InvalidSocket = -1; int socket = InvalidSocket; boolean connected = false; + boolean readyToConnect = false; boolean blocking = true; public static SocketChannel open() throws IOException { @@ -66,8 +67,23 @@ public class SocketChannel extends SelectableChannel public boolean finishConnect() throws IOException { if (! connected) { - connected = natFinishConnect(socket); + while (! readyToConnect) { + Selector selector = Selector.open(); + SelectionKey key = register(selector, SelectionKey.OP_CONNECT, null); + + if (blocking) { + selector.select(); + } else { + selector.selectNow(); + break; + } + } + + natFinishConnect(socket); + + connected = readyToConnect; } + return connected; } @@ -117,6 +133,23 @@ public class SocketChannel extends SelectableChannel return w; } + public long write(ByteBuffer[] srcs) throws IOException { + return write(srcs, 0, srcs.length); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + long total = 0; + for (int i = offset; i < offset + length; ++i) { + total += write(srcs[i]); + if (srcs[i].hasRemaining()) { + return total; + } + } + return total; + } + private void closeSocket() { natCloseSocket(socket); } @@ -125,6 +158,12 @@ public class SocketChannel extends SelectableChannel return socket; } + void handleReadyOps(int ops) { + if ((ops & SelectionKey.OP_CONNECT) != 0) { + readyToConnect = true; + } + } + public class Handle extends Socket { public void setTcpNoDelay(boolean on) throws SocketException { natSetTcpNoDelay(socket, on); @@ -139,7 +178,7 @@ public class SocketChannel extends SelectableChannel private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected) throws IOException; - private static native boolean natFinishConnect(int socket) + private static native void natFinishConnect(int socket) throws IOException; private static native int natRead(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; diff --git a/classpath/java/nio/channels/SocketSelector.java b/classpath/java/nio/channels/SocketSelector.java index 8ad7bbafd8..2482d0f180 100644 --- a/classpath/java/nio/channels/SocketSelector.java +++ b/classpath/java/nio/channels/SocketSelector.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -96,6 +96,7 @@ class SocketSelector extends Selector { int ready = natUpdateReadySet(socket, key.interestOps(), state); key.readyOps(ready); if (ready != 0) { + c.handleReadyOps(ready); selectedKeys.add(key); } } diff --git a/classpath/java/security/AccessController.java b/classpath/java/security/AccessController.java index 804dfe70a7..b219e450ae 100644 --- a/classpath/java/security/AccessController.java +++ b/classpath/java/security/AccessController.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008, 2010 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -21,5 +21,9 @@ public class AccessController { public static Object doPrivileged (PrivilegedAction action) { return action.run(); } + + public static void checkPermission(Permission perm) throws AccessControlException { + + } } diff --git a/classpath/java/security/AllPermission.java b/classpath/java/security/AllPermission.java index 6bc99d53e8..4a18ebbddf 100644 --- a/classpath/java/security/AllPermission.java +++ b/classpath/java/security/AllPermission.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,4 +10,10 @@ package java.security; -public class AllPermission extends Permission { } +public class AllPermission extends Permission { + public AllPermission() { + super(""); + } + + +} diff --git a/classpath/java/lang/reflect/TypeVariable.java b/classpath/java/security/BasicPermission.java similarity index 56% rename from classpath/java/lang/reflect/TypeVariable.java rename to classpath/java/security/BasicPermission.java index 65d531d6bf..756e70139d 100644 --- a/classpath/java/lang/reflect/TypeVariable.java +++ b/classpath/java/security/BasicPermission.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,12 +8,12 @@ There is NO WARRANTY for this software. See license.txt for details. */ -package java.lang.reflect; +package java.security; + +public class BasicPermission extends Permission { + + public BasicPermission(String name) { + super(name); + } -public interface TypeVariable - extends Type -{ - public Type[] getBounds(); - public T getGenericDeclaration(); - public String getName(); } diff --git a/classpath/java/security/Permission.java b/classpath/java/security/Permission.java index bc6c438e18..f622253976 100644 --- a/classpath/java/security/Permission.java +++ b/classpath/java/security/Permission.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -11,6 +11,22 @@ package java.security; public abstract class Permission { + + protected String name; + + public Permission(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + '['+name+']'; + } + public PermissionCollection newPermissionCollection() { return null; } diff --git a/classpath/java/util/Formatter.java b/classpath/java/security/SecurityPermission.java similarity index 51% rename from classpath/java/util/Formatter.java rename to classpath/java/security/SecurityPermission.java index 6acf9b5fba..22660f6111 100644 --- a/classpath/java/util/Formatter.java +++ b/classpath/java/security/SecurityPermission.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,16 +8,12 @@ There is NO WARRANTY for this software. See license.txt for details. */ -package java.util; +package java.security; -public class Formatter { - private final Locale locale; +public class SecurityPermission extends BasicPermission { - public Formatter(Locale locale) { - this.locale = locale; + public SecurityPermission(String name) { + super(name); } - public Formatter format(String format, Object ... args) { - throw new UnsupportedOperationException(); - } } diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index 8206988d90..dc607189d9 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -148,5 +148,11 @@ public class Arrays { array[i] = value; } } + + public static void fill(T[] array, T value) { + for (int i=0;i Enumeration enumeration(Collection c) { + return new IteratorEnumeration (c.iterator()); + } + public static Comparator reverseOrder(Comparator cmp) { + return new ReverseComparator(cmp); + } + static class IteratorEnumeration implements Enumeration { private final Iterator it; @@ -375,4 +384,19 @@ public class Collections { it.remove(); } } + + private static final class ReverseComparator implements Comparator { + + Comparator cmp; + + public ReverseComparator(Comparator cmp) { + this.cmp = cmp; + } + + public int compare(T o1, T o2) { + return - cmp.compare(o1, o2); + } + + } + } diff --git a/classpath/java/util/ConcurrentModificationException.java b/classpath/java/util/ConcurrentModificationException.java new file mode 100644 index 0000000000..28fe2bf7ee --- /dev/null +++ b/classpath/java/util/ConcurrentModificationException.java @@ -0,0 +1,47 @@ +/* Copyright (c) 2010, 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.util; + +/** + * @author zsombor + * + */ +public class ConcurrentModificationException extends RuntimeException { + + /** + * @param message + * @param cause + */ + public ConcurrentModificationException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + */ + public ConcurrentModificationException(String message) { + super(message); + } + + /** + * @param cause + */ + public ConcurrentModificationException(Throwable cause) { + super(cause); + } + + /** + * + */ + public ConcurrentModificationException() { + } + +} diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index c0a8a2474a..2931b52300 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -149,16 +149,17 @@ public class HashMap implements Map { } public boolean containsValue(Object value) { - if (array != null) { - int index = array.length - 1; - for (Cell c = array[index]; c != null; c = c.next()) { - if (helper.equal(value, c.getValue())) { - return true; + if (array != null) { + for (int i = 0; i < array.length; ++i) { + for (Cell c = array[i]; c != null; c = c.next()) { + if (helper.equal(value, c.getValue())) { + return true; + } } } } - return false; + return false; } public V get(Object key) { @@ -269,8 +270,10 @@ public class HashMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } public HashMap.Cell next() { @@ -448,10 +451,12 @@ public class HashMap implements Map { public Entry next() { if (hasNext()) { - if (currentCell != null && currentCell.next() != null) { - previousCell = currentCell; - } else { - previousCell = null; + if (currentCell != null) { + if (currentCell.next() != null) { + previousCell = currentCell; + } else { + previousCell = null; + } } currentCell = nextCell; @@ -488,6 +493,7 @@ public class HashMap implements Map { } } currentCell = null; + -- size; } else { throw new IllegalStateException(); } diff --git a/classpath/java/util/Map.java b/classpath/java/util/Map.java index 5b58bbb4f9..36f79a07f1 100644 --- a/classpath/java/util/Map.java +++ b/classpath/java/util/Map.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -40,6 +40,6 @@ public interface Map { public V getValue(); - public void setValue(V value); + public V setValue(V value); } } diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index b67d783c67..c37de95878 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -14,10 +14,15 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.IOException; +import java.io.Reader; public class Properties extends Hashtable { public void load(InputStream in) throws IOException { - new Parser().parse(in, this); + new InputStreamParser(in).parse(this); + } + + public void load(Reader reader) throws IOException { + new ReaderParser(reader).parse(this); } public void store(OutputStream out, String comment) throws IOException { @@ -48,8 +53,12 @@ public class Properties extends Hashtable { public Object setProperty(String key, String value) { return put(key, value); } + + public Enumeration propertyNames() { + return keys(); + } - private static class Parser { + private abstract static class Parser { private StringBuilder key = null; private StringBuilder value = null; private StringBuilder current = null; @@ -75,13 +84,15 @@ public class Properties extends Hashtable { key = value = current = null; } - private void parse(InputStream in, Map map) + abstract int readCharacter() throws IOException; + + void parse(Map map) throws IOException { boolean escaped = false; int c; - while ((c = in.read()) != -1) { + while ((c = readCharacter()) != -1) { if (c == '\\') { if (escaped) { escaped = false; @@ -94,7 +105,7 @@ public class Properties extends Hashtable { case '#': case '!': if (key == null) { - while ((c = in.read()) != -1 && c != '\n'); + while ((c = readCharacter()) != -1 && c != '\n'); } else { append(c); } @@ -162,4 +173,32 @@ public class Properties extends Hashtable { finishLine(map); } } + + static class InputStreamParser extends Parser { + InputStream in; + + + public InputStreamParser(InputStream in) { + this.in = in; + } + + @Override + int readCharacter() throws IOException { + return in.read(); + } + } + + static class ReaderParser extends Parser { + Reader in; + + public ReaderParser(Reader in) { + this.in = in; + } + + @Override + int readCharacter() throws IOException { + return in.read(); + } + } + } diff --git a/classpath/java/util/ResourceBundle.java b/classpath/java/util/ResourceBundle.java index 97bde9b80c..a07d693af4 100644 --- a/classpath/java/util/ResourceBundle.java +++ b/classpath/java/util/ResourceBundle.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -94,13 +94,12 @@ public abstract class ResourceBundle { } public static ResourceBundle getBundle(String name, Locale locale) { - return getBundle(name, locale, - Method.getCaller().getDeclaringClass().getClassLoader()); + return getBundle(name, locale, Method.getCaller().class_.loader); } public static ResourceBundle getBundle(String name) { - return getBundle(name, Locale.getDefault(), - Method.getCaller().getDeclaringClass().getClassLoader()); + return getBundle + (name, Locale.getDefault(), Method.getCaller().class_.loader); } public Object getObject(String key) { diff --git a/classpath/java/util/TreeMap.java b/classpath/java/util/TreeMap.java index 686e9ffda3..6100dbce80 100644 --- a/classpath/java/util/TreeMap.java +++ b/classpath/java/util/TreeMap.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -112,9 +112,12 @@ public class TreeMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } + } private class KeySet implements Set { diff --git a/classpath/java/util/TreeSet.java b/classpath/java/util/TreeSet.java index 5a1d4a8c47..16f291a134 100644 --- a/classpath/java/util/TreeSet.java +++ b/classpath/java/util/TreeSet.java @@ -33,6 +33,14 @@ public class TreeSet extends AbstractSet implements Collection { } }); } + + public TreeSet(Collection collection) { + this(); + + for (T item: collection) { + add(item); + } + } public Iterator iterator() { return new MyIterator(set.first()); diff --git a/classpath/java/util/WeakHashMap.java b/classpath/java/util/WeakHashMap.java index d8fdbc7968..862de6e7e1 100644 --- a/classpath/java/util/WeakHashMap.java +++ b/classpath/java/util/WeakHashMap.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -114,8 +114,10 @@ public class WeakHashMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } public HashMap.Cell next() { diff --git a/classpath/java/util/logging/Logger.java b/classpath/java/util/logging/Logger.java index d06a7bb00a..a1a64de307 100644 --- a/classpath/java/util/logging/Logger.java +++ b/classpath/java/util/logging/Logger.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -107,15 +107,15 @@ public class Logger { return logger.getLevel(); } - private void log(Level level, Method caller, String message, + private void log(Level level, avian.VMMethod caller, String message, Throwable exception) { if (level.intValue() < getEffectiveLevel().intValue()) { return; } LogRecord r = new LogRecord - (name, caller == null ? "" : caller.getName(), level, message, - exception); + (name, caller == null ? "" : Method.getName(caller), level, + message, exception); publish(r); } diff --git a/classpath/java/util/regex/Matcher.java b/classpath/java/util/regex/Matcher.java index 2296b4bf9d..99f9d9daad 100644 --- a/classpath/java/util/regex/Matcher.java +++ b/classpath/java/util/regex/Matcher.java @@ -36,18 +36,6 @@ public class Matcher { } } - public boolean requireEnd() { - throw new UnsupportedOperationException(); - } - - public boolean hitEnd() { - throw new UnsupportedOperationException(); - } - - public boolean lookingAt() { - throw new UnsupportedOperationException(); - } - public Matcher reset() { return reset(input); } @@ -63,26 +51,6 @@ public class Matcher { return start; } - public int start(int group) { - throw new UnsupportedOperationException(); - } - - public Pattern pattern() { - throw new UnsupportedOperationException(); - } - - public Matcher region(int start, int end) { - throw new UnsupportedOperationException(); - } - - public int regionEnd() { - throw new UnsupportedOperationException(); - } - - public int regionStart() { - throw new UnsupportedOperationException(); - } - public String replaceAll(String replacement) { return replace(replacement, Integer.MAX_VALUE); } @@ -124,10 +92,6 @@ public class Matcher { return end; } - public int end(int group) { - throw new UnsupportedOperationException(); - } - public boolean find() { return find(end); } @@ -143,16 +107,4 @@ public class Matcher { return false; } } - - public int groupCount() { - throw new UnsupportedOperationException(); - } - - public String group() { - throw new UnsupportedOperationException(); - } - - public String group(int group) { - throw new UnsupportedOperationException(); - } } diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java index a3ec90c676..bb9a6e26f8 100644 --- a/classpath/java/util/regex/Pattern.java +++ b/classpath/java/util/regex/Pattern.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -92,10 +92,6 @@ public class Pattern { return pattern; } - public static String quote(String s) { - throw new UnsupportedOperationException(); - } - public String[] split(CharSequence input) { return split(input, 0); } @@ -115,23 +111,34 @@ public class Pattern { List list = new LinkedList(); int index = 0; int trailing = 0; - while (index < input.length() && list.size() < limit) { - int i = indexOf(input, pattern, index); + int patternLength = pattern.length(); + while (index < input.length() && list.size() < limit - 1) { + int i; + if (patternLength == 0) { + if (list.size() == 0) { + i = 0; + } else { + i = index + 1; + } + } else { + i = indexOf(input, pattern, index); + } + if (i >= 0) { - if (i == index) { + if (patternLength != 0 && i == index) { ++ trailing; } else { trailing = 0; } list.add(input.subSequence(index, i)); - index = i + pattern.length(); + index = i + patternLength; } else { break; } } - if (strip && index == input.length()) { + if (strip && index > 0 && index == input.length()) { ++ trailing; } else { trailing = 0; diff --git a/classpath/java/util/zip/InflaterInputStream.java b/classpath/java/util/zip/InflaterInputStream.java index 1548c7eff4..a8cbeca173 100644 --- a/classpath/java/util/zip/InflaterInputStream.java +++ b/classpath/java/util/zip/InflaterInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/sun/reflect/ConstantPool.java b/classpath/sun/reflect/ConstantPool.java new file mode 100644 index 0000000000..582ce67607 --- /dev/null +++ b/classpath/sun/reflect/ConstantPool.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2010, 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 sun.reflect; + +public class ConstantPool { } diff --git a/license.txt b/license.txt index 3596960926..6e84838c86 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2008-2009, Avian Contributors +Copyright (c) 2008-2010, 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 diff --git a/makefile b/makefile index a8b450a7ed..c42fc35937 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ MAKEFLAGS = -s name = avian -version = 0.3 +version = 0.4 build-arch := $(shell uname -m | sed 's/^i.86$$/i386/' | sed 's/^arm.*$$/arm/') ifeq (Power,$(filter Power,$(build-arch))) @@ -39,37 +39,76 @@ endif ifeq ($(continuations),true) options := $(options)-continuations endif -ifdef gnu - options := $(options)-gnu - gnu-sources = $(src)/gnu.cpp - gnu-jar = $(gnu)/share/classpath/glibj.zip - gnu-libraries = \ - $(gnu)/lib/classpath/libjavaio.a \ - $(gnu)/lib/classpath/libjavalang.a \ - $(gnu)/lib/classpath/libjavalangreflect.a \ - $(gnu)/lib/classpath/libjavamath.a \ - $(gnu)/lib/classpath/libjavanet.a \ - $(gnu)/lib/classpath/libjavanio.a \ - $(gnu)/lib/classpath/libjavautil.a - gnu-object-dep = $(build)/gnu-object.dep - gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU - gnu-lflags = -lgmp - gnu-objects = $(shell find $(build)/gnu-objects -name "*.o") -endif root := $(shell (cd .. && pwd)) -build = build -native-build = $(build)/$(platform)-$(arch)$(options) +build = build/$(platform)-$(arch)$(options) classpath-build = $(build)/classpath test-build = $(build)/test src = src -classpath = classpath +classpath-src = classpath test = test -ifdef gnu - avian-classpath-build = $(build)/avian-classpath -else - avian-classpath-build = $(classpath-build) +classpath = avian + +test-executable = $(executable) +boot-classpath = $(classpath-build) +embed-prefix = /avian-embedded + +native-path = echo + +ifeq ($(build-platform),cygwin) + native-path = cygpath -m +endif + +path-separator = : + +ifneq (,$(filter mingw32 cygwin,$(build-platform))) + path-separator = ; +endif + +library-path-variable = LD_LIBRARY_PATH + +ifeq ($(build-platform),darwin) + library-path-variable = DYLD_LIBRARY_PATH +endif + +ifneq ($(openjdk),) + openjdk-arch = $(arch) + ifeq ($(arch),x86_64) + openjdk-arch = amd64 + endif + + ifneq ($(openjdk-src),) + include openjdk-src.mk + options := $(options)-openjdk-src + classpath-objects = $(openjdk-objects) $(openjdk-local-objects) + classpath-cflags = -DAVIAN_OPENJDK_SRC -DBOOT_JAVAHOME + openjdk-jar-dep = $(build)/openjdk-jar.dep + classpath-jar-dep = $(openjdk-jar-dep) + javahome = $(embed-prefix)/javahomeJar + javahome-files = lib/zi lib/currency.data + ifeq ($(platform),windows) + javahome-files += lib/tzmappings + endif + javahome-object = $(build)/javahome-jar.o + boot-javahome-object = $(build)/boot-javahome.o + else + options := $(options)-openjdk + test-executable = $(executable-dynamic) + library-path = \ + $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) + javahome = "$$($(native-path) "$(openjdk)/jre")" + endif + + classpath = openjdk + boot-classpath := "$(boot-classpath)$(path-separator)$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" + build-javahome = $(openjdk)/jre +endif + +ifeq ($(classpath),avian) + jni-sources := $(shell find $(classpath-src) -name '*.cpp') + jni-objects = $(call cpp-objects,$(jni-sources),$(classpath-src),$(build)) + classpath-objects = $(jni-objects) endif input = List @@ -79,12 +118,12 @@ build-cc = gcc mflag = ifneq ($(platform),darwin) - ifeq ($(arch),i386) - mflag = -m32 - endif - ifeq ($(arch),x86_64) - mflag = -m64 - endif + ifeq ($(arch),i386) + mflag = -m32 + endif + ifeq ($(arch),x86_64) + mflag = -m64 + endif endif cxx = $(build-cxx) $(mflag) @@ -97,6 +136,7 @@ vg = nice valgrind --num-callers=32 --db-attach=yes --freelist-vol=100000000 vg += --leak-check=full --suppressions=valgrind.supp db = gdb --args javac = "$(JAVA_HOME)/bin/javac" +javah = "$(JAVA_HOME)/bin/javah" jar = "$(JAVA_HOME)/bin/jar" strip = strip strip-all = --strip-all @@ -109,22 +149,36 @@ rdynamic = -rdynamic warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ -Wno-non-virtual-dtor -common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ - "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \ +common-cflags = $(warnings) -fno-rtti -fno-exceptions \ + "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS $(gnu-cflags) + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" + +ifneq (,$(filter i386 x86_64,$(arch))) + ifeq ($(use-frame-pointer),true) + common-cflags += -fno-omit-frame-pointer -DAVIAN_USE_FRAME_POINTER + asmflags += -DAVIAN_USE_FRAME_POINTER + endif +endif build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread +converter-cflags = -D__STDC_CONSTANT_MACROS + cflags = $(build-cflags) -common-lflags = -lm -lz $(gnu-lflags) +common-lflags = -lm -lz $(classpath-lflags) -build-lflags = +build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl +version-script-flag = -Wl,--version-script=openjdk.ld + +build-system = posix + system = posix asm = x86 @@ -135,7 +189,7 @@ so-suffix = .so shared = -shared -native-path = echo +openjdk-extra-cflags = -fvisibility=hidden ifeq ($(arch),i386) pointer-size = 4 @@ -145,34 +199,69 @@ ifeq ($(arch),powerpc) pointer-size = 4 endif ifeq ($(arch),arm) - asm = arm - pointer-size = 4 + asm = arm + pointer-size = 4 + cflags += -marm -Wno-psabi + + ifneq ($(arch),$(build-arch)) + cxx = arm-linux-gnueabi-g++ + cc = arm-linux-gnueabi-gcc + ar = arm-linux-gnueabi-ar + ranlib = arm-linux-gnueabi-ranlib + strip = arm-linux-gnueabi-strip + endif endif ifeq ($(platform),darwin) - build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) - lflags = $(common-lflags) -ldl -framework CoreFoundation -framework CoreServices + ifneq ($(build-platform),darwin) + cxx = i686-apple-darwin8-g++ $(mflag) + cc = i686-apple-darwin8-gcc $(mflag) + ar = i686-apple-darwin8-ar + ranlib = i686-apple-darwin8-ranlib + strip = i686-apple-darwin8-strip + extra-cflags = -I$(JAVA_HOME)/include/linux + else + build-lflags += -framework CoreFoundation + endif + + build-cflags = $(common-cflags) $(extra-cflags) -fPIC -fvisibility=hidden \ + -I$(src) + version-script-flag = + lflags = $(common-lflags) -ldl -framework CoreFoundation \ + -framework CoreServices ifeq ($(bootimage),true) bootimage-lflags = -Wl,-segprot,__RWX,rwx,rwx endif rdynamic = strip-all = -S -x - so-suffix = .jnilib + so-suffix = .dylib shared = -dynamiclib ifeq ($(arch),powerpc) - cflags += -arch ppc - asmflags += -arch ppc - lflags += -arch ppc + ifneq (,$(filter i386 x86_64,$(build-arch))) + converter-cflags += -DOPPOSITE_ENDIAN + endif + openjdk-extra-cflags += -arch ppc -mmacosx-version-min=10.4 + cflags += -arch ppc -mmacosx-version-min=10.4 + asmflags += -arch ppc -mmacosx-version-min=10.4 + lflags += -arch ppc -mmacosx-version-min=10.4 endif ifeq ($(arch),i386) - cflags += -arch i386 - asmflags += -arch i386 - lflags += -arch i386 + ifeq ($(build-arch),powerpc) + converter-cflags += -DOPPOSITE_ENDIAN + endif + openjdk-extra-cflags += -arch i386 -mmacosx-version-min=10.4 + cflags += -arch i386 -mmacosx-version-min=10.4 + asmflags += -arch i386 -mmacosx-version-min=10.4 + lflags += -arch i386 -mmacosx-version-min=10.4 endif ifeq ($(arch),x86_64) + ifeq ($(build-arch),powerpc) + converter-cflags += -DOPPOSITE_ENDIAN + endif + openjdk-extra-cflags += -arch x86_64 cflags += -arch x86_64 asmflags += -arch x86_64 lflags += -arch x86_64 @@ -183,6 +272,8 @@ ifeq ($(platform),windows) inc = "$(root)/win32/include" lib = "$(root)/win32/lib" + embed-prefix = c:/avian-embedded + system = windows so-prefix = @@ -193,21 +284,25 @@ ifeq ($(platform),windows) cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 ifeq (,$(filter mingw32 cygwin,$(build-platform))) - cxx = i586-mingw32msvc-g++ - cc = i586-mingw32msvc-gcc - dlltool = i586-mingw32msvc-dlltool - ar = i586-mingw32msvc-ar - ranlib = i586-mingw32msvc-ranlib - strip = i586-mingw32msvc-strip + openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive + cxx = x86_64-w64-mingw32-g++ -m32 + cc = x86_64-w64-mingw32-gcc -m32 + dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 + ar = x86_64-w64-mingw32-ar + ranlib = x86_64-w64-mingw32-ranlib + strip = x86_64-w64-mingw32-strip --strip-all else + build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" - build-cflags = $(common-cflags) -I$(src) -mthreads + build-cflags = $(common-cflags) -I$(src) -I$(inc) -mthreads + openjdk-extra-cflags = + build-lflags = -L$(lib) $(common-lflags) ifeq ($(build-platform),cygwin) build-lflags += -mno-cygwin build-cflags += -mno-cygwin + openjdk-extra-cflags += -mno-cygwin lflags += -mno-cygwin cflags += -mno-cygwin - native-path = cygpath -m endif endif @@ -224,32 +319,34 @@ ifeq ($(platform),windows) endif ifeq ($(mode),debug) - cflags += -O0 -g3 + optimization-cflags = -O0 -g3 strip = : endif ifeq ($(mode),debug-fast) - cflags += -O0 -g3 -DNDEBUG + optimization-cflags = -O0 -g3 -DNDEBUG strip = : endif ifeq ($(mode),stress) - cflags += -O0 -g3 -DVM_STRESS + optimization-cflags = -O0 -g3 -DVM_STRESS strip = : endif ifeq ($(mode),stress-major) - cflags += -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR + optimization-cflags = -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR strip = : endif ifeq ($(mode),fast) - cflags += -O3 -g3 -DNDEBUG + optimization-cflags = -O3 -g3 -DNDEBUG endif ifeq ($(mode),small) - cflags += -Os -g3 -DNDEBUG + optimization-cflags = -Os -g3 -DNDEBUG endif +cflags += $(optimization-cflags) + ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: - cflags += -march=i486 + cflags += -march=i586 endif endif @@ -266,10 +363,10 @@ ifdef msvc ld = "$(msvc)/BIN/link.exe" mt = "mt.exe" cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ - -DUSE_ATOMIC_OPERATIONS \ - -Fd$(native-build)/$(name).pdb -I"$(zlib)/include" -I$(src) \ - -I"$(native-build)" -I"$(windows-java-home)/include" \ - -I"$(windows-java-home)/include/win32" + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ + -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \ + -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" shared = -dll lflags = -nologo -LIBPATH:"$(zlib)/lib" -DEFAULTLIB:ws2_32 \ -DEFAULTLIB:zlib -MANIFEST -debug @@ -297,36 +394,15 @@ cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x))) asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(3)/%-asm.o,$(x))) java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x))) -jni-sources := $(shell find $(classpath) -name '*.cpp') -jni-objects = $(call cpp-objects,$(jni-sources),$(classpath),$(native-build)) - generated-code = \ - $(native-build)/type-enums.cpp \ - $(native-build)/type-declarations.cpp \ - $(native-build)/type-constructors.cpp \ - $(native-build)/type-initializations.cpp \ - $(native-build)/type-java-initializations.cpp + $(build)/type-enums.cpp \ + $(build)/type-declarations.cpp \ + $(build)/type-constructors.cpp \ + $(build)/type-initializations.cpp \ + $(build)/type-java-initializations.cpp \ + $(build)/type-name-initializations.cpp -vm-depends = \ - $(generated-code) \ - $(src)/allocator.h \ - $(src)/common.h \ - $(src)/system.h \ - $(src)/heap.h \ - $(src)/finder.h \ - $(src)/processor.h \ - $(src)/process.h \ - $(src)/stream.h \ - $(src)/constants.h \ - $(src)/jnienv.h \ - $(src)/machine.h \ - $(src)/util.h \ - $(src)/zone.h \ - $(src)/assembler.h \ - $(src)/compiler.h \ - $(src)/$(asm).h \ - $(src)/heapwalk.h \ - $(src)/bootimage.h +vm-depends := $(generated-code) $(wildcard $(src)/*.h) vm-sources = \ $(src)/$(system).cpp \ @@ -335,18 +411,14 @@ vm-sources = \ $(src)/util.cpp \ $(src)/heap.cpp \ $(src)/$(process).cpp \ + $(src)/classpath-$(classpath).cpp \ $(src)/builtin.cpp \ $(src)/jnienv.cpp \ - $(src)/process.cpp \ - $(gnu-sources) + $(src)/process.cpp vm-asm-sources = $(src)/$(asm).S ifeq ($(process),compile) - vm-depends += \ - $(src)/compiler.h \ - $(src)/vector.h - vm-sources += \ $(src)/compiler.cpp \ $(src)/$(asm).cpp @@ -354,13 +426,13 @@ ifeq ($(process),compile) vm-asm-sources += $(src)/compile-$(asm).S endif -vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(native-build)) -vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build)) +vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(build)) +vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(build)) vm-objects = $(vm-cpp-objects) $(vm-asm-objects) heapwalk-sources = $(src)/heapwalk.cpp heapwalk-objects = \ - $(call cpp-objects,$(heapwalk-sources),$(src),$(native-build)) + $(call cpp-objects,$(heapwalk-sources),$(src),$(build)) ifeq ($(heapdump),true) vm-sources += $(src)/heapdump.cpp @@ -379,12 +451,11 @@ endif bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-objects = \ - $(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build)) -bootimage-generator = \ - $(build)/$(bootimage-platform)-$(build-arch)$(options)/bootimage-generator + $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) +bootimage-generator = $(build)/bootimage-generator -bootimage-bin = $(native-build)/bootimage.bin -bootimage-object = $(native-build)/bootimage-bin.o +bootimage-bin = $(build)/bootimage.bin +bootimage-object = $(build)/bootimage-bin.o ifeq ($(bootimage),true) ifneq ($(build-arch),$(arch)) @@ -398,78 +469,87 @@ $(error "bootimage cross-builds not yet supported") endif vm-classpath-object = $(bootimage-object) - cflags += -DBOOT_IMAGE=\"bootimageBin\" + cflags += -DBOOT_IMAGE=\"bootimageBin\" -DAVIAN_CLASSPATH=\"\" else vm-classpath-object = $(classpath-object) - cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" + cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" \ + -DAVIAN_CLASSPATH=\"[classpathJar]\" endif driver-source = $(src)/main.cpp -driver-object = $(native-build)/main.o -driver-dynamic-object = $(native-build)/main-dynamic.o +driver-object = $(build)/main.o +driver-dynamic-objects = \ + $(build)/main-dynamic.o \ + $(build)/$(system).o \ + $(build)/finder.o boot-source = $(src)/boot.cpp -boot-object = $(native-build)/boot.o +boot-object = $(build)/boot.o -generator-headers = $(src)/constants.h -generator-sources = $(src)/type-generator.cpp +generator-depends := $(wildcard $(src)/*.h) +generator-sources = \ + $(src)/type-generator.cpp \ + $(src)/$(build-system).cpp \ + $(src)/finder.cpp +generator-cpp-objects = \ + $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%-build.o,$(x))) generator-objects = \ - $(call cpp-objects,$(generator-sources),$(src),$(native-build)) -generator = $(native-build)/generator + $(call generator-cpp-objects,$(generator-sources),$(src),$(build)) +generator = $(build)/generator converter-objects = \ - $(native-build)/binaryToObject-main.o \ - $(native-build)/binaryToObject-elf64.o \ - $(native-build)/binaryToObject-elf32.o \ - $(native-build)/binaryToObject-mach-o64.o \ - $(native-build)/binaryToObject-mach-o32.o \ - $(native-build)/binaryToObject-pe.o -converter = $(native-build)/binaryToObject + $(build)/binaryToObject-main.o \ + $(build)/binaryToObject-elf64.o \ + $(build)/binaryToObject-elf32.o \ + $(build)/binaryToObject-mach-o64.o \ + $(build)/binaryToObject-mach-o32.o \ + $(build)/binaryToObject-pe.o +converter = $(build)/binaryToObject -static-library = $(native-build)/lib$(name).a -executable = $(native-build)/$(name)${exe-suffix} -dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix) -executable-dynamic = $(native-build)/$(name)-dynamic${exe-suffix} +static-library = $(build)/lib$(name).a +executable = $(build)/$(name)${exe-suffix} +dynamic-library = $(build)/$(so-prefix)jvm$(so-suffix) +executable-dynamic = $(build)/$(name)-dynamic${exe-suffix} + +ifneq ($(classpath),avian) +# Assembler, ConstantPool, and Stream are not technically needed for a +# working build, but we include them since our Subroutine test uses +# them to synthesize a class: + classpath-sources := \ + $(classpath-src)/avian/Addendum.java \ + $(classpath-src)/avian/Assembler.java \ + $(classpath-src)/avian/Callback.java \ + $(classpath-src)/avian/CallbackReceiver.java \ + $(classpath-src)/avian/ClassAddendum.java \ + $(classpath-src)/avian/ConstantPool.java \ + $(classpath-src)/avian/Continuations.java \ + $(classpath-src)/avian/FieldAddendum.java \ + $(classpath-src)/avian/IncompatibleContinuationException.java \ + $(classpath-src)/avian/Machine.java \ + $(classpath-src)/avian/MethodAddendum.java \ + $(classpath-src)/avian/Stream.java \ + $(classpath-src)/avian/SystemClassLoader.java \ + $(classpath-src)/avian/VMClass.java \ + $(classpath-src)/avian/VMField.java \ + $(classpath-src)/avian/VMMethod.java \ + $(classpath-src)/avian/resource/Handler.java + + ifneq ($(openjdk),) + classpath-sources := $(classpath-sources) \ + $(classpath-src)/avian/OpenJDK.java + endif +else + classpath-sources := $(shell find $(classpath-src) -name '*.java') +endif -classpath-sources := $(shell find $(classpath) -name '*.java') classpath-classes = \ - $(call java-classes,$(classpath-sources),$(classpath),$(classpath-build)) -classpath-object = $(native-build)/classpath-jar.o + $(call java-classes,$(classpath-sources),$(classpath-src),$(classpath-build)) +classpath-object = $(build)/classpath-jar.o classpath-dep = $(classpath-build).dep -gnu-blacklist = \ - java/lang/AbstractStringBuffer.class \ - java/lang/reflect/Proxy.class - -gnu-overrides = \ +vm-classes = \ avian/*.class \ - avian/resource/*.class \ - java/lang/Class.class \ - java/lang/Enum.class \ - java/lang/InheritableThreadLocal.class \ - java/lang/Object.class \ - java/lang/StackTraceElement.class \ - java/lang/String.class \ - java/lang/String\$$*.class \ - java/lang/StringBuffer.class \ - java/lang/StringBuilder.class \ - java/lang/StringBuilder\$$*.class \ - java/lang/Thread.class \ - java/lang/Thread\$$*.class \ - java/lang/ThreadGroup.class \ - java/lang/ThreadLocal.class \ - java/lang/Throwable.class \ - java/lang/ref/PhantomReference.class \ - java/lang/ref/Reference.class \ - java/lang/ref/ReferenceQueue.class \ - java/lang/ref/SoftReference.class \ - java/lang/ref/WeakReference.class \ - java/lang/reflect/AccessibleObject.class \ - java/lang/reflect/Constructor.class \ - java/lang/reflect/Field.class \ - java/lang/reflect/Method.class \ - java/lang/reflect/Proxy.class \ - java/lang/reflect/Proxy\$$*.class + avian/resource/*.class test-sources = $(wildcard $(test)/*.java) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) @@ -480,12 +560,19 @@ test-extra-classes = \ $(call java-classes,$(test-extra-sources),$(test),$(test-build)) test-extra-dep = $(test-build)-extra.dep +ifeq ($(continuations),true) + continuation-tests = \ + extra.Continuations \ + extra.Coroutines \ + extra.DynamicWind +endif + class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) -flags = -cp $(test-build) +test-flags = -cp $(build)/test -args = $(flags) $(input) +test-args = $(test-flags) $(input) .PHONY: build build: $(static-library) $(executable) $(dynamic-library) \ @@ -497,21 +584,22 @@ $(test-extra-dep): $(classpath-dep) .PHONY: run run: build - $(executable) $(args) + $(library-path) $(test-executable) $(test-args) .PHONY: debug debug: build - gdb --args $(executable) $(args) + $(library-path) gdb --args $(test-executable) $(test-args) .PHONY: vg vg: build - $(vg) $(executable) $(args) + $(library-path) $(vg) $(test-executable) $(test-args) .PHONY: test test: build - /bin/sh $(test)/test.sh 2>/dev/null \ - $(executable) $(mode) "$(flags)" \ - $(call class-names,$(test-build),$(test-classes)) + $(library-path) /bin/sh $(test)/test.sh 2>/dev/null \ + $(test-executable) $(mode) "$(test-flags)" \ + $(call class-names,$(test-build),$(test-classes)) \ + $(continuation-tests) .PHONY: tarball tarball: @@ -533,43 +621,23 @@ clean: @echo "removing build" rm -rf build -.PHONY: clean-native -clean-native: - @echo "removing $(native-build)" - rm -rf $(native-build) +$(build)/compile-x86-asm.o: $(src)/continuations-x86.S -$(native-build)/compile-x86-asm.o: $(src)/continuations-x86.S - -gen-arg = $(shell echo $(1) | sed -e 's:$(native-build)/type-\(.*\)\.cpp:\1:') +gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @echo "generating $(@)" @mkdir -p $(dir $(@)) - $(generator) $(classpath-build) $(call gen-arg,$(@)) < $(<) > $(@) + $(generator) $(boot-classpath) $(<) $(@) $(call gen-arg,$(@)) -$(native-build)/type-generator.o: \ - $(generator-headers) - -$(classpath-build)/%.class: $(classpath)/%.java +$(classpath-build)/%.class: $(classpath-src)/%.java @echo $(<) -$(classpath-dep): $(classpath-sources) $(gnu-jar) +$(classpath-dep): $(classpath-sources) @echo "compiling classpath classes" - @mkdir -p $(avian-classpath-build) - $(javac) -d $(avian-classpath-build) \ - -bootclasspath $(avian-classpath-build) \ - $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) -ifdef gnu - (wd=$$(pwd) && \ - cd $(avian-classpath-build) && \ - $(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \ - $(gnu-overrides)) @mkdir -p $(classpath-build) - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) xf $(gnu-jar) && \ - rm $(gnu-blacklist) && \ - jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")") -endif + $(javac) -d $(classpath-build) -bootclasspath $(boot-classpath) \ + $(shell $(MAKE) -s --no-print-directory build=$(build) \ + $(classpath-classes)) @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -578,20 +646,20 @@ $(test-build)/%.class: $(test)/%.java $(test-dep): $(test-sources) @echo "compiling test classes" @mkdir -p $(test-build) - files="$(shell $(MAKE) -s --no-print-directory $(test-classes))"; \ + files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ if test -n "$${files}"; then \ - $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ + $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ - test/Subroutine.java + -bootclasspath $(boot-classpath) test/Subroutine.java @touch $(@) $(test-extra-dep): $(test-extra-sources) @echo "compiling extra test classes" @mkdir -p $(test-build) - files="$(shell $(MAKE) -s --no-print-directory $(test-extra-classes))"; \ + files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \ if test -n "$${files}"; then \ - $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ + $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi @touch $(@) @@ -607,75 +675,91 @@ define compile-asm-object $(as) -I$(src) $(asmflags) -c $(<) -o $(@) endef -$(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) +$(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) -$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S +$(vm-asm-objects): $(build)/%-asm.o: $(src)/%.S $(compile-asm-object) -$(bootimage-generator-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) +$(bootimage-generator-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) -$(heapwalk-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) +$(heapwalk-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) $(driver-object): $(driver-source) $(compile-object) -$(driver-dynamic-object): $(driver-source) +$(build)/main-dynamic.o: $(driver-source) @echo "compiling $(@)" @mkdir -p $(dir $(@)) - $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)$(name)$(so-suffix)\" \ + $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)jvm$(so-suffix)\" \ -c $(<) $(call output,$(@)) $(boot-object): $(boot-source) $(compile-object) -$(build)/classpath.jar: $(classpath-dep) - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) +$(boot-javahome-object): $(src)/boot-javahome.cpp + $(compile-object) -$(native-build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp +$(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp $(build-cxx) -c $(^) -o $(@) -$(native-build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) -DBITS_PER_WORD=64 -c $(^) -o $(@) +$(build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) -$(native-build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) -DBITS_PER_WORD=32 -c $(^) -o $(@) +$(build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) -$(native-build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) -DBITS_PER_WORD=64 -c $(^) -o $(@) +$(build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) -$(native-build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) -DBITS_PER_WORD=32 -c $(^) -o $(@) +$(build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) -$(native-build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp - $(build-cxx) -c $(^) -o $(@) +$(build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp + $(build-cxx) $(converter-cflags) -c $(^) -o $(@) $(converter): $(converter-objects) $(build-cxx) $(^) -o $(@) +$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) + @echo "creating $(@)" + (wd=$$(pwd) && \ + cd $(classpath-build) && \ + $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) + $(classpath-object): $(build)/classpath.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(platform) $(arch) -$(generator-objects): $(native-build)/%.o: $(src)/%.cpp +$(build)/javahome.jar: + @echo "creating $(@)" + (wd=$$(pwd) && \ + cd "$(build-javahome)" && \ + $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $(javahome-files)) + +$(javahome-object): $(build)/javahome.jar $(converter) + @echo "creating $(@)" + $(converter) $(<) $(@) _binary_javahome_jar_start \ + _binary_javahome_jar_end $(platform) $(arch) + +$(generator-objects): $(generator-depends) +$(generator-objects): $(build)/%-build.o: $(src)/%.cpp @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ -c $(<) -o $(@) -$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp +$(jni-objects): $(build)/%.o: $(classpath-src)/%.cpp $(compile-object) -$(static-library): $(gnu-object-dep) -$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) +$(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ + $(javahome-object) $(boot-javahome-object) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) $(call gnu-objects) + $(ar) cru $(@) $(^) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -687,30 +771,24 @@ $(bootimage-object): $(bootimage-bin) $(converter) _binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \ writable executable -$(gnu-object-dep): $(gnu-libraries) - @mkdir -p $(build)/gnu-objects - (cd $(build)/gnu-objects && \ - for x in $(gnu-libraries); do ar x $${x}; done) - @touch $(@) +executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ + $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ + $(javahome-object) $(boot-javahome-object) -$(executable): $(gnu-object-dep) -$(executable): \ - $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) +$(executable): $(executable-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc - $(ld) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb -IMPLIB:$(@).lib \ - -MANIFESTFILE:$(@).manifest + $(ld) $(lflags) $(executable-objects) -out:$(@) -PDB:$(@).pdb \ + -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(dlltool) -z $(@).def $(^) $(call gnu-objects) + $(dlltool) -z $(@).def $(executable-objects) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@) + $(ld) $(@).exp $(executable-objects) $(lflags) -o $(@) endif else - $(ld) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(ld) $(executable-objects) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -718,13 +796,15 @@ $(bootimage-generator): $(MAKE) mode=$(mode) \ arch=$(build-arch) \ platform=$(bootimage-platform) \ + openjdk=$(openjdk) \ + openjdk-src=$(openjdk-src) \ bootimage-generator= \ build-bootimage-generator=$(bootimage-generator) \ $(bootimage-generator) $(build-bootimage-generator): \ - $(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \ - $(bootimage-generator-objects) + $(vm-objects) $(classpath-object) $(classpath-objects) \ + $(heapwalk-objects) $(bootimage-generator-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc @@ -740,32 +820,74 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -$(dynamic-library): $(gnu-object-dep) -$(dynamic-library): \ - $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) $(gnu-libraries) +$(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ + $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ + $(classpath-libraries) $(javahome-object) $(boot-javahome-object) @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(native-build)/$(name).lib -MANIFESTFILE:$(@).manifest + -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \ + $(ld) $(^) $(version-script-flag) $(shared) $(lflags) $(bootimage-lflags) \ -o $(@) endif $(strip) $(strip-all) $(@) -$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) +$(executable-dynamic): $(driver-dynamic-objects) $(dynamic-library) @echo "linking $(@)" ifdef msvc - $(ld) $(lflags) -LIBPATH:$(native-build) -DEFAULTLIB:$(name) \ - -PDB:$(@).pdb -IMPLIB:$(@).lib $(<) -out:$(@) -MANIFESTFILE:$(@).manifest + $(ld) $(lflags) -LIBPATH:$(build) -DEFAULTLIB:$(name) \ + -PDB:$(@).pdb -IMPLIB:$(@).lib $(driver-dynamic-objects) -out:$(@) \ + -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(ld) $(^) $(lflags) -o $(@) + $(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) $(generator): $(generator-objects) @echo "linking $(@)" $(build-ld) $(^) $(build-lflags) -o $(@) + +$(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ + $(openjdk-headers-dep) + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + sed 's/^static jclass ia_class;//' < $(<) > $(build)/openjdk/$(notdir $(<)) + $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ + $(optimization-cflags) -w -c $(build)/openjdk/$(notdir $(<)) \ + $(call output,$(@)) + +$(openjdk-local-objects): $(build)/openjdk/%.o: $(src)/openjdk/%.c \ + $(openjdk-headers-dep) + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ + $(optimization-cflags) -w -c $(<) $(call output,$(@)) + +$(openjdk-headers-dep): + @echo "generating openjdk headers" + @mkdir -p $(dir $(@)) + $(javah) -d $(build)/openjdk -bootclasspath $(boot-classpath) \ + $(openjdk-headers-classes) +ifeq ($(platform),windows) + sed 's/^#ifdef _WIN64/#if 1/' \ + < "$(openjdk-src)/windows/native/java/net/net_util_md.h" \ + > $(build)/openjdk/net_util_md.h + cp "$(openjdk-src)/windows/native/java/net/NetworkInterface.h" \ + $(build)/openjdk/NetworkInterface.h + echo 'static int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP);' >> $(build)/openjdk/NetworkInterface.h +endif + @touch $(@) + +$(openjdk-jar-dep): + @echo "extracting openjdk classes" + @mkdir -p $(dir $(@)) + @mkdir -p $(classpath-build) + (cd $(classpath-build) && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jsse.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jce.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/resources.jar")") + @touch $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk new file mode 100644 index 0000000000..190c8622e9 --- /dev/null +++ b/openjdk-src.mk @@ -0,0 +1,309 @@ +openjdk-sources = \ + $(openjdk-src)/share/native/common/check_code.c \ + $(openjdk-src)/share/native/common/check_format.c \ + $(openjdk-src)/share/native/common/check_version.c \ + $(openjdk-src)/share/native/common/jdk_util.c \ + $(openjdk-src)/share/native/common/jio.c \ + $(openjdk-src)/share/native/common/jni_util.c \ + $(openjdk-src)/share/native/common/verify_stub.c \ + $(openjdk-src)/share/native/java/io/FileInputStream.c \ + $(openjdk-src)/share/native/java/io/io_util.c \ + $(openjdk-src)/share/native/java/io/ObjectInputStream.c \ + $(openjdk-src)/share/native/java/io/ObjectOutputStream.c \ + $(openjdk-src)/share/native/java/io/ObjectStreamClass.c \ + $(openjdk-src)/share/native/java/io/RandomAccessFile.c \ + $(openjdk-src)/share/native/java/lang/Class.c \ + $(openjdk-src)/share/native/java/lang/ClassLoader.c \ + $(openjdk-src)/share/native/java/lang/Compiler.c \ + $(openjdk-src)/share/native/java/lang/Double.c \ + $(openjdk-src)/share/native/java/lang/Float.c \ + $(openjdk-src)/share/native/java/lang/Object.c \ + $(openjdk-src)/share/native/java/lang/Package.c \ + $(openjdk-src)/share/native/java/lang/ref/Finalizer.c \ + $(openjdk-src)/share/native/java/lang/reflect/Array.c \ + $(openjdk-src)/share/native/java/lang/reflect/Proxy.c \ + $(openjdk-src)/share/native/java/lang/ResourceBundle.c \ + $(openjdk-src)/share/native/java/lang/Runtime.c \ + $(openjdk-src)/share/native/java/lang/SecurityManager.c \ + $(openjdk-src)/share/native/java/lang/Shutdown.c \ + $(openjdk-src)/share/native/java/lang/StrictMath.c \ + $(openjdk-src)/share/native/java/lang/String.c \ + $(openjdk-src)/share/native/java/lang/System.c \ + $(openjdk-src)/share/native/java/lang/Thread.c \ + $(openjdk-src)/share/native/java/lang/Throwable.c \ + $(wildcard $(openjdk-src)/share/native/java/lang/fdlibm/src/*.c) \ + $(openjdk-src)/share/native/java/net/DatagramPacket.c \ + $(openjdk-src)/share/native/java/net/InetAddress.c \ + $(openjdk-src)/share/native/java/net/Inet4Address.c \ + $(openjdk-src)/share/native/java/net/Inet6Address.c \ + $(openjdk-src)/share/native/java/nio/Bits.c \ + $(openjdk-src)/share/native/java/security/AccessController.c \ + $(openjdk-src)/share/native/java/sql/DriverManager.c \ + $(openjdk-src)/share/native/java/util/concurrent/atomic/AtomicLong.c \ + $(openjdk-src)/share/native/java/util/TimeZone.c \ + $(openjdk-src)/share/native/java/util/zip/Adler32.c \ + $(openjdk-src)/share/native/java/util/zip/CRC32.c \ + $(openjdk-src)/share/native/java/util/zip/Deflater.c \ + $(openjdk-src)/share/native/java/util/zip/Inflater.c \ + $(openjdk-src)/share/native/java/util/zip/ZipEntry.c \ + $(openjdk-src)/share/native/java/util/zip/ZipFile.c \ + $(openjdk-src)/share/native/java/util/zip/zip_util.c \ + $(openjdk-src)/share/native/sun/misc/GC.c \ + $(openjdk-src)/share/native/sun/misc/MessageUtils.c \ + $(openjdk-src)/share/native/sun/misc/NativeSignalHandler.c \ + $(openjdk-src)/share/native/sun/misc/Signal.c \ + $(openjdk-src)/share/native/sun/misc/Version.c \ + $(openjdk-src)/share/native/sun/misc/VM.c \ + $(openjdk-src)/share/native/sun/misc/VMSupport.c \ + $(openjdk-src)/share/native/sun/reflect/ConstantPool.c \ + $(openjdk-src)/share/native/sun/reflect/NativeAccessors.c \ + $(openjdk-src)/share/native/sun/reflect/Reflection.c + +openjdk-headers-classes = \ + java.io.Console \ + java.io.FileDescriptor \ + java.io.FileInputStream \ + java.io.FileOutputStream \ + java.io.FileSystem \ + java.io.ObjectInputStream \ + java.io.ObjectOutputStream \ + java.io.ObjectStreamClass \ + java.io.RandomAccessFile \ + java.lang.Class \ + java.lang.ClassLoader \ + java.lang.Compiler \ + java.lang.Double \ + java.lang.Float \ + java.lang.Integer \ + java.lang.Object \ + java.lang.Package \ + java.lang.Runtime \ + java.lang.SecurityManager \ + java.lang.Shutdown \ + java.lang.StrictMath \ + java.lang.String \ + java.lang.System \ + java.lang.Thread \ + java.lang.Throwable \ + java.lang.ref.Finalizer \ + java.lang.reflect.Array \ + java.lang.reflect.Proxy \ + java.net.InetAddress \ + java.net.Inet4Address \ + java.net.Inet6Address \ + java.net.DatagramPacket \ + java.net.SocketOptions \ + java.net.InetAddressImplFactory \ + java.net.Inet4AddressImpl \ + java.net.Inet6AddressImpl \ + java.net.NetworkInterface \ + java.net.PlainSocketImpl \ + java.net.SocketInputStream \ + java.net.SocketOutputStream \ + java.nio.MappedByteBuffer \ + java.security.AccessController \ + java.util.ResourceBundle \ + java.util.TimeZone \ + java.util.concurrent.atomic.AtomicLong \ + java.util.jar.JarFile \ + java.util.zip.Adler32 \ + java.util.zip.CRC32 \ + java.util.zip.Deflater \ + java.util.zip.Inflater \ + java.util.zip.ZipEntry \ + java.util.zip.ZipFile \ + sun.misc.GC \ + sun.misc.MessageUtils \ + sun.misc.NativeSignalHandler \ + sun.misc.Signal \ + sun.misc.VM \ + sun.misc.VMSupport \ + sun.misc.Version \ + sun.net.spi.DefaultProxySelector \ + sun.nio.ch.FileKey \ + sun.nio.ch.FileChannelImpl \ + sun.nio.ch.FileDispatcher \ + sun.nio.ch.DatagramChannelImpl \ + sun.nio.ch.DatagramDispatcher \ + sun.nio.ch.IOStatus \ + sun.nio.ch.IOUtil \ + sun.nio.ch.Net \ + sun.nio.ch.ServerSocketChannelImpl \ + sun.nio.ch.SocketChannelImpl \ + sun.nio.ch.SocketDispatcher \ + sun.nio.ch.PollArrayWrapper \ + sun.nio.ch.NativeThread \ + sun.reflect.ConstantPool \ + sun.reflect.NativeConstructorAccessorImpl \ + sun.reflect.NativeMethodAccessorImpl \ + sun.reflect.Reflection \ + sun.security.provider.NativeSeedGenerator + +# todo: set properties according to architecture targeted and OpenJDK +# version used: +openjdk-cflags = \ + "-I$(src)/openjdk" \ + "-I$(build)/openjdk" \ + "-I$(openjdk-src)/share/javavm/export" \ + "-I$(openjdk-src)/share/native/common" \ + "-I$(openjdk-src)/share/native/java/io" \ + "-I$(openjdk-src)/share/native/java/lang" \ + "-I$(openjdk-src)/share/native/java/lang/fdlibm/include" \ + "-I$(openjdk-src)/share/native/java/net" \ + "-I$(openjdk-src)/share/native/java/util/zip" \ + "-I$(openjdk-src)/share/native/sun/nio/ch" \ + "-I$(openjdk-src)/share/javavm/include" \ + -D_LITTLE_ENDIAN \ + -DARCHPROPNAME=\"x86\" \ + -DRELEASE=\"1.6.0\" \ + -DJDK_MAJOR_VERSION=\"1\" \ + -DJDK_MINOR_VERSION=\"6\" \ + -DJDK_MICRO_VERSION=\"0\" \ + -DJDK_BUILD_NUMBER=\"0\" \ + -D_GNU_SOURCE + +ifeq ($(platform),darwin) + openjdk-cflags += \ + -D_LFS_LARGEFILE=1 \ + -D_ALLBSD_SOURCE +endif + +ifeq ($(platform),windows) + openjdk-sources += \ + $(openjdk-src)/windows/native/java/io/canonicalize_md.c \ + $(openjdk-src)/windows/native/java/io/Console_md.c \ + $(openjdk-src)/windows/native/java/io/FileDescriptor_md.c \ + $(openjdk-src)/windows/native/java/io/FileInputStream_md.c \ + $(openjdk-src)/windows/native/java/io/FileOutputStream_md.c \ + $(openjdk-src)/windows/native/java/io/FileSystem_md.c \ + $(openjdk-src)/windows/native/java/io/io_util_md.c \ + $(openjdk-src)/windows/native/java/io/RandomAccessFile_md.c \ + $(openjdk-src)/windows/native/java/io/Win32FileSystem_md.c \ + $(openjdk-src)/windows/native/java/io/WinNTFileSystem_md.c \ + $(openjdk-src)/windows/native/java/lang/java_props_md.c \ + $(openjdk-src)/windows/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/windows/native/java/lang/ProcessImpl_md.c \ + $(openjdk-src)/windows/native/java/net/net_util_md.c \ + $(openjdk-src)/windows/native/java/net/InetAddressImplFactory.c \ + $(openjdk-src)/windows/native/java/net/Inet4AddressImpl.c \ + $(openjdk-src)/windows/native/java/net/Inet6AddressImpl.c \ + $(openjdk-src)/windows/native/java/net/NetworkInterface.c \ + $(openjdk-src)/windows/native/java/net/NetworkInterface_winXP.c \ + $(openjdk-src)/windows/native/java/net/NetworkInterface_win9x.c \ + $(openjdk-src)/windows/native/java/net/SocketInputStream.c \ + $(openjdk-src)/windows/native/java/net/SocketOutputStream.c \ + $(openjdk-src)/windows/native/java/util/WindowsPreferences.c \ + $(openjdk-src)/windows/native/java/util/logging.c \ + $(openjdk-src)/windows/native/java/util/TimeZone_md.c \ + $(openjdk-src)/windows/native/sun/io/Win32ErrorMode.c \ + $(openjdk-src)/windows/native/sun/nio/ch/DatagramChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/DatagramDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileKey.c \ + $(openjdk-src)/windows/native/sun/nio/ch/IOUtil.c \ + $(openjdk-src)/windows/native/sun/nio/ch/Net.c \ + $(openjdk-src)/windows/native/sun/nio/ch/ServerSocketChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/SocketChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/SocketDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/WindowsSelectorImpl.c \ + $(openjdk-src)/windows/native/sun/security/provider/WinCAPISeedGenerator.c + + openjdk-headers-classes += \ + java.lang.ProcessImpl \ + sun.io.Win32ErrorMode \ + sun.nio.ch.WindowsSelectorImpl \ + + openjdk-cflags += \ + "-I$(openjdk-src)/windows/javavm/export" \ + "-I$(openjdk-src)/windows/native/common" \ + "-I$(openjdk-src)/windows/native/java/io" \ + "-I$(openjdk-src)/windows/native/java/net" \ + "-I$(openjdk-src)/windows/native/java/util" \ + "-I$(openjdk-src)/windows/native/sun/nio/ch" \ + "-I$(openjdk-src)/windows/javavm/include" \ + "-I$(root)/win32/include" \ + -D_JNI_IMPLEMENTATION_ \ + -D_JAVASOFT_WIN32_TYPEDEF_MD_H_ \ + -D_WINSOCK2API_ \ + -Ds6_words=_s6_words \ + -Ds6_bytes=_s6_bytes +else + openjdk-sources += \ + $(openjdk-src)/solaris/native/common/jdk_util_md.c \ + $(openjdk-src)/solaris/native/java/io/canonicalize_md.c \ + $(openjdk-src)/solaris/native/java/io/Console_md.c \ + $(openjdk-src)/solaris/native/java/io/FileDescriptor_md.c \ + $(openjdk-src)/solaris/native/java/io/FileInputStream_md.c \ + $(openjdk-src)/solaris/native/java/io/FileOutputStream_md.c \ + $(openjdk-src)/solaris/native/java/io/FileSystem_md.c \ + $(openjdk-src)/solaris/native/java/io/io_util_md.c \ + $(openjdk-src)/solaris/native/java/io/RandomAccessFile_md.c \ + $(openjdk-src)/solaris/native/java/io/UnixFileSystem_md.c \ + $(openjdk-src)/solaris/native/java/lang/java_props_md.c \ + $(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c \ + $(openjdk-src)/solaris/native/java/net/net_util_md.c \ + $(openjdk-src)/solaris/native/java/net/InetAddressImplFactory.c \ + $(openjdk-src)/solaris/native/java/net/Inet4AddressImpl.c \ + $(openjdk-src)/solaris/native/java/net/Inet6AddressImpl.c \ + $(openjdk-src)/solaris/native/java/net/NetworkInterface.c \ + $(openjdk-src)/solaris/native/java/net/PlainSocketImpl.c \ + $(openjdk-src)/solaris/native/java/net/PlainDatagramSocketImpl.c \ + $(openjdk-src)/solaris/native/java/net/SocketInputStream.c \ + $(openjdk-src)/solaris/native/java/net/SocketOutputStream.c \ + $(openjdk-src)/solaris/native/java/nio/MappedByteBuffer.c \ + $(openjdk-src)/solaris/native/java/util/FileSystemPreferences.c \ + $(openjdk-src)/solaris/native/java/util/logging.c \ + $(openjdk-src)/solaris/native/java/util/TimeZone_md.c \ + $(openjdk-src)/solaris/native/sun/net/dns/ResolverConfigurationImpl.c \ + $(openjdk-src)/solaris/native/sun/net/spi/DefaultProxySelector.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/DatagramChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/DatagramDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileKey.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/IOUtil.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/Net.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/SocketChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/SocketDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/EPollArrayWrapper.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/PollArrayWrapper.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/InheritedChannel.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/NativeThread.c \ + + ifeq ($(platform),linux) + openjdk-sources += \ + $(openjdk-src)/solaris/native/java/net/linux_close.c + endif + + openjdk-headers-classes += \ + java.net.PlainDatagramSocketImpl \ + java.io.UnixFileSystem \ + sun.nio.ch.InheritedChannel \ + sun.nio.ch.EPollArrayWrapper \ + + openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ + "-I$(openjdk-src)/solaris/native/common" \ + "-I$(openjdk-src)/solaris/native/java/io" \ + "-I$(openjdk-src)/solaris/native/java/lang" \ + "-I$(openjdk-src)/solaris/native/java/net" \ + "-I$(openjdk-src)/solaris/native/java/util" \ + "-I$(openjdk-src)/solaris/native/sun/nio/ch" \ + "-I$(openjdk-src)/solaris/javavm/include" \ + "-I$(openjdk-src)/solaris/hpi/include" +endif + +openjdk-local-sources = \ + $(src)/openjdk/my_net_util.c + +c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) + +openjdk-objects = \ + $(call c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk) + +openjdk-local-objects = \ + $(call c-objects,$(openjdk-local-sources),$(src)/openjdk,$(build)/openjdk) + +openjdk-headers-dep = $(build)/openjdk/headers.dep diff --git a/openjdk.ld b/openjdk.ld new file mode 100644 index 0000000000..fdad025d57 --- /dev/null +++ b/openjdk.ld @@ -0,0 +1,288 @@ +# +# @(#)mapfile-vers-product 1.19 08/02/12 10:56:37 +# + +# +# Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# +# + +# Define public interface. + +SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + + # JVM + JVM_Accept; + JVM_ActiveProcessorCount; + JVM_AllocateNewArray; + JVM_AllocateNewObject; + JVM_ArrayCopy; + JVM_AssertionStatusDirectives; + JVM_Available; + JVM_Bind; + JVM_ClassDepth; + JVM_ClassLoaderDepth; + JVM_Clone; + JVM_Close; + JVM_CX8Field; + JVM_CompileClass; + JVM_CompileClasses; + JVM_CompilerCommand; + JVM_Connect; + JVM_ConstantPoolGetClassAt; + JVM_ConstantPoolGetClassAtIfLoaded; + JVM_ConstantPoolGetDoubleAt; + JVM_ConstantPoolGetFieldAt; + JVM_ConstantPoolGetFieldAtIfLoaded; + JVM_ConstantPoolGetFloatAt; + JVM_ConstantPoolGetIntAt; + JVM_ConstantPoolGetLongAt; + JVM_ConstantPoolGetMethodAt; + JVM_ConstantPoolGetMethodAtIfLoaded; + JVM_ConstantPoolGetMemberRefInfoAt; + JVM_ConstantPoolGetSize; + JVM_ConstantPoolGetStringAt; + JVM_ConstantPoolGetUTF8At; + JVM_CountStackFrames; + JVM_CurrentClassLoader; + JVM_CurrentLoadedClass; + JVM_CurrentThread; + JVM_CurrentTimeMillis; + JVM_DefineClass; + JVM_DefineClassWithSource; + JVM_DesiredAssertionStatus; + JVM_DisableCompiler; + JVM_DoPrivileged; + JVM_DTraceGetVersion; + JVM_DTraceActivate; + JVM_DTraceIsProbeEnabled; + JVM_DTraceIsSupported; + JVM_DTraceDispose; + JVM_DumpAllStacks; + JVM_DumpThreads; + JVM_EnableCompiler; + JVM_Exit; + JVM_FillInStackTrace; + JVM_FindClassFromClass; + JVM_FindClassFromClassLoader; + JVM_FindClassFromBootLoader; + JVM_FindLibraryEntry; + JVM_FindLoadedClass; + JVM_FindPrimitiveClass; + JVM_FindSignal; + JVM_FreeMemory; + JVM_GC; + JVM_GetAllThreads; + JVM_GetArrayElement; + JVM_GetArrayLength; + JVM_GetCPClassNameUTF; + JVM_GetCPFieldClassNameUTF; + JVM_GetCPFieldModifiers; + JVM_GetCPFieldNameUTF; + JVM_GetCPFieldSignatureUTF; + JVM_GetCPMethodClassNameUTF; + JVM_GetCPMethodModifiers; + JVM_GetCPMethodNameUTF; + JVM_GetCPMethodSignatureUTF; + JVM_GetCallerClass; + JVM_GetClassAccessFlags; + JVM_GetClassAnnotations; + JVM_GetClassCPEntriesCount; + JVM_GetClassCPTypes; + JVM_GetClassConstantPool; + JVM_GetClassContext; + JVM_GetClassDeclaredConstructors; + JVM_GetClassDeclaredFields; + JVM_GetClassDeclaredMethods; + JVM_GetClassFieldsCount; + JVM_GetClassInterfaces; + JVM_GetClassLoader; + JVM_GetClassMethodsCount; + JVM_GetClassModifiers; + JVM_GetClassName; + JVM_GetClassNameUTF; + JVM_GetClassSignature; + JVM_GetClassSigners; + JVM_GetComponentType; + JVM_GetDeclaredClasses; + JVM_GetDeclaringClass; + JVM_GetEnclosingMethodInfo; + JVM_GetFieldAnnotations; + JVM_GetFieldIxModifiers; + JVM_GetHostName; + JVM_GetInheritedAccessControlContext; + JVM_GetInterfaceVersion; + JVM_GetLastErrorString; + JVM_GetManagement; + JVM_GetMethodAnnotations; + JVM_GetMethodDefaultAnnotationValue; + JVM_GetMethodIxArgsSize; + JVM_GetMethodIxByteCode; + JVM_GetMethodIxByteCodeLength; + JVM_GetMethodIxExceptionIndexes; + JVM_GetMethodIxExceptionTableEntry; + JVM_GetMethodIxExceptionTableLength; + JVM_GetMethodIxExceptionsCount; + JVM_GetMethodIxLocalsCount; + JVM_GetMethodIxMaxStack; + JVM_GetMethodIxModifiers; + JVM_GetMethodIxNameUTF; + JVM_GetMethodIxSignatureUTF; + JVM_GetMethodParameterAnnotations; + JVM_GetPrimitiveArrayElement; + JVM_GetProtectionDomain; + JVM_GetSockName; + JVM_GetSockOpt; + JVM_GetStackAccessControlContext; + JVM_GetStackTraceDepth; + JVM_GetStackTraceElement; + JVM_GetSystemPackage; + JVM_GetSystemPackages; + JVM_GetThreadStateNames; + JVM_GetThreadStateValues; + JVM_GetVersionInfo; + JVM_Halt; + JVM_HoldsLock; + JVM_IHashCode; + JVM_InitAgentProperties; + JVM_InitProperties; + JVM_InitializeCompiler; + JVM_InitializeSocketLibrary; + JVM_InternString; + JVM_Interrupt; + JVM_InvokeMethod; + JVM_IsArrayClass; + JVM_IsConstructorIx; + JVM_IsInterface; + JVM_IsInterrupted; + JVM_IsNaN; + JVM_IsPrimitiveClass; + JVM_IsSameClassPackage; + JVM_IsSilentCompiler; + JVM_IsSupportedJNIVersion; + JVM_IsThreadAlive; + JVM_LatestUserDefinedLoader; + JVM_Listen; + JVM_LoadClass0; + JVM_LoadLibrary; + JVM_Lseek; + JVM_MaxObjectInspectionAge; + JVM_MaxMemory; + JVM_MonitorNotify; + JVM_MonitorNotifyAll; + JVM_MonitorWait; + JVM_NanoTime; + JVM_NativePath; + JVM_NewArray; + JVM_NewInstanceFromConstructor; + JVM_NewMultiArray; + JVM_OnExit; + JVM_Open; + JVM_PrintStackTrace; + JVM_RaiseSignal; + JVM_RawMonitorCreate; + JVM_RawMonitorDestroy; + JVM_RawMonitorEnter; + JVM_RawMonitorExit; + JVM_Read; + JVM_Recv; + JVM_RecvFrom; + JVM_RegisterSignal; + JVM_ReleaseUTF; + JVM_ResolveClass; + JVM_ResumeThread; + JVM_Send; + JVM_SendTo; + JVM_SetArrayElement; + JVM_SetClassSigners; + JVM_SetLength; + JVM_SetPrimitiveArrayElement; + JVM_SetProtectionDomain; + JVM_SetSockOpt; + JVM_SetThreadPriority; + JVM_Sleep; + JVM_Socket; + JVM_SocketAvailable; + JVM_SocketClose; + JVM_SocketShutdown; + JVM_StartThread; + JVM_StopThread; + JVM_SuspendThread; + JVM_SupportsCX8; + JVM_Sync; + JVM_Timeout; + JVM_TotalMemory; + JVM_TraceInstructions; + JVM_TraceMethodCalls; + JVM_UnloadLibrary; + JVM_Write; + JVM_Yield; + JVM_handle_linux_signal; + + # Old reflection routines + # These do not need to be present in the product build in JDK 1.4 + # but their code has not been removed yet because there will not + # be a substantial code savings until JVM_InvokeMethod and + # JVM_NewInstanceFromConstructor can also be removed; see + # reflectionCompat.hpp. + JVM_GetClassConstructor; + JVM_GetClassConstructors; + JVM_GetClassField; + JVM_GetClassFields; + JVM_GetClassMethod; + JVM_GetClassMethods; + JVM_GetField; + JVM_GetPrimitiveField; + JVM_NewInstance; + JVM_SetField; + JVM_SetPrimitiveField; + + # Needed for dropping VM into JDK 1.3.x, 1.4 + _JVM_native_threads; + jdk_sem_init; + jdk_sem_post; + jdk_sem_wait; + jdk_pthread_sigmask; + jdk_waitpid; + + # miscellaneous functions + jio_fprintf; + jio_printf; + jio_snprintf; + jio_vfprintf; + jio_vsnprintf; + fork1; + numa_warn; + numa_error; + + # Needed because there is no JVM interface for this. + sysThreadAvailableStackWithSlack; + + # This is for Forte Analyzer profiling support. + AsyncGetCallTrace; +}; + diff --git a/openjdk.pro b/openjdk.pro new file mode 100644 index 0000000000..81031f3bc9 --- /dev/null +++ b/openjdk.pro @@ -0,0 +1,213 @@ +# proguard include file (http://proguard.sourceforge.net) + +# This file is for use in combination with vm.pro when ProGuarding +# OpenJDK-based builds + +# the following methods and fields are refered to by name in the VM: + +-keepclassmembers class java.lang.Thread { + public void run(); + } + +-keep class java.lang.System { + private static void initializeSystemClass(); + } + +-keep class java.lang.ClassLoader { + private static java.lang.ClassLoader scl; + private static boolean sclSet; + + protected ClassLoader(java.lang.ClassLoader); + } + +-keep class avian.SystemClassLoader { + protected java.net.URL findResource(java.lang.String); + } + +-keepnames class java.lang.ClassLoader { + public java.lang.Class loadClass(java.lang.String); + static void loadLibrary(java.lang.Class, java.lang.String, boolean); + private static java.net.URL getBootstrapResource(java.lang.String); + private static java.util.Enumeration getBootstrapResources(java.lang.String); + } + +-keep class java.util.Properties { + public java.lang.Object setProperty(java.lang.String, java.lang.String); + } + +-keep class avian.OpenJDK { + public static java.security.ProtectionDomain getProtectionDomain(); + } + +-keepclassmembers public class java.security.PrivilegedAction { + public java.lang.Object run(); + } + +-keepclassmembers public class * implements java.security.PrivilegedAction { + public java.lang.Object run(); + } + +-keepclassmembers public class java.security.PrivilegedExceptionAction { + public java.lang.Object run(); + } + +-keepclassmembers public class * implements java.security.PrivilegedExceptionAction { + public java.lang.Object run(); + } + +-keep public class java.security.PrivilegedActionException { + public PrivilegedActionException(java.lang.Exception); + } + +# these class names are used to disambiguate JNI method lookups: + +-keepnames public class java.net.URL +-keepnames public class java.util.Enumeration +-keepnames public class java.security.ProtectionDomain +-keepnames public class java.security.PrivilegedAction +-keepnames public class java.security.PrivilegedExceptionAction +-keepnames public class java.security.AccessControlContext + +# the following methods and fields are refered to by name in the OpenJDK +# native code: + +-keep class java.util.Properties { + public java.lang.Object put(java.lang.Object, java.lang.Object); + } + +-keepclassmembers class * { + public boolean equals(java.lang.Object); + public void wait(); + public void notify(); + public void notifyAll(); + public java.lang.String toString(); + } + +-keepclassmembers class java.lang.String { + public String(byte[]); + public String(byte[], java.lang.String); + public byte[] getBytes(); + public byte[] getBytes(java.lang.String); + } + +-keepclassmembers class java.lang.Boolean { + public boolean getBoolean(java.lang.String); + } + +-keepclassmembers class java.util.zip.Inflater { + long strm; + boolean needDict; + boolean finished; + byte[] buf; + int off; + int len; + } + +-keepclassmembers class java.io.FileDescriptor { + private int fd; + } + +-keep class java.net.InetAddress { + ; + } +-keep class java.net.Inet4Address { + ; + } +-keep class java.net.Inet4AddressImpl +-keep class java.net.Inet6Address { + ; + } +-keep class java.net.Inet6AddressImpl +-keep class java.net.InetSocketAddress { + public InetSocketAddress(java.net.InetAddress, int); + } +-keep class java.net.ServerSocket + +-keepclassmembers class java.net.PlainSocketImpl { + ; + } + +-keepclassmembers class java.io.FileInputStream { + private java.io.FileDescriptor fd; + } + +-keepclassmembers class java.io.FileOutputStream { + private java.io.FileDescriptor fd; + } + +# changed in native code via sun.misc.Unsafe (todo: handle other +# Atomic* classes) +-keepclassmembers class java.util.concurrent.atomic.AtomicInteger { + private int value; + } + +# avoid inlining due to access check using a fixed offset into call stack: +-keep,allowshrinking,allowobfuscation class java.util.concurrent.atomic.AtomicReferenceFieldUpdater { + *** newUpdater(...); + } + +# accessed reflectively via an AtomicReferenceFieldUpdater: +-keepclassmembers class java.io.BufferedInputStream { + protected byte[] buf; + } + +-keep class java.lang.System { + public static java.io.InputStream in; + public static java.io.PrintStream out; + public static java.io.PrintStream err; + # avoid inlining due to access check using fixed offset into call stack: + static java.lang.Class getCallerClass(); + # called from jni_util.c: + static java.lang.String getProperty(java.lang.String); + } + +# refered to by name from native code: +-keepnames public class java.io.InputStream +-keepnames public class java.io.PrintStream + +# avoid inlining due to access check using fixed offset into call stack: +-keep,allowshrinking,allowobfuscation class java.lang.System { + static java.lang.Class getCallerClass(); + } + +-keep class java.io.UnixFileSystem { + public UnixFileSystem(); + } + +-keep class java.io.File { + private java.lang.String path; + } + +-keepclassmembers class java.lang.ClassLoader$NativeLibrary { + long handle; + private int jniVersion; + } + +-keep class java.nio.charset.Charset { + # called from jni_util.c: + boolean isSupported(java.lang.String); + } + +# Charsets are loaded via reflection. If you need others besides +# UTF-8, you'll need to add them (e.g. sun.nio.cs.ISO_8859_1). +-keep class sun.nio.cs.UTF_8 + +# loaded reflectively to handle embedded resources: +-keep class avian.resource.Handler + +# refered to symbolically in MethodAccessorGenerator: +-keep class sun.reflect.MethodAccessorImpl { + ; + } +-keep class sun.reflect.ConstructorAccessorImpl { + ; + } +-keep class sun.reflect.SerializationConstructorAccessorImpl { + ; + } + +# referred to by name in LocaleData to load resources: +-keep class sun.util.resources.CalendarData +-keep class sun.util.resources.TimeZoneNames +-keep class sun.text.resources.FormatData + diff --git a/readme.txt b/readme.txt index 78bad0048a..708c948d13 100644 --- a/readme.txt +++ b/readme.txt @@ -4,24 +4,24 @@ Quick Start on Linux: $ export JAVA_HOME=/usr/local/java # or wherever you have the JDK installed $ make - $ build/linux-i386/avian -cp build/test Hello + $ build/linux-i386/avian -cp build/linux-i386/test Hello on Mac OS X: $ export JAVA_HOME=/Library/Java/Home $ make - $ build/darwin-i386/avian -cp build/test Hello + $ build/darwin-i386/avian -cp build/darwin-i386/test Hello on Windows (MSYS): $ git clone git://oss.readytalk.com/win32.git ../win32 $ export JAVA_HOME="C:/Program Files/Java/jdk1.6.0_07" $ make - $ build/windows-i386/avian -cp build/test Hello + $ build/windows-i386/avian -cp build/windows-i386/test Hello on Windows (Cygwin): $ git clone git://oss.readytalk.com/win32.git ../win32 $ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_07" $ make - $ build/windows-i386/avian -cp build/test Hello + $ build/windows-i386/avian -cp build/windows-i386/test Hello Adjust JAVA_HOME according to your system, but be sure to use forward slashes in the path. @@ -51,7 +51,7 @@ Supported Platforms Avian can currently target the following platforms: - Linux (i386 and x86_64) + Linux (i386, x86_64 and ARM) Windows (i386 and x86_64) Mac OS X (i386, x86_64 and 32-bit PowerPC) @@ -62,7 +62,7 @@ Building Build requirements include: * GNU make 3.80 or later - * GCC 3.4 or later (4.5 or later for Windows/x86_64) + * GCC 3.4 or later (4.5.1 or later for Windows/x86_64) * JDK 1.5 or later * MinGW 3.4 or later (only if compiling for Windows) * zlib 1.2.3 or later @@ -73,10 +73,17 @@ been tested. The build is directed by a single makefile and may be influenced via certain flags described below, all of which are optional. - $ make platform={linux,windows,darwin} arch={i386,x86_64,powerpc} \ - process={compile,interpret} mode={debug,debug-fast,fast,small} \ - bootimage={true,false} heapdump={true,false} tails={true,false} \ - continuations={true,false} + $ make \ + platform={linux,windows,darwin} \ + arch={i386,x86_64,powerpc,arm} \ + process={compile,interpret} \ + mode={debug,debug-fast,fast,small} \ + bootimage={true,false} \ + heapdump={true,false} \ + tails={true,false} \ + continuations={true,false} \ + openjdk= \ + openjdk-src= * platform - the target platform default: output of $(uname -s | tr [:upper:] [:lower:]), @@ -119,6 +126,18 @@ certain flags described below, all of which are optional. only valid for process=compile builds. default: false + * openjdk - if set, use OpenJDK class library instead of the default + Avian class library. See "Building with the OpenJDK Class + Library" below for details. + default: not set + + * openjdk-src - if this and the openjdk option above are both set, + build an embeddable VM using the OpenJDK class library. The JNI + components of the OpenJDK class library will be built from the + sources found under the specified directory. See "Building with + the OpenJDK Class Library" below for details. + default: not set + These flags determine the name of the directory used for the build. The name always starts with ${platform}-${arch}, and each non-default build option is appended to the name. For example, a debug build with @@ -168,7 +187,7 @@ C++ portions of the VM, while the assembly code and helper tools are built using GCC. The MSVC build has been tested with Visual Studio Express Edition -versions 8 and 9. Other versions may also work. +versions 8, 9, and 10. Other versions may also work. To build with MSVC, install Cygwin as described above and set the following environment variables: @@ -191,25 +210,57 @@ Finally, build with the msvc flag set to the MSVC tool directory: $ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC" -Building with GNU Classpath ---------------------------- - - ** Please note that this feature is still under development and is - neither complete nor well-tested. ** +Building with the OpenJDK Class Library +--------------------------------------- By default, Avian uses its own lightweight class library. However, that library only contains a relatively small subset of the classes and methods included in the JRE. If your application requires -features beyond that subset, you may want to tell Avian to use GNU -Classpath instead. To do so, specify the directory where Classpath is -installed, e.g.: +features beyond that subset, you may want to tell Avian to use +OpenJDK's class library instead. To do so, specify the directory +where OpenJDK is installed, e.g.: - $ make clean - $ make gnu=/usr/local/classpath-0.98 + $ make openjdk=/usr/lib/jvm/java-6-openjdk -This build will use the classes and native code from Classpath, except -that certain core classes are replaced with implementations from the -Avian class library for compatibility with the VM. +This will build Avian as a conventional JVM (e.g. libjvm.so) which +loads its boot class library and native libraries (e.g. libjava.so) +from /usr/lib/jvm/java-6-openjdk/jre at runtime. To run an +application in this configuration, you'll need to make sure the VM is +in your library search path. For example: + + $ LD_LIBRARY_PATH=build/linux-x86_64-openjdk \ + build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ + com.example.MyApplication + +Alternatively, you can enable a stand-alone build using OpenJDK by +specifying the location of the OpenJDK source code, e.g.: + + $ make openjdk=$(pwd)/../jdk6/build/linux-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../jdk6/jdk/src + +You must ensure that the path specified for openjdk-src does not have +any spaces in it; make gets confused when dependency paths include +spaces, and we haven't found away around that except to avoid paths +with spaces entirely. + +The result of such a build is a self-contained binary which does not +depend on external libraries, jars, or other files. In this case, the +specified paths are used only at build time; anything needed at +runtime is embedded in the binary. Thus, the process of running an +application is simplified: + + $ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \ + com.example.MyApplication + +Note that the resulting binary will be very large due to the size of +OpenJDK's class library. This can be mitigated using UPX, preferably +an LZMA-enabled version: + + $ upx --lzma --best build/linux-x86_64-openjdk-src/avian + +You can reduce the size futher for embedded builds by using ProGuard +and the supplied openjdk.pro configuration file (see "Embedding with +ProGuard and a Boot Image" below). Installing @@ -237,7 +288,7 @@ VM object files and bootstrap classpath jar. $ mkdir hello $ cd hello $ ar x ../build/${platform}-${arch}/libavian.a - $ cp ../build/classpath.jar boot.jar + $ cp ../build/${platform}-${arch}/classpath.jar boot.jar Step 2: Build the Java code and add it to the jar. @@ -259,17 +310,21 @@ Step 3: Make an object file out of the jar. Step 4: Write a driver which starts the VM and runs the desired main method. Note the bootJar function, which will be called by the VM to get a handle to the embedded jar. We tell the VM about this jar by -setting the classpath to "[bootJar]". +setting the boot classpath to "[bootJar]". $ cat >main.cpp <("-Djava.class.path=[bootJar]"); + options[0].optionString = const_cast("-Xbootclasspath:[bootJar]"); JavaVM* vm; void* env; @@ -391,7 +446,10 @@ For boot image builds: space in the executable than the equivalent class files. In practice, this can make the executable 30-50% larger. Also, AOT compilation does not yet yield significantly faster or smaller code - than JIT compilation. + than JIT compilation. Finally, floating point code may be slower + on 32-bit x86 since the compiler cannot assume SSE2 support will be + available at runtime, and the x87 FPU is not supported except via + out-of-line helper functions. Note you can use ProGuard without using a boot image and vice-versa, as desired. @@ -411,7 +469,7 @@ Step 2: Create a stage1 directory and extract the contents of the class library jar into it. $ mkdir stage1 - $ (cd stage1 && jar xf ../../build/classpath.jar) + $ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar) Step 3: Build the Java code and add it to stage1. @@ -435,7 +493,7 @@ EOF Step 5: Run ProGuard with stage1 as input and stage2 as output. - $ java -jar ../../proguard4.4/lib/proguard.jar \ + $ java -jar ../../proguard4.6/lib/proguard.jar \ -injars stage1 -outjars stage2 @../vm.pro @hello.pro (note: pass -dontusemixedcaseclassnames to ProGuard when building on @@ -447,10 +505,10 @@ Step 6: Build the boot image. Step 7: Make an object file out of the boot image. - $ ../build/${platform}-${arch}/binaryToObject \ + $ ../build/linux-i386-bootimage/binaryToObject \ bootimage.bin bootimage-bin.o \ _binary_bootimage_bin_start _binary_bootimage_bin_end \ - ${platform} ${arch} 8 writable executable + linux i386 8 writable executable Step 8: Write a driver which starts the VM and runs the desired main method. Note the bootimageBin function, which will be called by the @@ -466,11 +524,15 @@ containing them. See the previous example for instructions. #include "stdint.h" #include "jni.h" -#ifdef __MINGW32__ +#if (defined __MINGW32__) || (defined _MSC_VER) # define EXPORT __declspec(dllexport) -# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x #else # define EXPORT __attribute__ ((visibility("default"))) +#endif + +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) +# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x +#else # define BOOTIMAGE_BIN(x) _binary_bootimage_bin_##x #endif @@ -545,3 +607,12 @@ executable, and optionally strip its symbols. $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello $ strip --strip-all hello + + +Trademarks +---------- + +Oracle and Java are registered trademarks of Oracle and/or its +affiliates. Other names may be trademarks of their respective owners. + +The Avian project is not affiliated with Oracle. diff --git a/src/arch.h b/src/arch.h index a49cf5078f..6e6d4b24a6 100644 --- a/src/arch.h +++ b/src/arch.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -22,7 +22,7 @@ #include "common.h" extern "C" void NO_RETURN -vmJump(void* address, void* base, void* stack, void* thread, +vmJump(void* address, void* frame, void* stack, void* thread, uintptr_t returnLow, uintptr_t returnHigh); namespace vm { diff --git a/src/arm.S b/src/arm.S index f3dd2b146f..458ece75cb 100644 --- a/src/arm.S +++ b/src/arm.S @@ -1,5 +1,5 @@ /* arm.S: JNI gluecode for ARM/Linux - Copyright (c) 2008-2009, Avian Contributors + Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -50,7 +50,31 @@ vmNativeCall: .globl vmJump vmJump: + mov lr, r0 + ldr r0, [sp] + ldr r1, [sp, #4] mov sp, r2 - mov r4, r3 - ldmia sp, {r0,r1} - mov pc, lr + mov r8, r3 + bx lr + +#define CHECKPOINT_THREAD 4 +#define CHECKPOINT_STACK 24 + +.globl vmRun +vmRun: + // r0: function + // r1: arguments + // r2: checkpoint + stmfd sp!, {r4-r11, lr} + + str sp, [r2, #CHECKPOINT_STACK] + + mov r12, r0 + ldr r0, [r2, #CHECKPOINT_THREAD] + + blx r12 + +.globl vmRun_returnAddress +vmRun_returnAddress: + ldmfd sp!, {r4-r11, lr} + bx lr diff --git a/src/arm.cpp b/src/arm.cpp index 66af8a37d3..d0bb5f02c7 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -14,6 +14,7 @@ #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST3(x) reinterpret_cast(x) +#define CAST_BRANCH(x) reinterpret_cast(x) using namespace vm; @@ -29,9 +30,9 @@ inline int DATA(int cond, int opcode, int S, int Rn, int Rd, int shift, int Sh, inline int DATAS(int cond, int opcode, int S, int Rn, int Rd, int Rs, int Sh, int Rm) { return cond<<28 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | Rs<<8 | Sh<<5 | 1<<4 | Rm; } inline int DATAI(int cond, int opcode, int S, int Rn, int Rd, int rot, int imm) -{ return cond<<28 | 1<<25 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | rot<<8 | imm; } +{ return cond<<28 | 1<<25 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | rot<<8 | (imm&0xff); } inline int BRANCH(int cond, int L, int offset) -{ return cond<<28 | 5<<25 | L<<24 | offset; } +{ return cond<<28 | 5<<25 | L<<24 | (offset&0xffffff); } inline int BRANCHX(int cond, int L, int Rm) { return cond<<28 | 0x4bffc<<6 | L<<5 | 1<<4 | Rm; } inline int MULTIPLY(int cond, int mul, int S, int Rd, int Rn, int Rs, int Rm) @@ -39,17 +40,19 @@ inline int MULTIPLY(int cond, int mul, int S, int Rd, int Rn, int Rs, int Rm) inline int XFER(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int shift, int Sh, int Rm) { return cond<<28 | 3<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | shift<<7 | Sh<<5 | Rm; } inline int XFERI(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int offset) -{ return cond<<28 | 2<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offset; } +{ return cond<<28 | 2<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | (offset&0xfff); } inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, int H, int Rm) { return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; } inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL) -{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | offsetL; } +{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | (offsetL&0xf); } inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist) { return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; } inline int SWI(int cond, int imm) -{ return cond<<28 | 0x0f<<24 | imm; } +{ return cond<<28 | 0x0f<<24 | (imm&0xffffff); } inline int SWAP(int cond, int B, int Rn, int Rd, int Rm) { return cond<<28 | 1<<24 | B<<22 | Rn<<16 | Rd<<12 | 9<<4 | Rm; } +// FIELD CALCULATORS +inline int calcU(int imm) { return imm >= 0 ? 1 : 0; } // INSTRUCTIONS // The "cond" and "S" fields are set using the SETCOND() and SETS() functions inline int b(int offset) { return BRANCH(AL, 0, offset); } @@ -65,10 +68,10 @@ inline int add(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, inline int adc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x5, 0, Rn, Rd, shift, Sh, Rm); } inline int sbc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x6, 0, Rn, Rd, shift, Sh, Rm); } inline int rsc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x7, 0, Rn, Rd, shift, Sh, Rm); } -inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 0, Rn, 0, shift, Sh, Rm); } -inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 0, Rn, 0, shift, Sh, Rm); } -inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 0, Rn, 0, shift, Sh, Rm); } -inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 0, Rn, 0, shift, Sh, Rm); } +inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 1, Rn, 0, shift, Sh, Rm); } +inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 1, Rn, 0, shift, Sh, Rm); } +inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 1, Rn, 0, shift, Sh, Rm); } +inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 1, Rn, 0, shift, Sh, Rm); } inline int orr(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xc, 0, Rn, Rd, shift, Sh, Rm); } inline int mov(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xd, 0, 0, Rd, shift, Sh, Rm); } inline int bic(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xe, 0, Rn, Rd, shift, Sh, Rm); } @@ -79,39 +82,40 @@ inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, R inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); } inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); } inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); } -inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0x0, 0, Rn, 0, rot, imm); } +inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, Rn, Rd, rot, imm); } +inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); } inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); } inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); } +inline int orrsh(int Rd, int Rn, int Rm, int Rs, int Sh) { return DATAS(AL, 0xc, 0, Rn, Rd, Rs, Sh, Rm); } inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); } inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); } -inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdLo, RdHi, Rs, Rm); } -inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdLo, RdHi, Rs, Rm); } -inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdLo, RdHi, Rs, Rm); } -inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdLo, RdHi, Rs, Rm); } -inline int ldr(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 0, 0, 1, Rn, Rd, 0, 0, Rm); } -inline int ldri(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 0, 0, 1, Rn, Rd, imm); } +inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); } +inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdHi, RdLo, Rs, Rm); } +inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdHi, RdLo, Rs, Rm); } +inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdHi, RdLo, Rs, Rm); } +inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); } +inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); } inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } -inline int ldrbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 1, 0, 1, Rn, Rd, imm); } +inline int ldrbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 1, Rn, Rd, abs(imm)); } inline int str(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 0, Rn, Rd, 0, 0, Rm); } -inline int stri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, 1, 0, W, 0, Rn, Rd, imm); } +inline int stri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 0, Rn, Rd, abs(imm)); } inline int strb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 0, Rn, Rd, 0, 0, Rm); } -inline int strbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 1, 0, 0, Rn, Rd, imm); } +inline int strbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 0, Rn, Rd, abs(imm)); } inline int ldrh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 0, 1, Rm); } -inline int ldrhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 0, 1, imm&0xf); } +inline int ldrhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 0, 1, abs(imm)&0xf); } inline int strh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 0, Rn, Rd, 0, 1, Rm); } -inline int strhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 0, Rn, Rd, imm>>4 & 0xf, 0, 1, imm&0xf); } +inline int strhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 0, Rn, Rd, abs(imm)>>4 & 0xf, 0, 1, abs(imm)&0xf); } inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 1, Rm); } -inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 1, 1, imm&0xf); } +inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); } inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); } -inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 1, 0, imm&0xf); } -inline int ldmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 1, Rn, rlist); } -inline int ldmia(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 0, 1, Rn, rlist); } -inline int stmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 0, Rn, rlist); } -inline int stmdb(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 0, 0, Rn, rlist); } +inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); } +inline int pop(int Rd) { return XFERI(AL, 0, 1, 0, 0, 1, 13, Rd, 4); } +inline int ldmfd(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 1, 1, Rn, rlist); } +inline int stmfd(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 1, 0, Rn, rlist); } inline int swp(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); } inline int swpb(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); } -inline int SETCOND(int ins, int cond) { return ins&0x0fffffff | cond<<28; } +inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); } inline int SETS(int ins) { return ins | 1<<20; } // PSEUDO-INSTRUCTIONS inline int nop() { return mov(0, 0); } @@ -122,6 +126,16 @@ inline int lsri(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSR, imm); } inline int asr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ASR); } inline int asri(int Rd, int Rm, int imm) { return mov(Rd, Rm, ASR, imm); } inline int ror(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ROR); } +inline int beq(int offset) { return SETCOND(b(offset), EQ); } +inline int bne(int offset) { return SETCOND(b(offset), NE); } +inline int bls(int offset) { return SETCOND(b(offset), LS); } +inline int bhi(int offset) { return SETCOND(b(offset), HI); } +inline int blt(int offset) { return SETCOND(b(offset), LT); } +inline int bgt(int offset) { return SETCOND(b(offset), GT); } +inline int ble(int offset) { return SETCOND(b(offset), LE); } +inline int bge(int offset) { return SETCOND(b(offset), GE); } +inline int blo(int offset) { return SETCOND(b(offset), CC); } +inline int bhs(int offset) { return SETCOND(b(offset), CS); } } const uint64_t MASK_LO32 = 0xffffffff; @@ -134,46 +148,87 @@ inline unsigned hi16(int64_t i) { return lo16(i>>16); } inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); } inline unsigned hi8(int64_t i) { return lo8(i>>8); } +inline int ha16(int32_t i) { + return ((i >> 16) + ((i & 0x8000) ? 1 : 0)) & 0xffff; +} +inline int unha16(int32_t high, int32_t low) { + return ((high - ((low & 0x8000) ? 1 : 0)) << 16) | low; +} + inline bool isInt8(intptr_t v) { return v == static_cast(v); } inline bool isInt16(intptr_t v) { return v == static_cast(v); } -inline bool isInt24(intptr_t v) { return v == v & 0xffffff; } +inline bool isInt24(intptr_t v) { return v == (v & 0xffffff); } inline bool isInt32(intptr_t v) { return v == static_cast(v); } inline int carry16(intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } -const unsigned FrameFooterSize = 0; +inline bool isOfWidth(long long i, int size) { return static_cast(i) >> size == 0; } +inline bool isOfWidth(int i, int size) { return static_cast(i) >> size == 0; } + +const unsigned FrameHeaderSize = 1; + const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; +const int ThreadRegister = 8; const int StackRegister = 13; -const int ThreadRegister = 12; +const int LinkRegister = 14; +const int ProgramCounter = 15; + +const int32_t PoolOffsetMask = 0xFFF; + +const bool DebugPool = false; + +class Context; +class MyBlock; +class PoolOffset; +class PoolEvent; + +void +resolve(MyBlock*); + +unsigned +padding(MyBlock*, unsigned); class MyBlock: public Assembler::Block { public: - MyBlock(unsigned offset): - next(0), offset(offset), start(~0), size(0) + MyBlock(Context* context, unsigned offset): + context(context), next(0), poolOffsetHead(0), poolOffsetTail(0), + lastPoolOffsetTail(0), poolEventHead(0), poolEventTail(0), + lastEventOffset(0), offset(offset), start(~0), size(0) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); - return start + size; + ::resolve(this); + + return start + size + padding(this, size); } + Context* context; MyBlock* next; + PoolOffset* poolOffsetHead; + PoolOffset* poolOffsetTail; + PoolOffset* lastPoolOffsetTail; + PoolEvent* poolEventHead; + PoolEvent* poolEventTail; + unsigned lastEventOffset; unsigned offset; unsigned start; unsigned size; }; class Task; +class ConstantPoolEntry; class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), - firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock) + firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(this, 0)), + lastBlock(firstBlock), poolOffsetHead(0), poolOffsetTail(0), + constantPool(0), constantPoolCount(0) { } System* s; @@ -184,6 +239,10 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; + PoolOffset* poolOffsetHead; + PoolOffset* poolOffsetTail; + ConstantPoolEntry* constantPool; + unsigned constantPoolCount; }; class Task { @@ -206,6 +265,10 @@ typedef void (*TernaryOperationType) (Context*, unsigned, Assembler::Operand*, Assembler::Operand*, Assembler::Operand*); +typedef void (*BranchOperationType) +(Context*, TernaryOperation, unsigned, Assembler::Operand*, + Assembler::Operand*, Assembler::Operand*); + class ArchitectureContext { public: ArchitectureContext(System* s): s(s) { } @@ -217,7 +280,9 @@ class ArchitectureContext { BinaryOperationType binaryOperations [BinaryOperationCount * OperandTypeCount * OperandTypeCount]; TernaryOperationType ternaryOperations - [TernaryOperationCount * OperandTypeCount]; + [NonBranchTernaryOperationCount * OperandTypeCount]; + BranchOperationType branchOperations + [BranchOperationCount * OperandTypeCount * OperandTypeCount]; }; inline void NO_RETURN @@ -254,8 +319,8 @@ expect(Context* c, bool v) class Offset: public Promise { public: - Offset(Context* c, MyBlock* block, unsigned offset): - c(c), block(block), offset(offset) + Offset(Context* c, MyBlock* block, unsigned offset, bool forTrace): + c(c), block(block), offset(offset), forTrace(forTrace) { } virtual bool resolved() { @@ -265,19 +330,21 @@ class Offset: public Promise { virtual int64_t value() { assert(c, resolved()); - return block->start + (offset - block->offset); + unsigned o = offset - block->offset; + return block->start + padding(block, forTrace ? o - BytesPerWord : o) + o; } Context* c; MyBlock* block; unsigned offset; + bool forTrace; }; Promise* -offset(Context* c) +offset(Context* c, bool forTrace = false) { return new (c->zone->allocate(sizeof(Offset))) - Offset(c, c->lastBlock, c->code.length()); + Offset(c, c->lastBlock, c->code.length(), forTrace); } bool @@ -287,10 +354,11 @@ bounded(int right, int left, int32_t v) } void* -updateOffset(System* s, uint8_t* instruction, bool conditional UNUSED, int64_t value) +updateOffset(System* s, uint8_t* instruction, int64_t value) { - int32_t v = reinterpret_cast(value) - instruction; - + // ARM's PC is two words ahead, and branches drop the bottom 2 bits. + int32_t v = (reinterpret_cast(value) - (instruction + 8)) >> 2; + int32_t mask; expect(s, bounded(0, 8, v)); mask = 0xFFFFFF; @@ -303,66 +371,59 @@ updateOffset(System* s, uint8_t* instruction, bool conditional UNUSED, int64_t v class OffsetListener: public Promise::Listener { public: - OffsetListener(System* s, uint8_t* instruction, bool conditional): + OffsetListener(System* s, uint8_t* instruction): s(s), - instruction(instruction), - conditional(conditional) + instruction(instruction) { } virtual bool resolve(int64_t value, void** location) { - void* p = updateOffset(s, instruction, conditional, value); + void* p = updateOffset(s, instruction, value); if (location) *location = p; return false; } System* s; uint8_t* instruction; - bool conditional; }; class OffsetTask: public Task { public: - OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, - bool conditional): + OffsetTask(Task* next, Promise* promise, Promise* instructionOffset): Task(next), promise(promise), - instructionOffset(instructionOffset), - conditional(conditional) + instructionOffset(instructionOffset) { } virtual void run(Context* c) { if (promise->resolved()) { updateOffset - (c->s, c->result + instructionOffset->value(), conditional, - promise->value()); + (c->s, c->result + instructionOffset->value(), promise->value()); } else { new (promise->listen(sizeof(OffsetListener))) - OffsetListener(c->s, c->result + instructionOffset->value(), - conditional); + OffsetListener(c->s, c->result + instructionOffset->value()); } } Promise* promise; Promise* instructionOffset; - bool conditional; }; void -appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, - bool conditional) +appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset) { c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask - (c->tasks, promise, instructionOffset, conditional); + (c->tasks, promise, instructionOffset); } inline unsigned -index(UnaryOperation operation, OperandType operand) +index(ArchitectureContext*, UnaryOperation operation, OperandType operand) { return operation + (UnaryOperationCount * operand); } inline unsigned -index(BinaryOperation operation, +index(ArchitectureContext*, + BinaryOperation operation, OperandType operand1, OperandType operand2) { @@ -371,13 +432,34 @@ index(BinaryOperation operation, + (BinaryOperationCount * OperandTypeCount * operand2); } -inline unsigned -index(TernaryOperation operation, - OperandType operand1) +bool +isBranch(TernaryOperation op) { - return operation + (TernaryOperationCount * operand1); + return op > FloatMin; } +bool +isFloatBranch(TernaryOperation op) +{ + return op > JumpIfNotEqual; +} + +inline unsigned +index(ArchitectureContext* c UNUSED, + TernaryOperation operation, + OperandType operand1) +{ + assert(c, not isBranch(operation)); + + return operation + (NonBranchTernaryOperationCount * operand1); +} + +unsigned +branchIndex(ArchitectureContext* c UNUSED, OperandType operand1, + OperandType operand2) +{ + return operand1 + (OperandTypeCount * operand2); +} // BEGIN OPERATION COMPILERS @@ -387,57 +469,61 @@ using namespace isa; inline void emit(Context* con, int code) { con->code.append4(code); } inline int newTemp(Context* con) { return con->client->acquireTemporary(); } inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } -inline int64_t getValue(Assembler::Constant c) { return c->value->value(); } +inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); } - -void shiftLeftR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) +inline void +write4(uint8_t* dst, uint32_t v) { - if (size == 8) { - int tmpHi = newTemp(con), tmpLo = newTemp(con); - emit(con, SETS(rsbi(tmpHi, a->low, 32))); - emit(con, lsl(t->high, b->high, a->low)); - emit(con, lsr(tmpLo, b->low, tmpHi)); - emit(con, orr(t->high, t->high, tmpLo)); - emit(con, addi(tmpHi, a->low, -32)); - emit(con, lsl(tmpLo, b->low, tmpHi)); - emit(con, orr(t->high, t->high, tmpLo)); - freeTemp(con, tmpHi); freeTemp(con, tmpLo); - } - emit(con, lsl(t->low, b->low, a->low)); + memcpy(dst, &v, 4); } -void shiftLeftC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) +void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) +{ + if (size == 8) { + int tmp1 = newTemp(con), tmp2 = newTemp(con); + emit(con, lsl(tmp1, b->high, a->low)); + emit(con, rsbi(tmp2, a->low, 32)); + emit(con, orrsh(tmp1, tmp1, b->low, tmp2, LSR)); + emit(con, SETS(subi(t->high, a->low, 32))); + emit(con, SETCOND(mov(t->high, tmp1), MI)); + emit(con, SETCOND(lsl(t->high, b->low, t->high), PL)); + emit(con, lsl(t->low, b->low, a->low)); + freeTemp(con, tmp1); freeTemp(con, tmp2); + } else { + emit(con, lsl(t->low, b->low, a->low)); + } +} + +void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, lsli(t->low, b->low, getValue(a))); } -void shiftRightR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) +void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - int tmpHi = newTemp(con), tmpLo = newTemp(con); - emit(con, SETS(rsbi(tmpHi, a->low, 32))); - emit(con, lsr(t->low, b->low, a->low)); - emit(con, lsl(tmpLo, b->high, tmpHi)); - emit(con, orr(t->low, t->low, tmpLo)); - emit(con, SETS(addi(tmpHi, a->low, -32))); - emit(con, asr(tmpLo, b->high, tmpHi)); - emit(con, SETCOND(b(8), LE)); - emit(con, orri(t->low, tmpLo, 0)); + int tmp1 = newTemp(con), tmp2 = newTemp(con); + emit(con, lsr(tmp1, b->low, a->low)); + emit(con, rsbi(tmp2, a->low, 32)); + emit(con, orrsh(tmp1, tmp1, b->high, tmp2, LSL)); + emit(con, SETS(subi(t->low, a->low, 32))); + emit(con, SETCOND(mov(t->low, tmp1), MI)); + emit(con, SETCOND(asr(t->low, b->high, t->low), PL)); emit(con, asr(t->high, b->high, a->low)); - freeTemp(con, tmpHi); freeTemp(con, tmpLo); + freeTemp(con, tmp1); freeTemp(con, tmp2); } else { emit(con, asr(t->low, b->low, a->low)); } } -void shiftRightC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) +void shiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, asri(t->low, b->low, getValue(a))); } -void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) +void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { emit(con, lsr(t->low, b->low, a->low)); if (size == 8) { @@ -453,81 +539,205 @@ void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register a, Ass } } -void unsignedShiftRightC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) +void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, lsri(t->low, b->low, getValue(a))); } -void -updateImmediate(System* s, void* dst, int64_t src, unsigned size) -{ - switch (size) { - case 4: { - int32_t* p = static_cast(dst); - int r = (p[0] >> 12) & 15; - - p[0] = movi(r, lo8(src)); - p[1] = orri(r, r, hi8(src), 12); - p[2] = orri(r, r, lo8(hi16(src)), 8); - p[3] = orri(r, r, hi8(hi16(src)), 4); - } break; - - default: abort(s); - } -} - -class ImmediateListener: public Promise::Listener { +class ConstantPoolEntry: public Promise { public: - ImmediateListener(System* s, void* dst, unsigned size, unsigned offset): - s(s), dst(dst), size(size), offset(offset) + ConstantPoolEntry(Context* c, Promise* constant, ConstantPoolEntry* next, + Promise* callOffset): + c(c), constant(constant), next(next), callOffset(callOffset), + address(0) + { } + + virtual int64_t value() { + assert(c, resolved()); + + return reinterpret_cast(address); + } + + virtual bool resolved() { + return address != 0; + } + + Context* c; + Promise* constant; + ConstantPoolEntry* next; + Promise* callOffset; + void* address; + unsigned constantPoolCount; +}; + +class ConstantPoolListener: public Promise::Listener { + public: + ConstantPoolListener(System* s, uintptr_t* address, uint8_t* returnAddress): + s(s), + address(address), + returnAddress(returnAddress) { } virtual bool resolve(int64_t value, void** location) { - updateImmediate(s, dst, value, size); - if (location) *location = static_cast(dst) + offset; - return false; + *address = value; + if (location) { + *location = returnAddress ? static_cast(returnAddress) : address; + } + return true; } System* s; - void* dst; - unsigned size; + uintptr_t* address; + uint8_t* returnAddress; +}; + +class PoolOffset { + public: + PoolOffset(MyBlock* block, ConstantPoolEntry* entry, unsigned offset): + block(block), entry(entry), next(0), offset(offset) + { } + + MyBlock* block; + ConstantPoolEntry* entry; + PoolOffset* next; unsigned offset; }; -class ImmediateTask: public Task { +class PoolEvent { public: - ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, - unsigned promiseOffset): - Task(next), - promise(promise), - offset(offset), - size(size), - promiseOffset(promiseOffset) + PoolEvent(PoolOffset* poolOffsetHead, PoolOffset* poolOffsetTail, + unsigned offset): + poolOffsetHead(poolOffsetHead), poolOffsetTail(poolOffsetTail), next(0), + offset(offset) { } - virtual void run(Context* c) { - if (promise->resolved()) { - updateImmediate - (c->s, c->result + offset->value(), promise->value(), size); - } else { - new (promise->listen(sizeof(ImmediateListener))) ImmediateListener - (c->s, c->result + offset->value(), size, promiseOffset); - } - } - - Promise* promise; - Promise* offset; - unsigned size; - unsigned promiseOffset; + PoolOffset* poolOffsetHead; + PoolOffset* poolOffsetTail; + PoolEvent* next; + unsigned offset; }; void -appendImmediateTask(Context* c, Promise* promise, Promise* offset, - unsigned size, unsigned promiseOffset = 0) +appendConstantPoolEntry(Context* c, Promise* constant, Promise* callOffset) { - c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask - (c->tasks, promise, offset, size, promiseOffset); + if (constant->resolved()) { + // make a copy, since the original might be allocated on the + // stack, and we need our copy to live until assembly is complete + constant = new (c->zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(constant->value()); + } + + c->constantPool = new (c->zone->allocate(sizeof(ConstantPoolEntry))) + ConstantPoolEntry(c, constant, c->constantPool, callOffset); + + ++ c->constantPoolCount; + + PoolOffset* o = new (c->zone->allocate(sizeof(PoolOffset))) PoolOffset + (c->lastBlock, c->constantPool, c->code.length() - c->lastBlock->offset); + + if (DebugPool) { + fprintf(stderr, "add pool offset %p %d to block %p\n", + o, o->offset, c->lastBlock); + } + + if (c->lastBlock->poolOffsetTail) { + c->lastBlock->poolOffsetTail->next = o; + } else { + c->lastBlock->poolOffsetHead = o; + } + c->lastBlock->poolOffsetTail = o; +} + +void +appendPoolEvent(Context* c, MyBlock* b, unsigned offset, PoolOffset* head, + PoolOffset* tail) +{ + PoolEvent* e = new (c->zone->allocate(sizeof(PoolEvent))) PoolEvent + (head, tail, offset); + + if (b->poolEventTail) { + b->poolEventTail->next = e; + } else { + b->poolEventHead = e; + } + b->poolEventTail = e; +} + +unsigned +padding(MyBlock* b, unsigned offset) +{ + unsigned total = 0; + for (PoolEvent* e = b->poolEventHead; e; e = e->next) { + if (e->offset <= offset) { + total += BytesPerWord; + for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { + total += BytesPerWord; + } + } else { + break; + } + } + return total; +} + +void +resolve(MyBlock* b) +{ + Context* c = b->context; + + if (b->poolOffsetHead) { + if (c->poolOffsetTail) { + c->poolOffsetTail->next = b->poolOffsetHead; + } else { + c->poolOffsetHead = b->poolOffsetHead; + } + c->poolOffsetTail = b->poolOffsetTail; + } + + if (c->poolOffsetHead) { + bool append; + if (b->next == 0 or b->next->poolEventHead) { + append = true; + } else { + int32_t v = (b->start + b->size + b->next->size + BytesPerWord - 8) + - (c->poolOffsetHead->offset + c->poolOffsetHead->block->start); + + append = (v != (v & PoolOffsetMask)); + + if (DebugPool) { + fprintf(stderr, + "current %p %d %d next %p %d %d\n", + b, b->start, b->size, b->next, b->start + b->size, + b->next->size); + fprintf(stderr, + "offset %p %d is of distance %d to next block; append? %d\n", + c->poolOffsetHead, c->poolOffsetHead->offset, v, append); + } + } + + if (append) { +#ifndef NDEBUG + int32_t v = (b->start + b->size - 8) + - (c->poolOffsetHead->offset + c->poolOffsetHead->block->start); + + expect(c, v == (v & PoolOffsetMask)); +#endif // not NDEBUG + + appendPoolEvent(c, b, b->size, c->poolOffsetHead, c->poolOffsetTail); + + if (DebugPool) { + for (PoolOffset* o = c->poolOffsetHead; o; o = o->next) { + fprintf(stderr, + "include %p %d in pool event %p at offset %d in block %p\n", + o, o->offset, b->poolEventTail, b->size, b); + } + } + + c->poolOffsetHead = 0; + c->poolOffsetTail = 0; + } + } } void @@ -606,7 +816,7 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src, switch (srcSize) { case 2: emit(c, lsli(dst->low, src->low, 16)); - emit(c, lsri(dst->low, src->low, 16)); + emit(c, lsri(dst->low, dst->low, 16)); break; default: abort(c); @@ -615,28 +825,14 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src, void moveCR2(Context* c, unsigned, Assembler::Constant* src, - unsigned dstSize, Assembler::Register* dst, unsigned promiseOffset) + unsigned dstSize, Assembler::Register* dst, Promise* callOffset) { if (dstSize <= 4) { - if (src->value->resolved()) { - int32_t i = getValue(c); - emit(c, movi(dst->low, lo8(i))); - if (!isInt8(i)) { - emit(c, orri(dst->low, dst->low, hi8(i), 12)); - if (!isInt16(i)) { - emit(c, orri(dst->low, dst->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { - emit(c, orri(dst->low, dst->low, hi8(hi16(i)), 4)); - } - } - } + if (src->value->resolved() and isOfWidth(getValue(src), 8)) { + emit(c, movi(dst->low, lo8(getValue(src)))); } else { - appendImmediateTask - (c, src->value, offset(c), BytesPerWord, promiseOffset); - emit(c, movi(dst->low, 0)); - emit(c, orri(dst->low, dst->low, 0, 12)); - emit(c, orri(dst->low, dst->low, 0, 8)); - emit(c, orri(dst->low, dst->low, 0, 4)); + appendConstantPoolEntry(c, src->value, callOffset); + emit(c, ldri(dst->low, ProgramCounter, 0)); } } else { abort(c); // todo @@ -650,36 +846,16 @@ moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, moveCR2(c, srcSize, src, dstSize, dst, 0); } -void addR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) { +void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - emit(con, SETS(addc(t->low, a->low, b->low))); + emit(con, SETS(add(t->low, a->low, b->low))); emit(con, adc(t->high, a->high, b->high)); } else { emit(con, add(t->low, a->low, b->low)); } } -void addC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) { - assert(con, size == BytesPerWord); - - int32_t i = getValue(a); - if (i) { - emit(con, addi(t->low, b->low, lo8(i))); - if (!isInt8(i)) { - emit(con, addi(t->low, b->low, hi8(i), 12)); - if (!isInt16(i)) { - emit(con, addi(t->low, b->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { - emit(con, addi(t->low, b->low, hi8(hi16(i)), 4)); - } - } - } - } else { - moveRR(con, size, b, size, t); - } -} - -void subR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) { +void subR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { emit(con, SETS(rsb(t->low, a->low, b->low))); emit(con, rsc(t->high, a->high, b->high)); @@ -688,19 +864,64 @@ void subR(Context* con, unsigned size, Assembler::Register a, Assembler::Registe } } -void subC(Context* c, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) { +void +addC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ assert(c, size == BytesPerWord); - ResolvedPromise promise(- a->value->value()); - Assembler::Constant constant(&promise); - addC(c, size, &constant, b, t); + int32_t v = a->value->value(); + if (v) { + if (v > 0 and v < 256) { + emit(c, addi(dst->low, b->low, v)); + } else if (v > 0 and v < 1024 and v % 4 == 0) { + emit(c, addi(dst->low, b->low, v >> 2, 15)); + } else { + // todo + abort(c); + } + } else { + moveRR(c, size, b, size, dst); + } } -void multiplyR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) { +void +subC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + assert(c, size == BytesPerWord); + + int32_t v = a->value->value(); + if (v) { + if (v > 0 and v < 256) { + emit(c, subi(dst->low, b->low, v)); + } else if (v > 0 and v < 1024 and v % 4 == 0) { + emit(c, subi(dst->low, b->low, v >> 2, 15)); + } else { + // todo + abort(c); + } + } else { + moveRR(c, size, b, size, dst); + } +} + +void multiplyR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - emit(con, mul(t->high, a->low, b->high)); - emit(con, mla(t->high, a->high, b->low, t->high)); - emit(con, smlal(t->low, t->high, a->low, b->low)); + bool useTemporaries = b->low == t->low; + int tmpLow = useTemporaries ? con->client->acquireTemporary() : t->low; + int tmpHigh = useTemporaries ? con->client->acquireTemporary() : t->high; + + emit(con, umull(tmpLow, tmpHigh, a->low, b->low)); + emit(con, mla(tmpHigh, a->low, b->high, tmpHigh)); + emit(con, mla(tmpHigh, a->high, b->low, tmpHigh)); + + if (useTemporaries) { + emit(con, mov(t->low, tmpLow)); + emit(con, mov(t->high, tmpHigh)); + con->client->releaseTemporary(tmpLow); + con->client->releaseTemporary(tmpHigh); + } } else { emit(con, mul(t->low, a->low, b->low)); } @@ -743,8 +964,10 @@ normalize(Context* c, int offset, int index, unsigned scale, ResolvedPromise offsetPromise(offset); Assembler::Constant offsetConstant(&offsetPromise); - addC(c, BytesPerWord, &offsetConstant, - &untranslatedIndex, &normalizedIndex); + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, BytesPerWord, &offsetConstant, BytesPerWord, &tmp); + addR(c, BytesPerWord, &tmp, &untranslatedIndex, &normalizedIndex); + c->client->releaseTemporary(tmp.low); } return normalizedIndex.low; @@ -786,7 +1009,10 @@ store(Context* c, unsigned size, Assembler::Register* src, } if (release) c->client->releaseTemporary(normalized); - } else { + } else if (size == 8 + or abs(offset) == (abs(offset) & 0xFF) + or (size != 2 and abs(offset) == (abs(offset) & 0xFFF))) + { switch (size) { case 1: emit(c, strbi(src->low, base, offset)); @@ -808,6 +1034,15 @@ store(Context* c, unsigned size, Assembler::Register* src, default: abort(c); } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + ResolvedPromise offsetPromise(offset); + Assembler::Constant offsetConstant(&offsetPromise); + moveCR(c, BytesPerWord, &offsetConstant, BytesPerWord, &tmp); + + store(c, size, src, base, 0, tmp.low, 1, false); + + c->client->releaseTemporary(tmp.low); } } @@ -828,7 +1063,7 @@ moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src, assert(c, dstSize == BytesPerWord); if (dst->index == NoRegister) { - emit(c, stri(src->low, dst->base, dst->offset, 1)); + emit(c, stri(src->low, dst->base, dst->offset, dst->offset ? 1 : 0)); } else { assert(c, dst->offset == 0); assert(c, dst->scale == 1); @@ -882,7 +1117,12 @@ load(Context* c, unsigned srcSize, int base, int offset, int index, } if (release) c->client->releaseTemporary(normalized); - } else { + } else if ((srcSize == 8 and dstSize == 8) + or abs(offset) == (abs(offset) & 0xFF) + or (srcSize != 2 + and (srcSize != 1 or not signExtend) + and abs(offset) == (abs(offset) & 0xFFF))) + { switch (srcSize) { case 1: if (signExtend) { @@ -916,6 +1156,15 @@ load(Context* c, unsigned srcSize, int base, int offset, int index, default: abort(c); } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + ResolvedPromise offsetPromise(offset); + Assembler::Constant offsetConstant(&offsetPromise); + moveCR(c, BytesPerWord, &offsetConstant, BytesPerWord, &tmp); + + load(c, srcSize, base, 0, tmp.low, 1, dstSize, dst, false, signExtend); + + c->client->releaseTemporary(tmp.low); } } @@ -947,16 +1196,47 @@ void andC(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* dst) { - assert(con, size == BytesPerWord); + int64_t v = a->value->value(); - int32_t i = getValue(a); - if (i) { - emit(con, andi(t->low, b->low, lo8(i))); - emit(con, andi(t->low, b->low, hi8(i), 12)); - emit(con, andi(t->low, b->low, lo8(hi16(i)), 8)); - emit(con, andi(t->low, b->low, hi8(hi16(i)), 4)); + if (size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + andC(c, 4, &al, b, dst); + andC(c, 4, &ah, &bh, &dh); } else { - moveRR(con, size, b, size, t); + uint32_t v32 = static_cast(v); + if (v32 != 0xFFFFFFFF) { + if ((v32 & 0xFFFFFF00) == 0xFFFFFF00) { + emit(c, bici(dst->low, b->low, (~(v32 & 0xFF)) & 0xFF)); + } else if ((v32 & 0xFFFFFF00) == 0) { + emit(c, andi(dst->low, b->low, v32 & 0xFF)); + } else { + // todo: there are other cases we can handle in one + // instruction + + bool useTemporary = b->low == dst->low; + Assembler::Register tmp(dst->low); + if (useTemporary) { + tmp.low = c->client->acquireTemporary(); + } + + moveCR(c, 4, a, 4, &tmp); + andR(c, 4, b, &tmp, dst); + + if (useTemporary) { + c->client->releaseTemporary(tmp.low); + } + } + } else { + moveRR(c, size, b, size, dst); + } } } @@ -964,75 +1244,36 @@ void orR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* dst) { - if (size == 8) orr(dst->high, a->high, b->high); + if (size == 8) emit(c, orr(dst->high, a->high, b->high)); emit(c, orr(dst->low, a->low, b->low)); } void -orC(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) +xorR(Context* con, unsigned size, Assembler::Register* a, + Assembler::Register* b, Assembler::Register* dst) { - assert(con, size == BytesPerWord); - - int32_t i = getValue(a); - if (i) { - emit(con, orri(t->low, b->low, lo8(i))); - if (!isInt8(i)) { - emit(con, orri(t->low, b->low, hi8(i), 12)); - if (!isInt16(i)) { - emit(con, orri(t->low, b->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { - emit(con, orri(t->low, b->low, hi8(hi16(i)), 4)); - } - } - } - } else { - moveRR(con, size, b, size, t); - } + if (size == 8) emit(con, eor(dst->high, a->high, b->high)); + emit(con, eor(dst->low, a->low, b->low)); } void -xorR(Context* com, unsigned size, Assembler::Register* a, - Assembler::Register* b, Assembler::Register* dst) +moveAR2(Context* c, unsigned srcSize, Assembler::Address* src, + unsigned dstSize, Assembler::Register* dst) { - if (size == 8) emit(com, eor(dst->high, a->high, b->high)); - emit(com, eor(dst->low, a->low, b->low)); -} + assert(c, srcSize == 4 and dstSize == 4); -void -xorC(Context* com, unsigned size, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) -{ - assert(con, size == BytesPerWord); + Assembler::Constant constant(src->address); + moveCR(c, srcSize, &constant, dstSize, dst); - int32_t i = getValue(a); - if (i) { - emit(con, eori(t->low, b->low, lo8(i))); - if (!isInt8(i)) { - emit(con, eori(t->low, b->low, hi8(i), 12)); - if (!isInt16(i)) { - emit(con, eori(t->low, b->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { - emit(con, eori(t->low, b->low, hi8(hi16(i)), 4)); - } - } - } - } else { - moveRR(con, size, b, size, t); - } + Assembler::Memory memory(dst->low, 0, -1, 0); + moveMR(c, dstSize, &memory, dstSize, dst); } void moveAR(Context* c, unsigned srcSize, Assembler::Address* src, unsigned dstSize, Assembler::Register* dst) { - assert(c, srcSize == 4 and dstSize == 4); - - Assembler::Constant constant(src->address); - Assembler::Memory memory(dst->low, 0, -1, 0); - - moveCR(c, srcSize, &constant, dstSize, dst); - moveMR(c, dstSize, &memory, dstSize, dst); + moveAR2(c, srcSize, src, dstSize, dst); } void @@ -1040,6 +1281,8 @@ compareRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, unsigned bSize UNUSED, Assembler::Register* b) { assert(c, aSize == 4 and bSize == 4); + assert(c, b->low != a->low); + emit(c, cmp(b->low, a->low)); } @@ -1049,7 +1292,7 @@ compareCR(Context* c, unsigned aSize, Assembler::Constant* a, { assert(c, aSize == 4 and bSize == 4); - if (a->value->resolved() and isInt16(a->value->value())) { + if (a->value->resolved() and isOfWidth(a->value->value(), 8)) { emit(c, cmpi(b->low, a->value->value())); } else { Assembler::Register tmp(c->client->acquireTemporary()); @@ -1083,105 +1326,185 @@ compareRM(Context* c, unsigned aSize, Assembler::Register* a, c->client->releaseTemporary(tmp.low); } -void -longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, - Assembler::Operand* bl, Assembler::Operand* bh, - Assembler::Register* dst, BinaryOperationType compareSigned, - BinaryOperationType compareUnsigned) +int32_t +branch(Context* c, TernaryOperation op) { - ResolvedPromise negativePromise(-1); - Assembler::Constant negative(&negativePromise); + switch (op) { + case JumpIfEqual: + return beq(0); + + case JumpIfNotEqual: + return bne(0); + + case JumpIfLess: + return blt(0); + + case JumpIfGreater: + return bgt(0); + + case JumpIfLessOrEqual: + return ble(0); + + case JumpIfGreaterOrEqual: + return bge(0); + + default: + abort(c); + } +} - ResolvedPromise zeroPromise(0); - Assembler::Constant zero(&zeroPromise); +void +conditional(Context* c, int32_t branch, Assembler::Constant* target) +{ + appendOffsetTask(c, target->value, offset(c)); + emit(c, branch); +} - ResolvedPromise positivePromise(1); - Assembler::Constant positive(&positivePromise); +void +branch(Context* c, TernaryOperation op, Assembler::Constant* target) +{ + conditional(c, branch(c, op), target); +} +void +branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, + Assembler::Operand* ah, Assembler::Operand* bl, + Assembler::Operand* bh, Assembler::Constant* target, + BinaryOperationType compareSigned, + BinaryOperationType compareUnsigned) +{ compareSigned(c, 4, ah, 4, bh); - unsigned less = c->code.length(); - emit(c, blt(0)); + unsigned next = 0; + + switch (op) { + case JumpIfEqual: + next = c->code.length(); + emit(c, bne(0)); - unsigned greater = c->code.length(); - emit(c, bgt(0)); + compareSigned(c, 4, al, 4, bl); + conditional(c, beq(0), target); + break; - compareUnsigned(c, 4, al, 4, bl); + case JumpIfNotEqual: + conditional(c, bne(0), target); - unsigned above = c->code.length(); - emit(c, bgt(0)); + compareSigned(c, 4, al, 4, bl); + conditional(c, bne(0), target); + break; - unsigned below = c->code.length(); - emit(c, blt(0)); + case JumpIfLess: + conditional(c, blt(0), target); - moveCR(c, 4, &zero, 4, dst); + next = c->code.length(); + emit(c, bgt(0)); - unsigned nextFirst = c->code.length(); - emit(c, b(0)); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, blo(0), target); + break; - updateOffset - (c->s, c->code.data + less, true, reinterpret_cast - (c->code.data + c->code.length())); + case JumpIfGreater: + conditional(c, bgt(0), target); - updateOffset - (c->s, c->code.data + below, true, reinterpret_cast - (c->code.data + c->code.length())); + next = c->code.length(); + emit(c, blt(0)); - moveCR(c, 4, &negative, 4, dst); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, bhi(0), target); + break; - unsigned nextSecond = c->code.length(); - emit(c, b(0)); + case JumpIfLessOrEqual: + conditional(c, blt(0), target); - updateOffset - (c->s, c->code.data + greater, true, reinterpret_cast - (c->code.data + c->code.length())); + next = c->code.length(); + emit(c, bgt(0)); - updateOffset - (c->s, c->code.data + above, true, reinterpret_cast - (c->code.data + c->code.length())); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, bls(0), target); + break; - moveCR(c, 4, &positive, 4, dst); + case JumpIfGreaterOrEqual: + conditional(c, bgt(0), target); - updateOffset - (c->s, c->code.data + nextFirst, false, reinterpret_cast - (c->code.data + c->code.length())); + next = c->code.length(); + emit(c, blt(0)); - updateOffset - (c->s, c->code.data + nextSecond, false, reinterpret_cast - (c->code.data + c->code.length())); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, bhs(0), target); + break; + + default: + abort(c); + } + + if (next) { + updateOffset + (c->s, c->code.data + next, reinterpret_cast + (c->code.data + c->code.length())); + } } void -longCompareR(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Register* b, Assembler::Register* dst) +branchRR(Context* c, TernaryOperation op, unsigned size, + Assembler::Register* a, Assembler::Register* b, + Assembler::Constant* target) { - assert(c, size == 8); - - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - longCompare(c, a, &ah, b, &bh, dst, CAST2(compareRR), - CAST2(compareUnsignedRR)); + if (size > BytesPerWord) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + branchLong(c, op, a, &ah, b, &bh, target, CAST2(compareRR), + CAST2(compareRR)); + } else { + compareRR(c, size, a, size, b); + branch(c, op, target); + } } void -longCompareC(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) +branchCR(Context* c, TernaryOperation op, unsigned size, + Assembler::Constant* a, Assembler::Register* b, + Assembler::Constant* target) { - assert(c, size == 8); + if (size > BytesPerWord) { + int64_t v = a->value->value(); - int64_t v = a->value->value(); + ResolvedPromise low(v & ~static_cast(0)); + Assembler::Constant al(&low); - ResolvedPromise low(v & ~static_cast(0)); - Assembler::Constant al(&low); - - ResolvedPromise high((v >> 32) & ~static_cast(0)); - Assembler::Constant ah(&high); - - Assembler::Register bh(b->high); - - longCompare(c, &al, &ah, b, &bh, dst, CAST2(compareCR), - CAST2(compareUnsignedCR)); + ResolvedPromise high((v >> 32) & ~static_cast(0)); + Assembler::Constant ah(&high); + + Assembler::Register bh(b->high); + + branchLong(c, op, &al, &ah, b, &bh, target, CAST2(compareCR), + CAST2(compareCR)); + } else { + compareCR(c, size, a, size, b); + branch(c, op, target); + } +} + +void +branchRM(Context* c, TernaryOperation op, unsigned size, + Assembler::Register* a, Assembler::Memory* b, + Assembler::Constant* target) +{ + assert(c, size <= BytesPerWord); + + compareRM(c, size, a, size, b); + branch(c, op, target); +} + +void +branchCM(Context* c, TernaryOperation op, unsigned size, + Assembler::Constant* a, Assembler::Memory* b, + Assembler::Constant* target) +{ + assert(c, size <= BytesPerWord); + + compareCM(c, size, a, size, b); + branch(c, op, target); } ShiftMaskPromise* @@ -1243,7 +1566,7 @@ callC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - appendOffsetTask(c, target->value, offset(c), false); + appendOffsetTask(c, target->value, offset(c)); emit(c, bl(0)); } @@ -1252,8 +1575,8 @@ longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - Assembler::Register tmp(0); - moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); + Assembler::Register tmp(4); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, offset(c)); callR(c, BytesPerWord, &tmp); } @@ -1262,8 +1585,8 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - Assembler::Register tmp(0); - moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); + Assembler::Register tmp(4); // a non-arg reg that we don't mind clobbering + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, offset(c)); jumpR(c, BytesPerWord, &tmp); } @@ -1272,77 +1595,85 @@ jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - appendOffsetTask(c, target->value, offset(c), false); + appendOffsetTask(c, target->value, offset(c)); emit(c, b(0)); } -void -jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), EQ)); -} - -void -jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), NE)); -} - -void -jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), GT)); -} - -void -jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), GE)); -} - -void -jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), LS)); -} - -void -jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), LE)); -} - void return_(Context* c) { - emit(c, mov(15, 14)); + emit(c, bx(LinkRegister)); } void -memoryBarrier(Context* c) {} +memoryBarrier(Context*) {} // END OPERATION COMPILERS +unsigned +argumentFootprint(unsigned footprint) +{ + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); +} + +void +nextFrame(ArchitectureContext* c, uint32_t* start, unsigned size UNUSED, + unsigned footprint, void* link, void*, + unsigned targetParameterFootprint UNUSED, void** ip, void** stack) +{ + assert(c, *ip >= start); + assert(c, *ip <= start + (size / BytesPerWord)); + + uint32_t* instruction = static_cast(*ip); + + if ((*start >> 20) == 0xe59) { + // skip stack overflow check + start += 3; + } + + if (instruction <= start) { + *ip = link; + return; + } + + unsigned offset = footprint + FrameHeaderSize; + + if (instruction <= start + 2) { + *ip = link; + *stack = static_cast(*stack) + offset; + return; + } + + if (*instruction == 0xe12fff1e) { // return + *ip = link; + return; + } + + if (TailCalls) { + if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { + offset += argumentFootprint(targetParameterFootprint) + - StackAlignmentInWords; + } + + // check for post-non-tail-call stack adjustment of the form "add + // sp, sp, #offset": + if ((*instruction >> 12) == 0xe24dd) { + unsigned value = *instruction & 0xff; + unsigned rotation = (*instruction >> 8) & 0xf; + switch (rotation) { + case 0: offset -= value / BytesPerWord; break; + case 15: offset -= value; break; + default: abort(c); + } + } + + // todo: check for and handle tail calls + } + + *ip = static_cast(*stack)[offset - 1]; + *stack = static_cast(*stack) + offset; +} + void populateTables(ArchitectureContext* c) { @@ -1355,96 +1686,90 @@ populateTables(ArchitectureContext* c) UnaryOperationType* uo = c->unaryOperations; BinaryOperationType* bo = c->binaryOperations; TernaryOperationType* to = c->ternaryOperations; + BranchOperationType* bro = c->branchOperations; zo[Return] = return_; zo[LoadBarrier] = memoryBarrier; zo[StoreStoreBarrier] = memoryBarrier; zo[StoreLoadBarrier] = memoryBarrier; - uo[index(LongCall, C)] = CAST1(longCallC); + uo[index(c, LongCall, C)] = CAST1(longCallC); - uo[index(LongJump, C)] = CAST1(longJumpC); + uo[index(c, AlignedLongCall, C)] = CAST1(longCallC); - uo[index(Jump, R)] = CAST1(jumpR); - uo[index(Jump, C)] = CAST1(jumpC); + uo[index(c, LongJump, C)] = CAST1(longJumpC); - uo[index(AlignedJump, R)] = CAST1(jumpR); - uo[index(AlignedJump, C)] = CAST1(jumpC); + uo[index(c, AlignedLongJump, C)] = CAST1(longJumpC); - uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC); - uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC); - uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC); - uo[index(JumpIfGreaterOrEqual, C)] = CAST1(jumpIfGreaterOrEqualC); - uo[index(JumpIfLess, C)] = CAST1(jumpIfLessC); - uo[index(JumpIfLessOrEqual, C)] = CAST1(jumpIfLessOrEqualC); + uo[index(c, Jump, R)] = CAST1(jumpR); + uo[index(c, Jump, C)] = CAST1(jumpC); - uo[index(Call, C)] = CAST1(callC); - uo[index(Call, R)] = CAST1(callR); + uo[index(c, AlignedJump, R)] = CAST1(jumpR); + uo[index(c, AlignedJump, C)] = CAST1(jumpC); - uo[index(AlignedCall, C)] = CAST1(callC); - uo[index(AlignedCall, R)] = CAST1(callR); + uo[index(c, Call, C)] = CAST1(callC); + uo[index(c, Call, R)] = CAST1(callR); - bo[index(Move, R, R)] = CAST2(moveRR); - bo[index(Move, C, R)] = CAST2(moveCR); - bo[index(Move, C, M)] = CAST2(moveCM); - bo[index(Move, M, R)] = CAST2(moveMR); - bo[index(Move, R, M)] = CAST2(moveRM); - bo[index(Move, A, R)] = CAST2(moveAR); + uo[index(c, AlignedCall, C)] = CAST1(callC); + uo[index(c, AlignedCall, R)] = CAST1(callR); - bo[index(MoveZ, R, R)] = CAST2(moveZRR); - bo[index(MoveZ, M, R)] = CAST2(moveZMR); - bo[index(MoveZ, C, R)] = CAST2(moveCR); + bo[index(c, Move, R, R)] = CAST2(moveRR); + bo[index(c, Move, C, R)] = CAST2(moveCR); + bo[index(c, Move, C, M)] = CAST2(moveCM); + bo[index(c, Move, M, R)] = CAST2(moveMR); + bo[index(c, Move, R, M)] = CAST2(moveRM); + bo[index(c, Move, A, R)] = CAST2(moveAR); - bo[index(Compare, R, R)] = CAST2(compareRR); - bo[index(Compare, C, R)] = CAST2(compareCR); - bo[index(Compare, R, M)] = CAST2(compareRM); - bo[index(Compare, C, M)] = CAST2(compareCM); + bo[index(c, MoveZ, R, R)] = CAST2(moveZRR); + bo[index(c, MoveZ, M, R)] = CAST2(moveZMR); + bo[index(c, MoveZ, C, R)] = CAST2(moveCR); - bo[index(Negate, R, R)] = CAST2(negateRR); + bo[index(c, Negate, R, R)] = CAST2(negateRR); - to[index(Add, R)] = CAST3(addR); - to[index(Add, C)] = CAST3(addC); + to[index(c, Add, R)] = CAST3(addR); - to[index(Subtract, R)] = CAST3(subR); - to[index(Subtract, C)] = CAST3(subC); + to[index(c, Subtract, R)] = CAST3(subR); - to[index(Multiply, R)] = CAST3(multiplyR); + to[index(c, Multiply, R)] = CAST3(multiplyR); - to[index(Divide, R)] = CAST3(divideR); + to[index(c, ShiftLeft, R)] = CAST3(shiftLeftR); + to[index(c, ShiftLeft, C)] = CAST3(shiftLeftC); - to[index(Remainder, R)] = CAST3(remainderR); + to[index(c, ShiftRight, R)] = CAST3(shiftRightR); + to[index(c, ShiftRight, C)] = CAST3(shiftRightC); - to[index(ShiftLeft, R)] = CAST3(shiftLeftR); - to[index(ShiftLeft, C)] = CAST3(shiftLeftC); + to[index(c, UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); + to[index(c, UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); - to[index(ShiftRight, R)] = CAST3(shiftRightR); - to[index(ShiftRight, C)] = CAST3(shiftRightC); + to[index(c, And, R)] = CAST3(andR); + to[index(c, And, C)] = CAST3(andC); - to[index(UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); - to[index(UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); + to[index(c, Or, R)] = CAST3(orR); - to[index(And, C)] = CAST3(andC); - to[index(And, R)] = CAST3(andR); + to[index(c, Xor, R)] = CAST3(xorR); - to[index(Or, C)] = CAST3(orC); - to[index(Or, R)] = CAST3(orR); - - to[index(Xor, C)] = CAST3(xorC); - to[index(Xor, R)] = CAST3(xorR); - - to[index(LongCompare, R)] = CAST3(longCompareR); - to[index(LongCompare, C)] = CAST3(longCompareC); + bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR); + bro[branchIndex(c, C, R)] = CAST_BRANCH(branchCR); + bro[branchIndex(c, C, M)] = CAST_BRANCH(branchCM); + bro[branchIndex(c, R, M)] = CAST_BRANCH(branchRM); } -// TODO class MyArchitecture: public Assembler::Architecture { public: MyArchitecture(System* system): c(system), referenceCount(0) { populateTables(&c); } - virtual unsigned registerCount() { - return 16; + virtual unsigned floatRegisterSize() { + return 0; + } + + virtual uint32_t generalRegisterMask() { + return 0xFFFF; + } + + virtual uint32_t floatRegisterMask() { + return 0; } virtual int stack() { @@ -1456,11 +1781,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual int returnLow() { - return 4; + return 0; } virtual int returnHigh() { - return (BytesPerWord == 4 ? 3 : NoRegister); + return 1; } virtual int virtualCallTarget() { @@ -1471,19 +1796,20 @@ class MyArchitecture: public Assembler::Architecture { return 3; } - virtual bool condensedAddressing() { - return false; - } - virtual bool bigEndian() { return false; } + virtual uintptr_t maximumImmediateJump() { + return 0x1FFFFFF; + } + virtual bool reserved(int register_) { switch (register_) { + case LinkRegister: case StackRegister: case ThreadRegister: - case 15: + case ProgramCounter: return true; default: @@ -1496,7 +1822,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); + return ::argumentFootprint(footprint); + } + + virtual bool argumentAlignment() { + return true; } virtual unsigned argumentRegisterCount() { @@ -1506,9 +1836,9 @@ class MyArchitecture: public Assembler::Architecture { virtual int argumentRegister(unsigned index) { assert(&c, index < argumentRegisterCount()); - return index + 0; + return index; } - + virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } @@ -1522,20 +1852,25 @@ class MyArchitecture: public Assembler::Architecture { } virtual void updateCall(UnaryOperation op UNUSED, - bool assertAlignment UNUSED, void* returnAddress, + void* returnAddress, void* newTarget) { switch (op) { case Call: - case Jump: { - updateOffset(c.s, static_cast(returnAddress) - 4, false, + case Jump: + case AlignedCall: + case AlignedJump: { + updateOffset(c.s, static_cast(returnAddress) - 4, reinterpret_cast(newTarget)); } break; case LongCall: - case LongJump: { - updateImmediate(c.s, static_cast(returnAddress) - 12, - reinterpret_cast(newTarget), BytesPerWord); + case LongJump: + case AlignedLongCall: + case AlignedLongJump: { + uint32_t* p = static_cast(returnAddress) - 2; + *reinterpret_cast(p + (((*p & PoolOffsetMask) + 8) / 4)) + = newTarget; } break; default: abort(&c); @@ -1546,26 +1881,30 @@ class MyArchitecture: public Assembler::Architecture { return 4; } - virtual uintptr_t getConstant(const void* src) { - const int32_t* p = static_cast(src); - return (p[0] << 16) | (p[1] & 0xFFFF); - } - virtual void setConstant(void* dst, uintptr_t constant) { - updateImmediate(c.s, dst, constant, BytesPerWord); + *static_cast(dst) = constant; } virtual unsigned alignFrameSize(unsigned sizeInWords) { - const unsigned alignment = StackAlignmentInBytes / BytesPerWord; - return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment); + return pad(sizeInWords + FrameHeaderSize, StackAlignmentInWords) + - FrameHeaderSize; + } + + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) + { + ::nextFrame(&c, static_cast(start), size, footprint, link, + stackLimit, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { - return stack ? static_cast(stack)[2] : 0; + return stack ? static_cast(stack)[returnAddressOffset()] : 0; } virtual unsigned frameHeaderSize() { - return 0; + return FrameHeaderSize; } virtual unsigned frameReturnAddressSize() { @@ -1573,23 +1912,33 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned frameFooterSize() { - return FrameFooterSize; + return 0; } virtual int returnAddressOffset() { - return 8 / BytesPerWord; + return -1; } virtual int framePointerOffset() { return 0; } - virtual void nextFrame(void** stack, void**) { - assert(&c, *static_cast(*stack) != *stack); - - *stack = *static_cast(*stack); + virtual BinaryOperation hasBinaryIntrinsic(Thread*, object) { + return NoBinaryOperation; } - + + virtual TernaryOperation hasTernaryIntrinsic(Thread*, object) { + return NoTernaryOperation; + } + + virtual bool alwaysCondensed(BinaryOperation) { + return false; + } + + virtual bool alwaysCondensed(TernaryOperation) { + return false; + } + virtual void plan (UnaryOperation, unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, @@ -1600,28 +1949,46 @@ class MyArchitecture: public Assembler::Architecture { *thunk = false; } - virtual void plan + virtual void planSource (BinaryOperation op, unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, - unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, - bool* thunk) + unsigned, bool* thunk) { *aTypeMask = ~0; *aRegisterMask = ~static_cast(0); - *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); - *bRegisterMask = ~static_cast(0); - *thunk = false; switch (op) { - case Compare: - *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); - *bTypeMask = (1 << RegisterOperand); - break; - case Negate: *aTypeMask = (1 << RegisterOperand); + break; + + case Absolute: + case FloatAbsolute: + case FloatSquareRoot: + case FloatNegate: + case Float2Float: + case Float2Int: + case Int2Float: + *thunk = true; + break; + + default: + break; + } + } + + virtual void planDestination + (BinaryOperation op, + unsigned, uint8_t, uint64_t, + unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask) + { + *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *bRegisterMask = ~static_cast(0); + + switch (op) { + case Negate: *bTypeMask = (1 << RegisterOperand); break; @@ -1630,12 +1997,30 @@ class MyArchitecture: public Assembler::Architecture { } } - virtual void plan + virtual void planMove + (unsigned, uint8_t* srcTypeMask, uint64_t* srcRegisterMask, + uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask, + uint8_t dstTypeMask, uint64_t) + { + *srcTypeMask = ~0; + *srcRegisterMask = ~static_cast(0); + + *tmpTypeMask = 0; + *tmpRegisterMask = 0; + + if (dstTypeMask & (1 << MemoryOperand)) { + // can't move directly from memory or constant to memory + *srcTypeMask = 1 << RegisterOperand; + *tmpTypeMask = 1 << RegisterOperand; + *tmpRegisterMask = ~static_cast(0); + } + } + + virtual void planSource (TernaryOperation op, - unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, - unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, - unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask, - bool* thunk) + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned, bool* thunk) { *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); *aRegisterMask = ~static_cast(0); @@ -1646,33 +2031,58 @@ class MyArchitecture: public Assembler::Architecture { *thunk = false; switch (op) { - case Add: - case Subtract: - if (aSize == 8) { - *aTypeMask = *bTypeMask = (1 << RegisterOperand); - } + case ShiftLeft: + case ShiftRight: + case UnsignedShiftRight: + if (bSize == 8) *aTypeMask = *bTypeMask = (1 << RegisterOperand); break; + case Add: + case Subtract: + case Or: + case Xor: case Multiply: *aTypeMask = *bTypeMask = (1 << RegisterOperand); break; - case LongCompare: - *bTypeMask = (1 << RegisterOperand); - break; - case Divide: case Remainder: - *bTypeMask = ~0; + case FloatAdd: + case FloatSubtract: + case FloatMultiply: + case FloatDivide: + case FloatRemainder: + case JumpIfFloatEqual: + case JumpIfFloatNotEqual: + case JumpIfFloatLess: + case JumpIfFloatGreater: + case JumpIfFloatLessOrEqual: + case JumpIfFloatGreaterOrEqual: + case JumpIfFloatLessOrUnordered: + case JumpIfFloatGreaterOrUnordered: + case JumpIfFloatLessOrEqualOrUnordered: + case JumpIfFloatGreaterOrEqualOrUnordered: *thunk = true; break; default: break; } + } - *cTypeMask = *bTypeMask; - *cRegisterMask = *bRegisterMask; + virtual void planDestination + (TernaryOperation op, + unsigned, uint8_t, uint64_t, + unsigned, uint8_t, const uint64_t, + unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask) + { + if (isBranch(op)) { + *cTypeMask = (1 << ConstantOperand); + *cRegisterMask = 0; + } else { + *cTypeMask = (1 << RegisterOperand); + *cRegisterMask = ~static_cast(0); + } } virtual void acquire() { @@ -1704,7 +2114,19 @@ class MyAssembler: public Assembler { return arch_; } - virtual void saveFrame(unsigned stackOffset, unsigned) { + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) + { + Register stack(StackRegister); + Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); + Constant handlerConstant + (new (c.zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(handler)); + branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, + &handlerConstant); + } + + virtual void saveFrame(unsigned stackOffset) { Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); @@ -1740,7 +2162,7 @@ class MyAssembler: public Assembler { offset += ceiling(arguments[i].size, BytesPerWord); } else { - Memory dst(ThreadRegister, (offset + FrameFooterSize) * BytesPerWord); + Memory dst(StackRegister, offset * BytesPerWord); apply(Move, arguments[i].size, arguments[i].type, arguments[i].operand, @@ -1752,117 +2174,110 @@ class MyAssembler: public Assembler { } virtual void allocateFrame(unsigned footprint) { - Register returnAddress(0); - emit(&c, mov(returnAddress.low, 14)); + footprint += FrameHeaderSize; - Memory returnAddressDst(StackRegister, 8); + // larger frames may require multiple subtract/add instructions + // to allocate/deallocate, and nextFrame will need to be taught + // how to handle them: + assert(&c, footprint < 256); + + Register stack(StackRegister); + ResolvedPromise footprintPromise(footprint * BytesPerWord); + Constant footprintConstant(&footprintPromise); + subC(&c, BytesPerWord, &footprintConstant, &stack, &stack); + + Register returnAddress(LinkRegister); + Memory returnAddressDst(StackRegister, (footprint - 1) * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); - - Register stack(StackRegister); - Memory stackDst(StackRegister, -footprint * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); } - virtual void adjustFrame(unsigned footprint) { - Register nextStack(0); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack); - - Memory stackDst(StackRegister, -footprint * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst); + virtual void adjustFrame(unsigned difference) { + Register stack(StackRegister); + ResolvedPromise differencePromise(difference * BytesPerWord); + Constant differenceConstant(&differencePromise); + subC(&c, BytesPerWord, &differenceConstant, &stack, &stack); } - virtual void popFrame() { - Register stack(StackRegister); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); + virtual void popFrame(unsigned footprint) { + footprint += FrameHeaderSize; - Register returnAddress(0); - Memory returnAddressSrc(StackRegister, 8); + Register returnAddress(LinkRegister); + Memory returnAddressSrc(StackRegister, (footprint - 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); - emit(&c, mov(14, returnAddress.low)); + Register stack(StackRegister); + ResolvedPromise footprintPromise(footprint * BytesPerWord); + Constant footprintConstant(&footprintPromise); + addC(&c, BytesPerWord, &footprintConstant, &stack, &stack); } virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, - int framePointerSurrogate) + int framePointerSurrogate UNUSED) { + assert(&c, framePointerSurrogate == NoRegister); + if (TailCalls) { if (offset) { - Register tmp(0); - Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); - moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); + footprint += FrameHeaderSize; + + Register link(LinkRegister); + Memory returnAddressSrc + (StackRegister, (footprint - 1) * BytesPerWord); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &link); - emit(&c, mov(14, tmp.low)); - - Memory stackSrc(StackRegister, footprint * BytesPerWord); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); - - Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + Register stack(StackRegister); + ResolvedPromise footprintPromise((footprint - offset) * BytesPerWord); + Constant footprintConstant(&footprintPromise); + addC(&c, BytesPerWord, &footprintConstant, &stack, &stack); if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); Register ras(returnAddressSurrogate); - Memory dst(StackRegister, 8 + (offset * BytesPerWord)); + Memory dst(StackRegister, (offset - 1) * BytesPerWord); moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); } - - if (framePointerSurrogate != NoRegister) { - assert(&c, offset > 0); - - Register fps(framePointerSurrogate); - Memory dst(StackRegister, offset * BytesPerWord); - moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); - } } else { - popFrame(); + popFrame(footprint); } } else { abort(&c); } } - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { - popFrame(); + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) + { + popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); + unsigned offset; if (TailCalls and argumentFootprint > StackAlignmentInWords) { - Register tmp(0); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); + offset = argumentFootprint - StackAlignmentInWords; - Memory stackDst(StackRegister, - (argumentFootprint - StackAlignmentInWords) - * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + Register stack(StackRegister); + ResolvedPromise adjustmentPromise(offset * BytesPerWord); + Constant adjustment(&adjustmentPromise); + addC(&c, BytesPerWord, &adjustment, &stack, &stack); + } else { + offset = 0; } return_(&c); } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) { - popFrame(); - - Register tmp1(0); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1); - - Register tmp2(5); - Memory newStackSrc(ThreadRegister, stackOffsetFromThread); - moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &tmp2); + popFrame(frameFootprint); Register stack(StackRegister); - subR(&c, BytesPerWord, &stack, &tmp2, &tmp2); - - Memory stackDst(StackRegister, 0, tmp2.low); - moveAndUpdateRM(&c, BytesPerWord, &tmp1, BytesPerWord, &stackDst); + Memory newStackSrc(ThreadRegister, stackOffsetFromThread); + moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &stack); return_(&c); } @@ -1874,46 +2289,115 @@ class MyAssembler: public Assembler { virtual void apply(UnaryOperation op, unsigned aSize, OperandType aType, Operand* aOperand) { - arch_->c.unaryOperations[index(op, aType)](&c, aSize, aOperand); + arch_->c.unaryOperations[index(&(arch_->c), op, aType)] + (&c, aSize, aOperand); } virtual void apply(BinaryOperation op, unsigned aSize, OperandType aType, Operand* aOperand, unsigned bSize, OperandType bType, Operand* bOperand) { - arch_->c.binaryOperations[index(op, aType, bType)] + arch_->c.binaryOperations[index(&(arch_->c), op, aType, bType)] (&c, aSize, aOperand, bSize, bOperand); } virtual void apply(TernaryOperation op, - unsigned, OperandType aType, Operand* aOperand, + unsigned aSize, OperandType aType, Operand* aOperand, unsigned bSize, OperandType bType UNUSED, Operand* bOperand, unsigned cSize UNUSED, OperandType cType UNUSED, Operand* cOperand) { - assert(&c, bSize == cSize); - assert(&c, bType == RegisterOperand); - assert(&c, cType == RegisterOperand); + if (isBranch(op)) { + assert(&c, aSize == bSize); + assert(&c, cSize == BytesPerWord); + assert(&c, cType == ConstantOperand); - arch_->c.ternaryOperations[index(op, aType)] - (&c, bSize, aOperand, bOperand, cOperand); + arch_->c.branchOperations[branchIndex(&(arch_->c), aType, bType)] + (&c, op, aSize, aOperand, bOperand, cOperand); + } else { + assert(&c, bSize == cSize); + assert(&c, bType == RegisterOperand); + assert(&c, cType == RegisterOperand); + + arch_->c.ternaryOperations[index(&(arch_->c), op, aType)] + (&c, bSize, aOperand, bOperand, cOperand); + } } virtual void writeTo(uint8_t* dst) { c.result = dst; + unsigned dstOffset = 0; for (MyBlock* b = c.firstBlock; b; b = b->next) { - memcpy(dst + b->start, c.code.data + b->offset, b->size); + if (DebugPool) { + fprintf(stderr, "write block %p\n", b); + } + + unsigned blockOffset = 0; + for (PoolEvent* e = b->poolEventHead; e; e = e->next) { + unsigned size = e->offset - blockOffset; + memcpy(dst + dstOffset, c.code.data + b->offset + blockOffset, size); + blockOffset = e->offset; + dstOffset += size; + + unsigned poolSize = 0; + for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { + if (DebugPool) { + fprintf(stderr, "visit pool offset %p %d in block %p\n", + o, o->offset, b); + } + + poolSize += BytesPerWord; + + unsigned entry = dstOffset + poolSize; + + o->entry->address = dst + entry; + + unsigned instruction = o->block->start + + padding(o->block, o->offset) + o->offset; + + int32_t v = (entry - 8) - instruction; + expect(&c, v == (v & PoolOffsetMask)); + + int32_t* p = reinterpret_cast(dst + instruction); + *p = (v & PoolOffsetMask) | ((~PoolOffsetMask) & *p); + } + + write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2)); + + dstOffset += poolSize + BytesPerWord; + } + + unsigned size = b->size - blockOffset; + + memcpy(dst + dstOffset, + c.code.data + b->offset + blockOffset, + size); + + dstOffset += size; } - + for (Task* t = c.tasks; t; t = t->next) { t->run(&c); } + + for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { + if (e->constant->resolved()) { + *static_cast(e->address) = e->constant->value(); + } else { + new (e->constant->listen(sizeof(ConstantPoolListener))) + ConstantPoolListener(c.s, static_cast(e->address), + e->callOffset + ? dst + e->callOffset->value() + 8 + : 0); + } +// fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); + } } - virtual Promise* offset() { - return ::offset(&c); + virtual Promise* offset(bool forTrace) { + return ::offset(&c, forTrace); } virtual Block* endBlock(bool startNew) { @@ -1921,17 +2405,55 @@ class MyAssembler: public Assembler { b->size = c.code.length() - b->offset; if (startNew) { c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) - MyBlock(c.code.length()); + MyBlock(&c, c.code.length()); } else { c.lastBlock = 0; } return b; } + virtual void endEvent() { + MyBlock* b = c.lastBlock; + unsigned thisEventOffset = c.code.length() - b->offset; + if (b->poolOffsetHead) { + int32_t v = (thisEventOffset + BytesPerWord - 8) + - b->poolOffsetHead->offset; + + if (v > 0 and v != (v & PoolOffsetMask)) { + appendPoolEvent + (&c, b, b->lastEventOffset, b->poolOffsetHead, + b->lastPoolOffsetTail); + + if (DebugPool) { + for (PoolOffset* o = b->poolOffsetHead; + o != b->lastPoolOffsetTail->next; o = o->next) + { + fprintf(stderr, + "in endEvent, include %p %d in pool event %p at offset %d " + "in block %p\n", + o, o->offset, b->poolEventTail, b->lastEventOffset, b); + } + } + + b->poolOffsetHead = b->lastPoolOffsetTail->next; + b->lastPoolOffsetTail->next = 0; + if (b->poolOffsetHead == 0) { + b->poolOffsetTail = 0; + } + } + } + b->lastEventOffset = thisEventOffset; + b->lastPoolOffsetTail = b->poolOffsetTail; + } + virtual unsigned length() { return c.code.length(); } + virtual unsigned footerSize() { + return 0; + } + virtual void dispose() { c.code.dispose(); } @@ -1945,7 +2467,7 @@ class MyAssembler: public Assembler { namespace vm { Assembler::Architecture* -makeArchitecture(System* system) +makeArchitecture(System* system, bool) { return new (allocate(system, sizeof(MyArchitecture))) MyArchitecture(system); } diff --git a/src/arm.h b/src/arm.h index b7b844685d..93f80842c1 100644 --- a/src/arm.h +++ b/src/arm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -14,9 +14,12 @@ #include "types.h" #include "common.h" +#define VA_LIST(x) (&(x)) + #define IP_REGISTER(context) (context->uc_mcontext.arm_pc) #define STACK_REGISTER(context) (context->uc_mcontext.arm_sp) #define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip) +#define LINK_REGISTER(context) (context->uc_mcontext.arm_lr) extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, @@ -27,7 +30,7 @@ namespace vm { inline void trap() { - asm("nop"); + asm("bkpt"); } inline void @@ -55,9 +58,11 @@ loadMemoryBarrier() } inline void -syncInstructionCache(const void* start UNUSED, unsigned size UNUSED) +syncInstructionCache(const void* start, unsigned size) { - asm("nop"); + __clear_cache + (const_cast(start), + const_cast(static_cast(start) + size)); } typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); @@ -101,6 +106,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, memcpy(gprTable + gprIndex, arguments + ai, 8); gprIndex += 8 / BytesPerWord; } else { // pass argument on stack + gprIndex = GprCount; if (stackIndex & 1) { // 8-byte alignment memset(stack + stackIndex, 0, 4); // probably not necessary, but for good luck ++stackIndex; diff --git a/src/assembler.h b/src/assembler.h index 918c548acb..d122a53207 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -22,6 +22,12 @@ const bool TailCalls = true; const bool TailCalls = false; #endif +#ifdef AVIAN_USE_FRAME_POINTER +const bool UseFramePointer = true; +#else +const bool UseFramePointer = false; +#endif + enum Operation { Return, LoadBarrier, @@ -323,6 +329,7 @@ class Assembler { virtual unsigned frameFootprint(unsigned footprint) = 0; virtual unsigned argumentFootprint(unsigned footprint) = 0; + virtual bool argumentAlignment() = 0; virtual unsigned argumentRegisterCount() = 0; virtual int argumentRegister(unsigned index) = 0; @@ -337,13 +344,16 @@ class Assembler { virtual unsigned alignFrameSize(unsigned sizeInWords) = 0; + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) = 0; virtual void* frameIp(void* stack) = 0; virtual unsigned frameHeaderSize() = 0; virtual unsigned frameReturnAddressSize() = 0; virtual unsigned frameFooterSize() = 0; virtual int returnAddressOffset() = 0; virtual int framePointerOffset() = 0; - virtual void nextFrame(void** stack, void** base) = 0; virtual void plan (UnaryOperation op, @@ -385,17 +395,21 @@ class Assembler { virtual Architecture* arch() = 0; - virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) = 0; + virtual void saveFrame(unsigned stackOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; - virtual void adjustFrame(unsigned footprint) = 0; - virtual void popFrame() = 0; + virtual void adjustFrame(unsigned difference) = 0; + virtual void popFrame(unsigned footprint) = 0; virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) = 0; - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) = 0; - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) = 0; virtual void apply(Operation op) = 0; @@ -414,13 +428,15 @@ class Assembler { virtual void writeTo(uint8_t* dst) = 0; - virtual Promise* offset() = 0; + virtual Promise* offset(bool forTrace = false) = 0; virtual Block* endBlock(bool startNew) = 0; + virtual void endEvent() = 0; + virtual unsigned length() = 0; - virtual unsigned scratchSize() = 0; + virtual unsigned footerSize() = 0; virtual void dispose() = 0; }; diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index 8a6c2417d1..8af5c0cd58 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -232,7 +232,7 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, fileHeader.e_entry = 0; fileHeader.e_phoff = 0; fileHeader.e_shoff = sizeof(FileHeader); - fileHeader.e_flags = 0; + fileHeader.e_flags = (machine == EM_ARM ? 0x04000000 : 0); fileHeader.e_ehsize = sizeof(FileHeader); fileHeader.e_phentsize = 0; fileHeader.e_phnum = 0; diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index d153694b5c..d832703200 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -12,6 +12,32 @@ #include "stdio.h" #include "string.h" +#define V1(v) v + +#ifdef OPPOSITE_ENDIAN +# define V2(v) \ + ((((v) >> 8) & 0xFF) | \ + (((v) << 8))) +# define V4(v) \ + ((((v) >> 24) & 0x000000FF) | \ + (((v) >> 8) & 0x0000FF00) | \ + (((v) << 8) & 0x00FF0000) | \ + (((v) << 24))) +# define V8(v) \ + (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | \ + ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | \ + ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | \ + ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | \ + ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | \ + ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | \ + ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | \ + ((static_cast(v) << 56))) +#else +# define V2(v) v +# define V4(v) v +# define V8(v) v +#endif + #define MH_MAGIC_64 0xfeedfacf #define MH_MAGIC 0xfeedface @@ -37,6 +63,7 @@ #define CPU_SUBTYPE_POWERPC_ALL 0 #if (BITS_PER_WORD == 64) +# define VW(v) V8(v) # define Magic MH_MAGIC_64 # define Segment LC_SEGMENT_64 # define FileHeader mach_header_64 @@ -44,6 +71,7 @@ # define Section section_64 # define NList struct nlist_64 #elif (BITS_PER_WORD == 32) +# define VW(v) V4(v) # define Magic MH_MAGIC # define Segment LC_SEGMENT # define FileHeader mach_header @@ -191,32 +219,32 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, unsigned endNameLength = strlen(endName) + 1; FileHeader header = { - Magic, // magic - cpuType, - cpuSubType, - MH_OBJECT, // filetype, - 2, // ncmds - sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command), // sizeofcmds - 0 // flags + V4(Magic), // magic + V4(cpuType), + V4(cpuSubType), + V4(MH_OBJECT), // filetype, + V4(2), // ncmds + V4(sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command)), // sizeofcmds + V4(0) // flags }; SegmentCommand segment = { - Segment, // cmd - sizeof(SegmentCommand) + sizeof(Section), // cmdsize + V4(Segment), // cmd + V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize "", // segname - 0, // vmaddr - pad(size), // vmsize - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command), // fileoff - pad(size), // filesize - 7, // maxprot - 7, // initprot - 1, // nsects - 0 // flags + VW(0), // vmaddr + VW(pad(size)), // vmsize + VW(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command)), // fileoff + VW(pad(size)), // filesize + V4(7), // maxprot + V4(7), // initprot + V4(1), // nsects + V4(0) // flags }; strncpy(segment.segname, segmentName, sizeof(segment.segname)); @@ -224,55 +252,55 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, Section sect = { "", // sectname "", // segname - 0, // addr - pad(size), // size - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command), // offset - log(alignment), // align - 0, // reloff - 0, // nreloc - S_REGULAR, // flags - 0, // reserved1 - 0, // reserved2 + VW(0), // addr + VW(pad(size)), // size + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command)), // offset + V4(log(alignment)), // align + V4(0), // reloff + V4(0), // nreloc + V4(S_REGULAR), // flags + V4(0), // reserved1 + V4(0), // reserved2 }; strncpy(sect.segname, segmentName, sizeof(sect.segname)); strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); symtab_command symbolTable = { - LC_SYMTAB, // cmd - sizeof(symtab_command), // cmdsize - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size), // symoff - 2, // nsyms - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size) - + (sizeof(NList) * 2), // stroff - 1 + startNameLength + endNameLength, // strsize + V4(LC_SYMTAB), // cmd + V4(sizeof(symtab_command)), // cmdsize + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command) + + pad(size)), // symoff + V4(2), // nsyms + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command) + + pad(size) + + (sizeof(NList) * 2)), // stroff + V4(1 + startNameLength + endNameLength), // strsize }; NList symbolList[] = { { - 1, // n_un - N_SECT | N_EXT, // n_type - 1, // n_sect - 0, // n_desc - 0 // n_value + V4(1), // n_un + V1(N_SECT | N_EXT), // n_type + V1(1), // n_sect + V2(0), // n_desc + VW(0) // n_value }, { - 1 + startNameLength, // n_un - N_SECT | N_EXT, // n_type - 1, // n_sect - 0, // n_desc - size // n_value + V4(1 + startNameLength), // n_un + V1(N_SECT | N_EXT), // n_type + V1(1), // n_sect + V2(0), // n_desc + VW(size) // n_value } }; diff --git a/src/boot-javahome.cpp b/src/boot-javahome.cpp new file mode 100644 index 0000000000..8f32d545c7 --- /dev/null +++ b/src/boot-javahome.cpp @@ -0,0 +1,45 @@ +/* Copyright (c) 2010, 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. */ + +#ifdef _MSC_VER + +typedef unsigned char uint8_t; + +#else +# include "stdint.h" +#endif + +#ifdef BOOT_JAVAHOME + +#if (defined __MINGW32__) || (defined _MSC_VER) +# define EXPORT __declspec(dllexport) +# define SYMBOL(x) binary_javahome_jar_##x +#else +# define EXPORT __attribute__ ((visibility("default"))) +# define SYMBOL(x) _binary_javahome_jar_##x +#endif + +extern "C" { + + extern const uint8_t SYMBOL(start)[]; + extern const uint8_t SYMBOL(end)[]; + + EXPORT const uint8_t* + javahomeJar(unsigned* size) + { + *size = SYMBOL(end) - SYMBOL(start); + return SYMBOL(start); + } + +} + +#undef SYMBOL + +#endif//BOOT_JAVAHOME diff --git a/src/boot.cpp b/src/boot.cpp index 186cf4745f..7e074c0a14 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -32,7 +32,7 @@ extern "C" void __cxa_pure_virtual(void) { abort(); } #ifdef BOOT_IMAGE -#if (defined __MINGW32__) || (defined _MSC_VER) +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define SYMBOL(x) binary_bootimage_bin_##x #else # define SYMBOL(x) _binary_bootimage_bin_##x @@ -52,11 +52,13 @@ extern "C" { } +#undef SYMBOL + #endif//BOOT_IMAGE #ifdef BOOT_CLASSPATH -#if (defined __MINGW32__) || (defined _MSC_VER) +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define SYMBOL(x) binary_classpath_jar_##x #else # define SYMBOL(x) _binary_classpath_jar_##x @@ -76,4 +78,6 @@ extern "C" { } +#undef SYMBOL + #endif//BOOT_CLASSPATH diff --git a/src/bootimage.cpp b/src/bootimage.cpp index bc9b847cd8..13a278ea8b 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -23,6 +23,38 @@ using namespace vm; namespace { +const unsigned HeapCapacity = 768 * 1024 * 1024; + +// Notes on immutable references in the heap image: +// +// One of the advantages of a bootimage-based build is that reduces +// the overhead of major GCs at runtime since we can avoid scanning +// the pre-built heap image entirely. However, this only works if we +// can ensure that no part of the heap image (with exceptions noted +// below) ever points to runtime-allocated objects. Therefore (most) +// references in the heap image are considered immutable, and any +// attempt to update them at runtime will cause the process to abort. +// +// However, some references in the heap image really must be updated +// at runtime: e.g. the static field table for each class. Therefore, +// we allocate these as "fixed" objects, subject to mark-and-sweep +// collection, instead of as "copyable" objects subject to copying +// collection. This strategy avoids the necessity of maintaining +// "dirty reference" bitsets at runtime for the entire heap image; +// each fixed object has its own bitset specific to that object. +// +// In addition to the "fixed" object solution, there are other +// strategies available to avoid attempts to update immutable +// references at runtime: +// +// * Table-based: use a lazily-updated array or vector to associate +// runtime data with heap image objects (see +// e.g. getClassRuntimeData in machine.cpp). +// +// * Update references at build time: for example, we set the names +// of primitive classes before generating the heap image so that we +// need not populate them lazily at runtime. + bool endsWith(const char* suffix, const char* s, unsigned length) { @@ -44,7 +76,11 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, DelayedPromise* addresses = 0; - for (Finder::Iterator it(t->m->finder); it.hasMore();) { + for (Finder::Iterator it + (static_cast + (systemClassLoaderFinder(t, root(t, Machine::BootLoader)))); + it.hasMore();) + { unsigned nameSize = 0; const char* name = it.next(&nameSize); @@ -53,30 +89,59 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, { // fprintf(stderr, "%.*s\n", nameSize - 6, name); object c = resolveSystemClass - (t, makeByteArray(t, "%.*s", nameSize - 6, name)); - - if (t->exception) return 0; + (t, root(t, Machine::BootLoader), + makeByteArray(t, "%.*s", nameSize - 6, name), true); PROTECT(t, c); if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if ((methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) - and ((methodName == 0 + if (((methodName == 0 + or ::strcmp + (reinterpret_cast + (&byteArrayBody + (t, vm::methodName(t, method), 0)), methodName) == 0) + and (methodSpec == 0 or ::strcmp (reinterpret_cast (&byteArrayBody - (t, vm::methodName(t, method), 0)), methodName) == 0) - and (methodSpec == 0 - or ::strcmp - (reinterpret_cast - (&byteArrayBody - (t, vm::methodSpec(t, method), 0)), methodSpec) - == 0))) + (t, vm::methodSpec(t, method), 0)), methodSpec) + == 0))) { - t->m->processor->compileMethod - (t, zone, &constants, &calls, &addresses, method); + if (methodCode(t, method) + or (methodFlags(t, method) & ACC_NATIVE)) + { + PROTECT(t, method); + + t->m->processor->compileMethod + (t, zone, &constants, &calls, &addresses, method); + } + + object addendum = methodAddendum(t, method); + if (addendum and methodAddendumExceptionTable(t, addendum)) { + PROTECT(t, addendum); + + // resolve exception types now to avoid trying to update + // immutable references at runtime + for (unsigned i = 0; i < shortArrayLength + (t, methodAddendumExceptionTable(t, addendum)); ++i) + { + uint16_t index = shortArrayBody + (t, methodAddendumExceptionTable(t, addendum), i) - 1; + + object o = singletonObject + (t, addendumPool(t, addendum), index); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { + o = resolveClass + (t, root(t, Machine::BootLoader), referenceName(t, o)); + + set(t, addendumPool(t, addendum), + SingletonBody + (index * BytesPerWord), o); + } + } + } } } } @@ -89,7 +154,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (methodFlags(t, method) & ACC_NATIVE) { address = reinterpret_cast(code + image->thunks.native.start); } else { - address = methodCompiled(t, method); + address = codeCompiled(t, methodCode(t, method)); } static_cast(pointerValue(t, tripleSecond(t, calls))) @@ -101,7 +166,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, assert(t, value >= code); void* location; - bool flat = addresses->listener->resolve(0, &location); + bool flat = addresses->listener->resolve + (reinterpret_cast(code), &location); uintptr_t offset = value - code; if (flat) { offset |= BootFlatConstant; @@ -131,14 +197,17 @@ visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) { Machine* m = t->m; - for (HashMapIterator it(t, m->classMap); it.hasMore();) { + for (HashMapIterator it(t, classLoaderMap(t, root(t, Machine::BootLoader))); + it.hasMore();) + { w->visitRoot(tripleSecond(t, it.next())); } - image->loader = w->visitRoot(m->loader); + image->bootLoader = w->visitRoot(root(t, Machine::BootLoader)); + image->appLoader = w->visitRoot(root(t, Machine::AppLoader)); image->types = w->visitRoot(m->types); - m->processor->visitRoots(w); + m->processor->visitRoots(t, w); for (; constants; constants = tripleThird(t, constants)) { w->visitRoot(tripleFirst(t, constants)); @@ -177,9 +246,17 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned size = objectSize(t, p); unsigned number; - if (currentObject - and (currentOffset * BytesPerWord) == ClassStaticTable) + if ((currentObject + and (currentOffset * BytesPerWord) == ClassStaticTable) + or instanceOf(t, type(t, Machine::SystemClassLoaderType), p)) { + // Static tables and system classloaders must be allocated + // as fixed objects in the heap image so that they can be + // marked as dirty and visited during GC. Otherwise, + // attempts to update references in these objects to point + // to runtime-allocated memory would fail because we don't + // scan non-fixed objects in the heap image during GC. + FixedAllocator allocator (t->m->system, reinterpret_cast(heap + position), (capacity - position) * BytesPerWord); @@ -279,9 +356,9 @@ offset(object a, uintptr_t* b) } void -writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, - unsigned codeCapacity, const char* className, - const char* methodName, const char* methodSpec) +writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code, + unsigned codeCapacity, const char* className, + const char* methodName, const char* methodSpec) { Zone zone(t->m->system, t->m->heap, 64 * 1024); @@ -292,44 +369,119 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, object constants = makeCodeImage (t, &zone, image, code, codeMap, className, methodName, methodSpec); - if (t->exception) return; - PROTECT(t, constants); - const unsigned HeapCapacity = 32 * 1024 * 1024; + // this map will not be used when the bootimage is loaded, so + // there's no need to preserve it: + setRoot(t, Machine::ByteArrayMap, makeWeakHashMap(t, 0, 0)); + + // name all primitive classes so we don't try to update immutable + // references at runtime: + { object name = makeByteArray(t, "void"); + set(t, type(t, Machine::JvoidType), ClassName, name); + + name = makeByteArray(t, "boolean"); + set(t, type(t, Machine::JbooleanType), ClassName, name); + + name = makeByteArray(t, "byte"); + set(t, type(t, Machine::JbyteType), ClassName, name); + + name = makeByteArray(t, "short"); + set(t, type(t, Machine::JshortType), ClassName, name); + + name = makeByteArray(t, "char"); + set(t, type(t, Machine::JcharType), ClassName, name); + + name = makeByteArray(t, "int"); + set(t, type(t, Machine::JintType), ClassName, name); + + name = makeByteArray(t, "float"); + set(t, type(t, Machine::JfloatType), ClassName, name); + + name = makeByteArray(t, "long"); + set(t, type(t, Machine::JlongType), ClassName, name); + + name = makeByteArray(t, "double"); + set(t, type(t, Machine::JdoubleType), ClassName, name); + } + + // resolve primitive array classes in case they are needed at + // runtime: + { object name = makeByteArray(t, "[B"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[Z"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[S"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[C"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[I"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[J"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[F"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + + name = makeByteArray(t, "[D"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); + } + + collect(t, Heap::MajorCollection); + uintptr_t* heap = static_cast (t->m->heap->allocate(HeapCapacity)); uintptr_t* heapMap = static_cast (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); - // this map will not be used when the bootimage is loaded, so - // there's no need to preserve it: - t->m->byteArrayMap = makeWeakHashMap(t, 0, 0); - - collect(t, Heap::MajorCollection); - HeapWalker* heapWalker = makeHeapImage (t, image, heap, heapMap, HeapCapacity, constants); updateConstants(t, constants, code, codeMap, heapWalker->map()); - image->classCount = hashMapSize(t, t->m->classMap); - unsigned* classTable = static_cast - (t->m->heap->allocate(image->classCount * sizeof(unsigned))); + image->bootClassCount = hashMapSize + (t, classLoaderMap(t, root(t, Machine::BootLoader))); + + unsigned* bootClassTable = static_cast + (t->m->heap->allocate(image->bootClassCount * sizeof(unsigned))); { unsigned i = 0; - for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { - classTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next())); + for (HashMapIterator it + (t, classLoaderMap(t, root(t, Machine::BootLoader))); + it.hasMore();) + { + bootClassTable[i++] = heapWalker->map()->find + (tripleSecond(t, it.next())); } } - image->stringCount = hashMapSize(t, t->m->stringMap); + image->appClassCount = hashMapSize + (t, classLoaderMap(t, root(t, Machine::AppLoader))); + + unsigned* appClassTable = static_cast + (t->m->heap->allocate(image->appClassCount * sizeof(unsigned))); + + { unsigned i = 0; + for (HashMapIterator it + (t, classLoaderMap(t, root(t, Machine::AppLoader))); + it.hasMore();) + { + appClassTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next())); + } + } + + image->stringCount = hashMapSize(t, root(t, Machine::StringMap)); unsigned* stringTable = static_cast (t->m->heap->allocate(image->stringCount * sizeof(unsigned))); { unsigned i = 0; - for (HashMapIterator it(t, t->m->stringMap); it.hasMore();) { + for (HashMapIterator it(t, root(t, Machine::StringMap)); it.hasMore();) { stringTable[i++] = heapWalker->map()->find (jreferenceTarget(t, tripleFirst(t, it.next()))); } @@ -344,17 +496,19 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, fprintf(stderr, "class count %d string count %d call count %d\n" "heap size %d code size %d\n", - image->classCount, image->stringCount, image->callCount, + image->bootClassCount, image->stringCount, image->callCount, image->heapSize, image->codeSize); if (true) { fwrite(image, sizeof(BootImage), 1, out); - fwrite(classTable, image->classCount * sizeof(unsigned), 1, out); + fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1, out); + fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1, out); fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, out); fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, out); - unsigned offset = (image->classCount * sizeof(unsigned)) + unsigned offset = (image->bootClassCount * sizeof(unsigned)) + + (image->appClassCount * sizeof(unsigned)) + (image->stringCount * sizeof(unsigned)) + (image->callCount * sizeof(unsigned) * 2); @@ -372,6 +526,23 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, } } +uint64_t +writeBootImage(Thread* t, uintptr_t* arguments) +{ + FILE* out = reinterpret_cast(arguments[0]); + BootImage* image = reinterpret_cast(arguments[1]); + uint8_t* code = reinterpret_cast(arguments[2]); + unsigned codeCapacity = arguments[3]; + const char* className = reinterpret_cast(arguments[4]); + const char* methodName = reinterpret_cast(arguments[5]); + const char* methodSpec = reinterpret_cast(arguments[6]); + + writeBootImage2 + (t, out, image, code, codeCapacity, className, methodName, methodSpec); + + return 1; +} + } // namespace int @@ -384,16 +555,18 @@ main(int ac, const char** av) } System* s = makeSystem(0); - Heap* h = makeHeap(s, 128 * 1024 * 1024); - Finder* f = makeFinder(s, av[1], 0); + Heap* h = makeHeap(s, HeapCapacity * 2); + Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); + Finder* f = makeFinder(s, h, av[1], 0); Processor* p = makeProcessor(s, h, false); BootImage image; - const unsigned CodeCapacity = 16 * 1024 * 1024; + const unsigned CodeCapacity = 128 * 1024 * 1024; uint8_t* code = static_cast(h->allocate(CodeCapacity)); p->initialize(&image, code, CodeCapacity); - Machine* m = new (h->allocate(sizeof(Machine))) Machine(s, h, f, p, 0, 0); + Machine* m = new (h->allocate(sizeof(Machine))) Machine + (s, h, f, 0, p, c, 0, 0); Thread* t = p->makeThread(m, 0, 0); enter(t, Thread::ActiveState); @@ -405,15 +578,22 @@ main(int ac, const char** av) return -1; } - writeBootImage - (t, output, &image, code, CodeCapacity, - (ac > 3 ? av[3] : 0), (ac > 4 ? av[4] : 0), (ac > 5 ? av[5] : 0)); + uintptr_t arguments[] = { reinterpret_cast(output), + reinterpret_cast(&image), + reinterpret_cast(code), + CodeCapacity, + reinterpret_cast(ac > 3 ? av[3] : 0), + reinterpret_cast(ac > 4 ? av[4] : 0), + reinterpret_cast(ac > 5 ? av[5] : 0) }; + + run(t, writeBootImage, arguments); fclose(output); if (t->exception) { printTrace(t, t->exception); + return -1; + } else { + return 0; } - - return 0; } diff --git a/src/bootimage.h b/src/bootimage.h index b76a77b7fa..a5ed58bb61 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -45,6 +45,7 @@ class BootImage { Thunk defaultVirtual; Thunk native; Thunk aioob; + Thunk stackOverflow; Thunk table; }; @@ -55,11 +56,13 @@ class BootImage { unsigned heapSize; unsigned codeSize; - unsigned classCount; + unsigned bootClassCount; + unsigned appClassCount; unsigned stringCount; unsigned callCount; - unsigned loader; + unsigned bootLoader; + unsigned appLoader; unsigned types; unsigned methodTree; unsigned methodTreeSentinal; @@ -73,6 +76,7 @@ class BootImage { unsigned compileVirtualMethodCall; unsigned invokeNativeCall; unsigned throwArrayIndexOutOfBoundsCall; + unsigned throwStackOverflowCall; #define THUNK(s) unsigned s##Call; #include "thunks.cpp" diff --git a/src/builtin.cpp b/src/builtin.cpp index d8ee84cc2c..240ec9628a 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -18,10 +18,11 @@ using namespace vm; namespace { int64_t -search(Thread* t, object name, object (*op)(Thread*, object), - bool replaceDots) +search(Thread* t, object loader, object name, + object (*op)(Thread*, object, object), bool replaceDots) { if (LIKELY(name)) { + PROTECT(t, loader); PROTECT(t, name); object n = makeByteArray(t, stringLength(t, name) + 1); @@ -32,683 +33,69 @@ search(Thread* t, object name, object (*op)(Thread*, object), replace('.', '/', s); } - object r = op(t, n); - if (t->exception) { - return 0; - } - - return reinterpret_cast(r); + return reinterpret_cast(op(t, loader, n)); } else { - t->exception = makeNullPointerException(t); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } -void -enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, - unsigned limit) +object +resolveSystemClassThrow(Thread* t, object loader, object spec) { - if (*index < limit) { - set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread); - ++ (*index); - - if (x->peer) enumerateThreads(t, x->peer, array, index, limit); - - if (x->child) enumerateThreads(t, x->child, array, index, limit); - } -} - -bool -compatibleArrayTypes(Thread* t, object a, object b) -{ - return classArrayElementSize(t, a) - and classArrayElementSize(t, b) - and (a == b - or (not ((classVmFlags(t, a) & PrimitiveFlag) - or (classVmFlags(t, b) & PrimitiveFlag)))); -} - -void -runOnLoadIfFound(Thread* t, System::Library* library) -{ - void* p = library->resolve("JNI_OnLoad"); - if (p) { - jint (JNICALL * JNI_OnLoad)(Machine*, void*); - memcpy(&JNI_OnLoad, &p, sizeof(void*)); - JNI_OnLoad(t->m, 0); - } + return resolveSystemClass(t, loader, spec, true); } } // namespace extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_toString -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - unsigned hash = objectHash(t, this_); - object s = makeString - (t, "%s@0x%x", - &byteArrayBody(t, className(t, objectClass(t, this_)), 0), - hash); - - return reinterpret_cast(s); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_getClass -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - return reinterpret_cast(objectClass(t, this_)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Object_wait -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8); - - vm::wait(t, this_, milliseconds); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Object_notify -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - notify(t, this_); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Object_notifyAll -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - notifyAll(t, this_); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_hashCode -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - return objectHash(t, this_); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_clone -(Thread* t, object, uintptr_t* arguments) -{ - object o = reinterpret_cast(arguments[0]); - PROTECT(t, o); - - object class_ = objectClass(t, o); - unsigned size = baseSize(t, o, class_) * BytesPerWord; - object clone; - - if (classArrayElementSize(t, class_)) { - clone = static_cast(allocate(t, size, classObjectMask(t, class_))); - memcpy(clone, o, size); - // clear any object header flags: - setObjectClass(t, o, objectClass(t, o)); - } else { - clone = make(t, class_); - memcpy(reinterpret_cast(clone) + 1, - reinterpret_cast(o) + 1, - size - BytesPerWord); - } - - return reinterpret_cast(clone); -} - -extern "C" JNIEXPORT void JNICALL -Avian_avian_SystemClassLoader_acquireClassLock -(Thread* t, object, uintptr_t*) -{ - acquire(t, t->m->classLock); -} - -extern "C" JNIEXPORT void JNICALL -Avian_avian_SystemClassLoader_releaseClassLock -(Thread* t, object, uintptr_t*) -{ - release(t, t->m->classLock); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_defineClass +Avian_avian_SystemClassLoader_findLoadedVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); - PROTECT(t, loader); - - object b = reinterpret_cast(arguments[1]); - int offset = arguments[2]; - int length = arguments[3]; - - uint8_t* buffer = static_cast - (t->m->heap->allocate(length)); - memcpy(buffer, &byteArrayBody(t, b, offset), length); - object c = parseClass(t, loader, buffer, length); - t->m->heap->free(buffer, length); - - if (c) { - PROTECT(t, c); - if (getClassLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); - } - - hashMapInsert(t, getClassLoaderMap(t, loader), className(t, c), c, - byteArrayHash); - } - - return reinterpret_cast(c); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_reallyFindLoadedClass -(Thread* t, object, uintptr_t* arguments) -{ object name = reinterpret_cast(arguments[1]); - return search(t, name, findLoadedSystemClass, true); + return search(t, loader, name, findLoadedClass, true); } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_findClass -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[1]); - - return search(t, name, resolveSystemClass, true); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_resolveClass +Avian_avian_SystemClassLoader_findVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); - object spec = reinterpret_cast(arguments[1]); + object name = reinterpret_cast(arguments[1]); - return reinterpret_cast(resolveClass(t, loader, spec)); + return search(t, loader, name, resolveSystemClassThrow, true); } extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_resourceExists (Thread* t, object, uintptr_t* arguments) { + object loader = reinterpret_cast(arguments[0]); object name = reinterpret_cast(arguments[1]); if (LIKELY(name)) { - RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); + THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - return t->m->finder->exists(RUNTIME_ARRAY_BODY(n)); + + unsigned length; + bool r = static_cast(systemClassLoaderFinder(t, loader))->stat + (RUNTIME_ARRAY_BODY(n), &length) == System::TypeFile; + +// fprintf(stderr, "resource %s exists? %d\n", n, r); + + return r; } else { - t->exception = makeNullPointerException(t); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_io_ObjectInputStream_makeInstance +Avian_avian_SystemClassLoader_getClass (Thread* t, object, uintptr_t* arguments) { - object c = reinterpret_cast(arguments[0]); - - return reinterpret_cast(make(t, c)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_primitiveClass -(Thread* t, object, uintptr_t* arguments) -{ - char name = arguments[0]; - - switch (name) { - case 'B': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JbyteType)); - case 'C': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JcharType)); - case 'D': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JdoubleType)); - case 'F': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JfloatType)); - case 'I': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JintType)); - case 'J': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JlongType)); - case 'S': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JshortType)); - case 'V': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JvoidType)); - case 'Z': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JbooleanType)); - default: - t->exception = makeIllegalArgumentException(t); - return 0; - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Class_initialize -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - initClass(t, this_); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_isAssignableFrom -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - object that = reinterpret_cast(arguments[1]); - - if (LIKELY(that)) { - return vm::isAssignableFrom(t, this_, that); - } else { - t->exception = makeNullPointerException(t); - return 0; - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Field_getPrimitive -(Thread* t, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int code = arguments[1]; - int offset = arguments[2]; - - switch (code) { - case ByteField: - return cast(instance, offset); - case BooleanField: - return cast(instance, offset); - case CharField: - return cast(instance, offset); - case ShortField: - return cast(instance, offset); - case IntField: - return cast(instance, offset); - case LongField: - return cast(instance, offset); - case FloatField: - return cast(instance, offset); - case DoubleField: - return cast(instance, offset); - default: - abort(t); - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Field_getObject -(Thread*, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int offset = arguments[1]; - - return reinterpret_cast(cast(instance, offset)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_reflect_Field_setPrimitive -(Thread* t, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int code = arguments[1]; - int offset = arguments[2]; - int64_t value; memcpy(&value, arguments + 3, 8); - - switch (code) { - case ByteField: - cast(instance, offset) = static_cast(value); - break; - case BooleanField: - cast(instance, offset) = static_cast(value); - break; - case CharField: - cast(instance, offset) = static_cast(value); - break; - case ShortField: - cast(instance, offset) = static_cast(value); - break; - case IntField: - cast(instance, offset) = static_cast(value); - break; - case LongField: - cast(instance, offset) = static_cast(value); - break; - case FloatField: - cast(instance, offset) = static_cast(value); - break; - case DoubleField: - cast(instance, offset) = static_cast(value); - break; - default: - abort(t); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_reflect_Field_setObject -(Thread* t, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int offset = arguments[1]; - object value = reinterpret_cast(arguments[2]); - - set(t, instance, offset, value); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Constructor_make -(Thread* t, object, uintptr_t* arguments) -{ - object c = reinterpret_cast(arguments[0]); - - return reinterpret_cast(make(t, c)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Method_getCaller -(Thread* t, object, uintptr_t*) -{ - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t): t(t), method(0), count(0) { } - - virtual bool visit(Processor::StackWalker* walker) { - if (count == 2) { - method = walker->method(); - return false; - } else { - ++ count; - return true; - } - } - - Thread* t; - object method; - unsigned count; - } v(t); - - t->m->processor->walkStack(t, &v); - - return reinterpret_cast(v.method); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Method_invoke -(Thread* t, object, uintptr_t* arguments) -{ - object method = reinterpret_cast(arguments[0]); - object instance = reinterpret_cast(arguments[1]); - object args = reinterpret_cast(arguments[2]); - - object v = t->m->processor->invokeArray(t, method, instance, args); - if (t->exception) { - t->exception = makeInvocationTargetException(t, t->exception); - } - return reinterpret_cast(v); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Array_getLength -(Thread* t, object, uintptr_t* arguments) -{ - object array = reinterpret_cast(arguments[0]); - - if (LIKELY(array)) { - unsigned elementSize = classArrayElementSize(t, objectClass(t, array)); - - if (LIKELY(elementSize)) { - return cast(array, BytesPerWord); - } else { - t->exception = makeIllegalArgumentException(t); - } - } else { - t->exception = makeNullPointerException(t); - } - return 0; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Array_makeObjectArray -(Thread* t, object, uintptr_t* arguments) -{ - object elementType = reinterpret_cast(arguments[0]); - int length = arguments[1]; - return reinterpret_cast - (makeObjectArray(t, classLoader(t, elementType), elementType, length)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Float_floatToRawIntBits -(Thread*, object, uintptr_t* arguments) -{ - return static_cast(*arguments); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Float_intBitsToFloat -(Thread*, object, uintptr_t* arguments) -{ - return static_cast(*arguments); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Double_doubleToRawLongBits -(Thread*, object, uintptr_t* arguments) -{ - int64_t v; memcpy(&v, arguments, 8); - return v; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Double_longBitsToDouble -(Thread*, object, uintptr_t* arguments) -{ - int64_t v; memcpy(&v, arguments, 8); - return v; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_String_intern -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - return reinterpret_cast(intern(t, this_)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_System_getVMProperty -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - object found = reinterpret_cast(arguments[1]); - PROTECT(t, found); - - unsigned length = stringLength(t, name); - RUNTIME_ARRAY(char, n, length + 1); - stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - - int64_t r = 0; - if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) { - r = reinterpret_cast(makeString(t, "%s", t->m->finder->path())); - } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) { - r = reinterpret_cast(makeString(t, AVIAN_VERSION)); - } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) { - r = reinterpret_cast(makeString(t, "ASCII")); - } else { - const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n)); - if (v) { - r = reinterpret_cast(makeString(t, v)); - } - } - - if (r) { - booleanArrayBody(t, found, 0) = true; - } - - return r; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_System_arraycopy -(Thread* t, object, uintptr_t* arguments) -{ - object src = reinterpret_cast(arguments[0]); - int32_t srcOffset = arguments[1]; - object dst = reinterpret_cast(arguments[2]); - int32_t dstOffset = arguments[3]; - int32_t length = arguments[4]; - - if (LIKELY(src and dst)) { - if (LIKELY(compatibleArrayTypes - (t, objectClass(t, src), objectClass(t, dst)))) - { - unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); - - if (LIKELY(elementSize)) { - intptr_t sl = cast(src, BytesPerWord); - intptr_t dl = cast(dst, BytesPerWord); - if (LIKELY(length > 0)) { - if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and - dstOffset >= 0 and dstOffset + length <= dl)) - { - uint8_t* sbody = &cast(src, ArrayBody); - uint8_t* dbody = &cast(dst, ArrayBody); - if (src == dst) { - memmove(dbody + (dstOffset * elementSize), - sbody + (srcOffset * elementSize), - length * elementSize); - } else { - memcpy(dbody + (dstOffset * elementSize), - sbody + (srcOffset * elementSize), - length * elementSize); - } - - if (classObjectMask(t, objectClass(t, dst))) { - mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length); - } - - return; - } else { - t->exception = makeIndexOutOfBoundsException(t); - return; - } - } else { - return; - } - } - } - } else { - t->exception = makeNullPointerException(t); - return; - } - - t->exception = makeArrayStoreException(t); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_System_identityHashCode -(Thread* t, object, uintptr_t* arguments) -{ - object o = reinterpret_cast(arguments[0]); - - if (LIKELY(o)) { - return objectHash(t, o); - } else { - t->exception = makeNullPointerException(t); - return 0; - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_load -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - bool mapName = arguments[1]; - - unsigned length = stringLength(t, name); - RUNTIME_ARRAY(char, n, length + 1); - stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - - ACQUIRE(t, t->m->classLock); - - const char* builtins = findProperty(t, "avian.builtins"); - if (mapName and builtins) { - const char* s = builtins; - while (*s) { - if (::strncmp(s, RUNTIME_ARRAY_BODY(n), length) == 0 - and (s[length] == ',' or s[length] == 0)) - { - // library is built in to this executable - if (not t->m->triedBuiltinOnLoad) { - t->m->triedBuiltinOnLoad = true; - runOnLoadIfFound(t, t->m->libraries); - } - return; - } else { - while (*s and *s != ',') ++ s; - if (*s) ++ s; - } - } - } - - System::Library* last = t->m->libraries; - for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { - if (lib->name() - and ::strcmp(lib->name(), RUNTIME_ARRAY_BODY(n)) == 0 - and lib->mapName() == mapName) - { - // already loaded - return; - } - last = lib; - } - - System::Library* lib; - if (LIKELY(t->m->system->success - (t->m->system->load(&lib, RUNTIME_ARRAY_BODY(n), mapName)))) - { - last->setNext(lib); - runOnLoadIfFound(t, lib); - } else { - object message = makeString - (t, "library not found: %s", RUNTIME_ARRAY_BODY(n)); - t->exception = makeUnsatisfiedLinkError(t, message); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_gc -(Thread* t, object, uintptr_t*) -{ - collect(t, Heap::MajorCollection); + (getJClass(t, reinterpret_cast(arguments[0]))); } #ifdef AVIAN_HEAPDUMP @@ -720,17 +107,16 @@ Avian_avian_Machine_dumpHeap object outputFile = reinterpret_cast(*arguments); unsigned length = stringLength(t, outputFile); - char n[length + 1]; - stringChars(t, outputFile, n); - FILE* out = vm::fopen(n, "wb"); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); + stringChars(t, outputFile, RUNTIME_ARRAY_BODY(n)); + FILE* out = vm::fopen(RUNTIME_ARRAY_BODY(n), "wb"); if (out) { { ENTER(t, Thread::ExclusiveState); dumpHeap(t, out); } fclose(out); } else { - object message = makeString(t, "file not found: %s", n); - t->exception = makeRuntimeException(t, message); + throwNew(t, Machine::RuntimeExceptionType, "file not found: %s", n); } } @@ -745,193 +131,6 @@ Avian_java_lang_Runtime_exit t->m->system->exit(arguments[1]); } -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Runtime_freeMemory -(Thread*, object, uintptr_t*) -{ - // todo - return 0; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Runtime_totalMemory -(Thread*, object, uintptr_t*) -{ - // todo - return 0; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_addShutdownHook -(Thread* t, object, uintptr_t* arguments) -{ - object hook = reinterpret_cast(arguments[1]); - PROTECT(t, hook); - - ACQUIRE(t, t->m->shutdownLock); - - t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Throwable_trace -(Thread* t, object, uintptr_t* arguments) -{ - int32_t skipCount = arguments[0]; - - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t, int skipCount): - t(t), trace(0), skipCount(skipCount) - { } - - virtual bool visit(Processor::StackWalker* walker) { - if (skipCount == 0) { - object method = walker->method(); - if (isAssignableFrom - (t, arrayBody(t, t->m->types, Machine::ThrowableType), - methodClass(t, method)) - and vm::strcmp(reinterpret_cast(""), - &byteArrayBody(t, methodName(t, method), 0)) - == 0) - { - return true; - } else { - trace = makeTrace(t, walker); - return false; - } - } else { - -- skipCount; - return true; - } - } - - Thread* t; - object trace; - unsigned skipCount; - } v(t, skipCount); - - t->m->processor->walkStack(t, &v); - - if (v.trace == 0) v.trace = makeArray(t, 0); - - return reinterpret_cast(v.trace); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Throwable_resolveTrace -(Thread* t, object, uintptr_t* arguments) -{ - object trace = reinterpret_cast(*arguments); - PROTECT(t, trace); - - unsigned length = arrayLength(t, trace); - object elementType = arrayBody - (t, t->m->types, Machine::StackTraceElementType); - object array = makeObjectArray - (t, classLoader(t, elementType), elementType, length); - PROTECT(t, array); - - object e = 0; - PROTECT(t, e); - - object class_ = 0; - PROTECT(t, class_); - - object method = 0; - PROTECT(t, method); - - for (unsigned i = 0; i < length; ++i) { - e = arrayBody(t, trace, i); - - class_ = className(t, methodClass(t, traceElementMethod(t, e))); - class_ = makeString(t, class_, 0, byteArrayLength(t, class_) - 1, 0); - - method = methodName(t, traceElementMethod(t, e)); - method = makeString(t, method, 0, byteArrayLength(t, method) - 1, 0); - - unsigned line = t->m->processor->lineNumber - (t, traceElementMethod(t, e), traceElementIp(t, e)); - - object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e))); - file = file ? makeString(t, file, 0, byteArrayLength(t, file) - 1, 0) : 0; - - object ste = makeStackTraceElement(t, class_, method, file, line); - set(t, array, ArrayBody + (i * BytesPerWord), ste); - } - - return reinterpret_cast(array); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_currentThread -(Thread* t, object, uintptr_t*) -{ - return reinterpret_cast(t->javaThread); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_doStart -(Thread* t, object, uintptr_t* arguments) -{ - return reinterpret_cast - (startThread(t, reinterpret_cast(*arguments))); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Thread_interrupt -(Thread* t, object, uintptr_t* arguments) -{ - int64_t peer; memcpy(&peer, arguments, 8); - - interrupt(t, reinterpret_cast(peer)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_getStackTrace -(Thread* t, object, uintptr_t* arguments) -{ - int64_t peer; memcpy(&peer, arguments, 8); - - if (reinterpret_cast(peer) == t) { - return reinterpret_cast(makeTrace(t)); - } else { - return reinterpret_cast - (t->m->processor->getStackTrace(t, reinterpret_cast(peer))); - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_activeCount -(Thread* t, object, uintptr_t*) -{ - return t->m->liveCount; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_enumerate -(Thread* t, object, uintptr_t* arguments) -{ - object array = reinterpret_cast(*arguments); - - ACQUIRE_RAW(t, t->m->stateLock); - - unsigned count = min(t->m->liveCount, objectArrayLength(t, array)); - unsigned index = 0; - enumerateThreads(t, t->m->rootThread, array, &index, count); - return count; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Thread_setDaemon -(Thread* t, object, uintptr_t* arguments) -{ - object thread = reinterpret_cast(arguments[0]); - bool daemon = arguments[1] != 0; - - setDaemon(t, thread, daemon); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength (Thread* t, object, uintptr_t* arguments) @@ -939,10 +138,14 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength object path = reinterpret_cast(*arguments); if (LIKELY(path)) { - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - System::Region* r = t->m->finder->find(RUNTIME_ARRAY_BODY(p)); + System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); + if (r == 0) { + r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + } + if (r) { jint rSize = r->length(); r->dispose(); @@ -959,17 +162,31 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open object path = reinterpret_cast(*arguments); if (LIKELY(path)) { - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - return reinterpret_cast - (t->m->finder->find(RUNTIME_ARRAY_BODY(p))); + System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); + if (r == 0) { + r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + } + + return reinterpret_cast(r); } else { - t->exception = makeNullPointerException(t); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_resource_Handler_00024ResourceInputStream_available +(Thread*, object, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + int32_t position = arguments[2]; + + System::Region* region = reinterpret_cast(peer); + return static_cast(region->length()) - position; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_resource_Handler_00024ResourceInputStream_read__JI (Thread*, object, uintptr_t* arguments) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp new file mode 100644 index 0000000000..95b2a32703 --- /dev/null +++ b/src/classpath-avian.cpp @@ -0,0 +1,669 @@ +/* Copyright (c) 2010, 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. */ + +#include "machine.h" +#include "classpath-common.h" + +using namespace vm; + +namespace { + +namespace local { + +class MyClasspath : public Classpath { + public: + MyClasspath(Allocator* allocator): + allocator(allocator) + { } + + virtual object + makeJclass(Thread* t, object class_) + { + return vm::makeJclass(t, class_); + } + + virtual object + makeString(Thread* t, object array, int32_t offset, int32_t length) + { + return vm::makeString(t, array, offset, length, 0); + } + + virtual object + makeThread(Thread* t, Thread* parent) + { + object group; + if (parent) { + group = threadGroup(t, parent->javaThread); + } else { + group = makeThreadGroup(t, 0, 0, 0); + } + + const unsigned NewState = 0; + const unsigned NormalPriority = 5; + + return vm::makeThread + (t, 0, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, + root(t, Machine::BootLoader), 0, 0, group, 0); + } + + virtual void + runThread(Thread* t) + { + object method = resolveMethod + (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", + "(Ljava/lang/Thread;)V"); + + t->m->processor->invoke(t, method, 0, t->javaThread); + } + + virtual void + boot(Thread*) + { + // ignore + } + + virtual const char* + bootClasspath() + { + return AVIAN_CLASSPATH; + } + + virtual void + dispose() + { + allocator->free(this, sizeof(*this)); + } + + Allocator* allocator; +}; + +void +enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, + unsigned limit) +{ + if (*index < limit) { + set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread); + ++ (*index); + + if (x->peer) enumerateThreads(t, x->peer, array, index, limit); + + if (x->child) enumerateThreads(t, x->child, array, index, limit); + } +} + +} // namespace local + +} // namespace + +namespace vm { + +Classpath* +makeClasspath(System*, Allocator* allocator, const char*, const char*) +{ + return new (allocator->allocate(sizeof(local::MyClasspath))) + local::MyClasspath(allocator); +} + +} // namespace vm + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_toString +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + unsigned hash = objectHash(t, this_); + object s = makeString + (t, "%s@0x%x", + &byteArrayBody(t, className(t, objectClass(t, this_)), 0), + hash); + + return reinterpret_cast(s); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_getVMClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (objectClass(t, reinterpret_cast(arguments[0]))); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_wait +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8); + + vm::wait(t, this_, milliseconds); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_notify +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + notify(t, this_); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_notifyAll +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + notifyAll(t, this_); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_hashCode +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + return objectHash(t, this_); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_clone +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (clone(t, reinterpret_cast(arguments[0]))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_io_ObjectInputStream_makeInstance +(Thread* t, object, uintptr_t* arguments) +{ + object c = reinterpret_cast(arguments[0]); + + return reinterpret_cast(make(t, c)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getPrimitive +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int code = arguments[1]; + int offset = arguments[2]; + + switch (code) { + case ByteField: + return cast(instance, offset); + case BooleanField: + return cast(instance, offset); + case CharField: + return cast(instance, offset); + case ShortField: + return cast(instance, offset); + case IntField: + return cast(instance, offset); + case LongField: + return cast(instance, offset); + case FloatField: + return cast(instance, offset); + case DoubleField: + return cast(instance, offset); + default: + abort(t); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getObject +(Thread*, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int offset = arguments[1]; + + return reinterpret_cast(cast(instance, offset)); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_reflect_Field_setPrimitive +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int code = arguments[1]; + int offset = arguments[2]; + int64_t value; memcpy(&value, arguments + 3, 8); + + switch (code) { + case ByteField: + cast(instance, offset) = static_cast(value); + break; + case BooleanField: + cast(instance, offset) = static_cast(value); + break; + case CharField: + cast(instance, offset) = static_cast(value); + break; + case ShortField: + cast(instance, offset) = static_cast(value); + break; + case IntField: + cast(instance, offset) = static_cast(value); + break; + case LongField: + cast(instance, offset) = static_cast(value); + break; + case FloatField: + cast(instance, offset) = static_cast(value); + break; + case DoubleField: + cast(instance, offset) = static_cast(value); + break; + default: + abort(t); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_reflect_Field_setObject +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int offset = arguments[1]; + object value = reinterpret_cast(arguments[2]); + + set(t, instance, offset, value); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Constructor_make +(Thread* t, object, uintptr_t* arguments) +{ + object c = reinterpret_cast(arguments[0]); + + return reinterpret_cast(make(t, c)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_getCaller +(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast(getCaller(t, 2)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_invoke +(Thread* t, object, uintptr_t* arguments) +{ + object method = reinterpret_cast(arguments[0]); + object instance = reinterpret_cast(arguments[1]); + object args = reinterpret_cast(arguments[2]); + + THREAD_RESOURCE0(t, { + if (t->exception) { + object exception = t->exception; + t->exception = makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, exception); + } + }); + + return reinterpret_cast + (t->m->processor->invokeArray(t, method, instance, args)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_getLength +(Thread* t, object, uintptr_t* arguments) +{ + object array = reinterpret_cast(arguments[0]); + + if (LIKELY(array)) { + unsigned elementSize = classArrayElementSize(t, objectClass(t, array)); + + if (LIKELY(elementSize)) { + return cast(array, BytesPerWord); + } else { + throwNew(t, Machine::IllegalArgumentExceptionType); + } + } else { + throwNew(t, Machine::NullPointerExceptionType); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_makeObjectArray +(Thread* t, object, uintptr_t* arguments) +{ + object elementType = reinterpret_cast(arguments[0]); + int length = arguments[1]; + + return reinterpret_cast + (makeObjectArray(t, jclassVmClass(t, elementType), length)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_floatToRawIntBits +(Thread*, object, uintptr_t* arguments) +{ + return static_cast(*arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_intBitsToFloat +(Thread*, object, uintptr_t* arguments) +{ + return static_cast(*arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Double_doubleToRawLongBits +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, arguments, 8); + return v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Double_longBitsToDouble +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, arguments, 8); + return v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_String_intern +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + return reinterpret_cast(intern(t, this_)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_getVMProperty +(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + object found = reinterpret_cast(arguments[1]); + PROTECT(t, found); + + unsigned length = stringLength(t, name); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + int64_t r = 0; + if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) { + r = reinterpret_cast + (makeString(t, "%s", t->m->appFinder->path())); + } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) { + r = reinterpret_cast(makeString(t, AVIAN_VERSION)); + } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) { + r = reinterpret_cast(makeString(t, "ASCII")); + } else { + const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n)); + if (v) { + r = reinterpret_cast(makeString(t, v)); + } + } + + if (r) { + booleanArrayBody(t, found, 0) = true; + } + + return r; +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_System_arraycopy +(Thread* t, object, uintptr_t* arguments) +{ + arrayCopy(t, reinterpret_cast(arguments[0]), + arguments[1], + reinterpret_cast(arguments[2]), + arguments[3], + arguments[4]); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_identityHashCode +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[0]); + + if (LIKELY(o)) { + return objectHash(t, o); + } else { + throwNew(t, Machine::NullPointerExceptionType); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_load +(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + bool mapName = arguments[1]; + + unsigned length = stringLength(t, name); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_gc +(Thread* t, object, uintptr_t*) +{ + collect(t, Heap::MajorCollection); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Runtime_freeMemory +(Thread*, object, uintptr_t*) +{ + // todo + return 0; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Runtime_totalMemory +(Thread*, object, uintptr_t*) +{ + // todo + return 0; +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_addShutdownHook +(Thread* t, object, uintptr_t* arguments) +{ + object hook = reinterpret_cast(arguments[1]); + PROTECT(t, hook); + + ACQUIRE(t, t->m->shutdownLock); + + setRoot(t, Machine::ShutdownHooks, + makePair(t, hook, root(t, Machine::ShutdownHooks))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_trace +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast(getTrace(t, arguments[0])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_resolveTrace +(Thread* t, object, uintptr_t* arguments) +{ + object trace = reinterpret_cast(*arguments); + PROTECT(t, trace); + + unsigned length = objectArrayLength(t, trace); + object elementType = type(t, Machine::StackTraceElementType); + object array = makeObjectArray(t, elementType, length); + PROTECT(t, array); + + for (unsigned i = 0; i < length; ++i) { + object ste = makeStackTraceElement(t, objectArrayBody(t, trace, i)); + set(t, array, ArrayBody + (i * BytesPerWord), ste); + } + + return reinterpret_cast(array); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_currentThread +(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast(t->javaThread); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_doStart +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (startThread(t, reinterpret_cast(*arguments))); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Thread_interrupt +(Thread* t, object, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + interrupt(t, reinterpret_cast(peer)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_getStackTrace +(Thread* t, object, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + if (reinterpret_cast(peer) == t) { + return reinterpret_cast(makeTrace(t)); + } else { + return reinterpret_cast + (t->m->processor->getStackTrace(t, reinterpret_cast(peer))); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_activeCount +(Thread* t, object, uintptr_t*) +{ + return t->m->liveCount; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_enumerate +(Thread* t, object, uintptr_t* arguments) +{ + object array = reinterpret_cast(*arguments); + + ACQUIRE_RAW(t, t->m->stateLock); + + unsigned count = min(t->m->liveCount, objectArrayLength(t, array)); + unsigned index = 0; + local::enumerateThreads(t, t->m->rootThread, array, &index, count); + return count; +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Thread_yield +(Thread* t, object, uintptr_t*) +{ + t->m->system->yield(); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_acquireClassLock +(Thread* t, object, uintptr_t*) +{ + acquire(t, t->m->classLock); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_releaseClassLock +(Thread* t, object, uintptr_t*) +{ + release(t, t->m->classLock); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_resolveVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + object spec = reinterpret_cast(arguments[1]); + + return reinterpret_cast(resolveClass(t, loader, spec)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_primitiveClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast(primitiveClass(t, arguments[0])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_defineVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + object b = reinterpret_cast(arguments[1]); + int offset = arguments[2]; + int length = arguments[3]; + + uint8_t* buffer = static_cast + (t->m->heap->allocate(length)); + + THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, + t->m->heap->free(buffer, length)); + + memcpy(buffer, &byteArrayBody(t, b, offset), length); + + return reinterpret_cast(defineClass(t, loader, buffer, length)); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_initialize +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + initClass(t, this_); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_isAssignableFrom +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object that = reinterpret_cast(arguments[1]); + + if (LIKELY(that)) { + return vm::isAssignableFrom(t, this_, that); + } else { + throwNew(t, Machine::NullPointerExceptionType); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_getVMClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (objectClass(t, reinterpret_cast(arguments[0]))); +} diff --git a/src/classpath-common.h b/src/classpath-common.h new file mode 100644 index 0000000000..6efc0a1424 --- /dev/null +++ b/src/classpath-common.h @@ -0,0 +1,291 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef CLASSPATH_COMMON_H +#define CLASSPATH_COMMON_H + +#include "tokenizer.h" + +namespace vm { + +object +getTrace(Thread* t, unsigned skipCount) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t, int skipCount): + t(t), trace(0), skipCount(skipCount) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (skipCount == 0) { + object method = walker->method(); + if (isAssignableFrom + (t, type(t, Machine::ThrowableType), methodClass(t, method)) + and vm::strcmp(reinterpret_cast(""), + &byteArrayBody(t, methodName(t, method), 0)) + == 0) + { + return true; + } else { + trace = makeTrace(t, walker); + return false; + } + } else { + -- skipCount; + return true; + } + } + + Thread* t; + object trace; + unsigned skipCount; + } v(t, skipCount); + + t->m->processor->walkStack(t, &v); + + if (v.trace == 0) v.trace = makeObjectArray(t, 0); + + return v.trace; +} + +bool +compatibleArrayTypes(Thread* t, object a, object b) +{ + return classArrayElementSize(t, a) + and classArrayElementSize(t, b) + and (a == b + or (not ((classVmFlags(t, a) & PrimitiveFlag) + or (classVmFlags(t, b) & PrimitiveFlag)))); +} + +void +arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, + int32_t dstOffset, int32_t length) +{ + if (LIKELY(src and dst)) { + if (LIKELY(compatibleArrayTypes + (t, objectClass(t, src), objectClass(t, dst)))) + { + unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); + + if (LIKELY(elementSize)) { + intptr_t sl = cast(src, BytesPerWord); + intptr_t dl = cast(dst, BytesPerWord); + if (LIKELY(length > 0)) { + if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and + dstOffset >= 0 and dstOffset + length <= dl)) + { + uint8_t* sbody = &cast(src, ArrayBody); + uint8_t* dbody = &cast(dst, ArrayBody); + if (src == dst) { + memmove(dbody + (dstOffset * elementSize), + sbody + (srcOffset * elementSize), + length * elementSize); + } else { + memcpy(dbody + (dstOffset * elementSize), + sbody + (srcOffset * elementSize), + length * elementSize); + } + + if (classObjectMask(t, objectClass(t, dst))) { + mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length); + } + + return; + } else { + throwNew(t, Machine::IndexOutOfBoundsExceptionType); + } + } else { + return; + } + } + } + } else { + throwNew(t, Machine::NullPointerExceptionType); + return; + } + + throwNew(t, Machine::ArrayStoreExceptionType); +} + +void +runOnLoadIfFound(Thread* t, System::Library* library) +{ + void* p = library->resolve("JNI_OnLoad"); + if (p) { + jint (JNICALL * JNI_OnLoad)(Machine*, void*); + memcpy(&JNI_OnLoad, &p, sizeof(void*)); + JNI_OnLoad(t->m, 0); + } +} + +System::Library* +loadLibrary(Thread* t, const char* name) +{ + ACQUIRE(t, t->m->classLock); + + System::Library* last = t->m->libraries; + for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { + if (lib->name() and ::strcmp(lib->name(), name) == 0) { + // already loaded + return lib; + } + last = lib; + } + + System::Library* lib; + if (t->m->system->success(t->m->system->load(&lib, name))) { + last->setNext(lib); + return lib; + } else { + return 0; + } +} + +System::Library* +loadLibrary(Thread* t, const char* path, const char* name, bool mapName, + bool runOnLoad) +{ + ACQUIRE(t, t->m->classLock); + + char* mappedName; + unsigned nameLength = strlen(name); + if (mapName) { + const char* builtins = findProperty(t, "avian.builtins"); + if (builtins) { + const char* s = builtins; + while (*s) { + if (::strncmp(s, name, nameLength) == 0 + and (s[nameLength] == ',' or s[nameLength] == 0)) + { + // library is built in to this executable + if (runOnLoad and not t->m->triedBuiltinOnLoad) { + t->m->triedBuiltinOnLoad = true; + // todo: release the classLock before calling this to + // avoid the possibility of deadlock: + runOnLoadIfFound(t, t->m->libraries); + } + return t->m->libraries; + } else { + while (*s and *s != ',') ++ s; + if (*s) ++ s; + } + } + } + + const char* prefix = t->m->system->libraryPrefix(); + const char* suffix = t->m->system->librarySuffix(); + unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix); + + mappedName = static_cast + (t->m->heap->allocate(mappedNameLength + 1)); + + snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix); + + name = mappedName; + nameLength = mappedNameLength; + } else { + mappedName = 0; + } + + THREAD_RESOURCE2 + (t, char*, mappedName, unsigned, nameLength, if (mappedName) { + t->m->heap->free(mappedName, nameLength + 1); + }); + + System::Library* lib = 0; + for (Tokenizer tokenizer(path, t->m->system->pathSeparator()); + tokenizer.hasMore();) + { + Tokenizer::Token token(tokenizer.next()); + + unsigned fullNameLength = token.length + 1 + nameLength; + THREAD_RUNTIME_ARRAY(t, char, fullName, fullNameLength + 1); + + snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1, + "%*s/%s", token.length, token.s, name); + + lib = loadLibrary(t, RUNTIME_ARRAY_BODY(fullName)); + if (lib) break; + } + + if (lib == 0) { + lib = loadLibrary(t, name); + } + + if (lib) { + if (runOnLoad) { + runOnLoadIfFound(t, lib); + } + } else { + throwNew(t, Machine::UnsatisfiedLinkErrorType, "library not found: %s", + name); + } + + return lib; +} + +object +clone(Thread* t, object o) +{ + PROTECT(t, o); + + object class_ = objectClass(t, o); + unsigned size = baseSize(t, o, class_) * BytesPerWord; + object clone; + + if (classArrayElementSize(t, class_)) { + clone = static_cast(allocate(t, size, classObjectMask(t, class_))); + memcpy(clone, o, size); + // clear any object header flags: + setObjectClass(t, o, objectClass(t, o)); + } else { + clone = make(t, class_); + memcpy(reinterpret_cast(clone) + 1, + reinterpret_cast(o) + 1, + size - BytesPerWord); + } + + return clone; +} + +object +makeStackTraceElement(Thread* t, object e) +{ + PROTECT(t, e); + + object class_ = className(t, methodClass(t, traceElementMethod(t, e))); + PROTECT(t, class_); + + THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), + reinterpret_cast(&byteArrayBody(t, class_, 0))); + class_ = makeString(t, "%s", s); + + object method = methodName(t, traceElementMethod(t, e)); + PROTECT(t, method); + + method = t->m->classpath->makeString + (t, method, 0, byteArrayLength(t, method) - 1); + + unsigned line = t->m->processor->lineNumber + (t, traceElementMethod(t, e), traceElementIp(t, e)); + + object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e))); + file = file ? t->m->classpath->makeString + (t, file, 0, byteArrayLength(t, file) - 1) : 0; + + return makeStackTraceElement(t, class_, method, file, line); +} + +} // namespace vm + +#endif//CLASSPATH_COMMON_H diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp new file mode 100644 index 0000000000..ab7ba61179 --- /dev/null +++ b/src/classpath-openjdk.cpp @@ -0,0 +1,3951 @@ +/* Copyright (c) 2010, 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. */ + +#include "machine.h" +#include "classpath-common.h" +#include "util.h" + +#ifdef PLATFORM_WINDOWS + +# include +# include +# include +# include +# include +# include +# include +# include + +# undef interface + +# define CLOSE _close +# define READ _read +# define WRITE _write +# define FSTAT _fstat +# define STAT _stat +# define LSEEK _lseek + +# define S_ISSOCK(x) false + +# ifdef _MSC_VER +# define S_ISREG(x) ((x) | _S_IFREG) +# define S_ISDIR(x) ((x) | _S_IFDIR) +# define S_IRUSR _S_IREAD +# define S_IWUSR _S_IWRITE +# else +# define OPEN _open +# define CREAT _creat +# endif + +# define O_RDONLY _O_RDONLY + +# ifdef AVIAN_OPENJDK_SRC +# define EXPORT(x) x +# else +# define EXPORT(x) _##x +# endif + +typedef int socklen_t; + +# define RTLD_DEFAULT 0 + +#else // not PLATFORM_WINDOWS + +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# define OPEN open +# define CLOSE close +# define READ read +# define WRITE write +# define STAT stat +# define FSTAT fstat +# define LSEEK lseek + +# define EXPORT(x) x + +#endif // not PLATFORM_WINDOWS + +using namespace vm; + +namespace { + +#ifdef _MSC_VER +inline int +OPEN(string_t path, int mask, int mode) +{ + int fd; + if (_wsopen_s(&fd, path, mask, _SH_DENYNO, mode) == 0) { + return fd; + } else { + return -1; + } +} + +inline int +CREAT(string_t path, int mode) +{ + return OPEN(path, _O_CREAT, mode); +} +#endif + +namespace local { + +const unsigned InterfaceVersion = 4; +const unsigned PageSize = 4 * 1024; +const int VirtualFileBase = 1000000000; + +Machine* globalMachine; + +const char* +primitiveName(Thread* t, object c) +{ + if (c == primitiveClass(t, 'V')) { + return "void"; + } else if (c == primitiveClass(t, 'Z')) { + return "boolean"; + } else if (c == primitiveClass(t, 'B')) { + return "byte"; + } else if (c == primitiveClass(t, 'C')) { + return "char"; + } else if (c == primitiveClass(t, 'S')) { + return "short"; + } else if (c == primitiveClass(t, 'I')) { + return "int"; + } else if (c == primitiveClass(t, 'F')) { + return "float"; + } else if (c == primitiveClass(t, 'J')) { + return "long"; + } else if (c == primitiveClass(t, 'D')) { + return "double"; + } else { + abort(t); + } +} + +object +getClassName(Thread* t, object c) +{ + if (className(t, c) == 0) { + if (classVmFlags(t, c) & PrimitiveFlag) { + PROTECT(t, c); + + object name = makeByteArray(t, primitiveName(t, c)); + + set(t, c, ClassName, name); + } else { + abort(t); + } + } + + return className(t, c); +} + +object +makeClassNameString(Thread* t, object name) +{ + THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, name)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), + reinterpret_cast(&byteArrayBody(t, name, 0))); + + return makeString(t, "%s", s); +} + +void +interceptFileOperations(Thread*); + +class MyClasspath : public Classpath { + public: + static const unsigned BufferSize = 1024; + + MyClasspath(System* s, Allocator* allocator, const char* javaHome, + const char* embedPrefix): + allocator(allocator), ranNetOnLoad(0) + { + class StringBuilder { + public: + StringBuilder(System* s, char* pointer, unsigned remaining): + s(s), pointer(pointer), remaining(remaining) + { } + + void append(const char* append) { + unsigned length = strlen(append); + expect(s, remaining > length); + + strncpy(pointer, append, remaining); + + remaining -= length; + pointer += length; + } + + void append(char c) { + assert(s, remaining > 1); + + pointer[0] = c; + pointer[1] = 0; + + -- remaining; + ++ pointer; + } + + System* s; + char* pointer; + unsigned remaining; + } sb(s, buffer, BufferSize); + + this->javaHome = sb.pointer; + sb.append(javaHome); + sb.append('\0'); + + this->classpath = sb.pointer; + sb.append(AVIAN_CLASSPATH); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/lib/rt.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/lib/jsse.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/lib/jce.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/lib/resources.jar"); + sb.append('\0'); + + this->libraryPath = sb.pointer; + sb.append(javaHome); +#ifdef PLATFORM_WINDOWS + sb.append("/bin"); +#elif defined ARCH_x86_64 + sb.append("/lib/amd64"); +#else + // todo: handle other architectures + sb.append("/lib/i386"); +#endif + sb.append('\0'); + + this->tzMappings = sb.pointer; + sb.append(javaHome); + sb.append("/lib/tzmappings"); + this->tzMappingsLength = sb.pointer - tzMappings; + sb.append('\0'); + + this->embedPrefix = sb.pointer; + sb.append(embedPrefix); + this->embedPrefixLength = sb.pointer - this->embedPrefix; + } + + virtual object + makeJclass(Thread* t, object class_) + { + PROTECT(t, class_); + + object name = makeClassNameString(t, getClassName(t, class_)); + + return vm::makeJclass + (t, 0, 0, name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, class_); + } + + virtual object + makeString(Thread* t, object array, int32_t offset, int32_t length) + { + if (objectClass(t, array) == type(t, Machine::ByteArrayType)) { + PROTECT(t, array); + + object charArray = makeCharArray(t, length); + for (int i = 0; i < length; ++i) { + charArrayBody(t, charArray, i) = byteArrayBody(t, array, offset + i); + } + + array = charArray; + } + return vm::makeString(t, array, offset, length, 0); + } + + virtual object + makeThread(Thread* t, Thread* parent) + { + const unsigned MaxPriority = 10; + const unsigned NormalPriority = 5; + + object group; + if (parent) { + group = threadGroup(t, parent->javaThread); + } else { + group = allocate(t, FixedSizeOfThreadGroup, true); + setObjectClass(t, group, type(t, Machine::ThreadGroupType)); + threadGroupMaxPriority(t, group) = MaxPriority; + } + + PROTECT(t, group); + + object thread = allocate(t, FixedSizeOfThread, true); + setObjectClass(t, thread, type(t, Machine::ThreadType)); + threadPriority(t, thread) = NormalPriority; + threadGroup(t, thread) = group; + threadContextClassLoader(t, thread) = root(t, Machine::BootLoader); + + PROTECT(t, thread); + + const unsigned BufferSize = 256; + char buffer[BufferSize]; + unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread); + object name = makeCharArray(t, length); + for (unsigned i = 0; i < length; ++i) { + charArrayBody(t, name, i) = buffer[i]; + } + set(t, thread, ThreadName, name); + + return thread; + } + + virtual void + runThread(Thread* t) + { + object method = resolveMethod + (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); + + t->m->processor->invoke(t, method, t->javaThread); + + acquire(t, t->javaThread); + t->flags &= ~Thread::ActiveFlag; + notifyAll(t, t->javaThread); + release(t, t->javaThread); + } + + virtual void + boot(Thread* t) + { + globalMachine = t->m; + + resolveSystemClass(t, root(t, Machine::BootLoader), + className(t, type(t, Machine::ClassLoaderType))); + +#ifdef AVIAN_OPENJDK_SRC + interceptFileOperations(t); +#else // not AVIAN_OPENJDK_SRC + if (loadLibrary(t, libraryPath, "verify", true, true) == 0 + or loadLibrary(t, libraryPath, "java", true, true) == 0) + { + abort(t); + } +#endif // not AVIAN_OPENJDK_SRC + + object constructor = resolveMethod + (t, type(t, Machine::ClassLoaderType), "", + "(Ljava/lang/ClassLoader;)V"); + + PROTECT(t, constructor); + + t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); + + t->m->processor->invoke + (t, constructor, root(t, Machine::AppLoader), + root(t, Machine::BootLoader)); + + object scl = resolveField + (t, type(t, Machine::ClassLoaderType), "scl", "Ljava/lang/ClassLoader;"); + + PROTECT(t, scl); + + object sclSet = resolveField + (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); + + set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), + fieldOffset(t, scl), root(t, Machine::AppLoader)); + + cast(classStaticTable(t, type(t, Machine::ClassLoaderType)), + fieldOffset(t, sclSet)) = true; + + t->m->processor->invoke + (t, root(t, Machine::BootLoader), "java/lang/System", + "initializeSystemClass", "()V", 0); + } + + virtual const char* + bootClasspath() + { + return classpath; + } + + virtual void + dispose() + { + allocator->free(this, sizeof(*this)); + } + + Allocator* allocator; + const char* javaHome; + const char* classpath; + const char* libraryPath; + const char* tzMappings; + const char* embedPrefix; + unsigned tzMappingsLength; + unsigned embedPrefixLength; + unsigned filePathField; + unsigned fileDescriptorFdField; + unsigned fileInputStreamFdField; + bool ranNetOnLoad; + char buffer[BufferSize]; +}; + +struct JVM_ExceptionTableEntryType { + jint start_pc; + jint end_pc; + jint handler_pc; + jint catchType; +}; + +struct jvm_version_info { + unsigned jvm_version; + unsigned update_version: 8; + unsigned special_update_version: 8; + unsigned reserved1: 16; + unsigned reserved2; + unsigned is_attach_supported: 1; + unsigned is_kernel_jvm: 1; + unsigned: 30; + unsigned: 32; + unsigned: 32; +}; + +Finder* +getFinder(Thread* t, const char* name, unsigned nameLength) +{ + ACQUIRE(t, t->m->referenceLock); + + for (object p = root(t, Machine::VirtualFileFinders); + p; p = finderNext(t, p)) + { + if (byteArrayLength(t, finderName(t, p)) == nameLength + and strncmp(reinterpret_cast + (&byteArrayBody(t, finderName(t, p), 0)), + name, nameLength)) + { + return static_cast(finderFinder(t, p)); + } + } + + object n = makeByteArray(t, nameLength + 1); + memcpy(&byteArrayBody(t, n, 0), name, nameLength); + + void* p = t->m->libraries->resolve + (reinterpret_cast(&byteArrayBody(t, n, 0))); + + if (p) { + uint8_t* (*function)(unsigned*); + memcpy(&function, &p, BytesPerWord); + + unsigned size; + uint8_t* data = function(&size); + if (data) { + Finder* f = makeFinder(t->m->system, t->m->heap, data, size); + object finder = makeFinder + (t, f, n, root(t, Machine::VirtualFileFinders)); + + setRoot(t, Machine::VirtualFileFinders, finder); + + return f; + } + } + + return 0; +} + +bool +pathEqual(const char* a, const char* b, unsigned length) +{ +#ifdef PLATFORM_WINDOWS + return strncasecmp(a, b, length) == 0; +#else + return strncmp(a, b, length) == 0; +#endif +} + +bool +pathEqual(const char* a, const char* b) +{ +#ifdef PLATFORM_WINDOWS + return strcasecmp(a, b) == 0; +#else + return strcmp(a, b) == 0; +#endif +} + +class EmbeddedFile { + public: + EmbeddedFile(MyClasspath* cp, const char* path, unsigned pathLength) { + if (pathEqual(cp->embedPrefix, path, cp->embedPrefixLength)) { + const char* p = path + cp->embedPrefixLength; + while (*p == '/') ++ p; + + this->jar = p; + + if (*p == 0) { + this->jarLength = 0; + this->path = 0; + this->pathLength = 0; + return; + } + + while (*p and *p != '/') ++p; + + this->jarLength = p - this->jar; + + while (*p == '/') ++p; + + this->path = p; + this->pathLength = pathLength - (p - path); + } else { + this->jar = 0; + this->jarLength =0; + this->path = 0; + this->pathLength = 0; + } + } + + const char* jar; + const char* path; + unsigned jarLength; + unsigned pathLength; +}; + +int64_t JNICALL +getFileAttributes +(Thread* t, object method, uintptr_t* arguments) +{ + const unsigned Exists = 1; + const unsigned Regular = 2; + const unsigned Directory = 4; + + MyClasspath* cp = static_cast(t->m->classpath); + + object file = reinterpret_cast(arguments[1]); + object path = cast(file, cp->filePathField); + + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return Exists | Directory; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { + return Exists | Directory; + } + + unsigned length; + System::FileType type = finder->stat(ef.path, &length, true); + switch (type) { + case System::TypeUnknown: return Exists; + case System::TypeDoesNotExist: return 0; + case System::TypeFile: return Exists | Regular; + case System::TypeDirectory: return Exists | Directory; + default: abort(t); + } + } else { + return 0; + } + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file)); + } +} + +int64_t JNICALL +checkFileAccess +(Thread* t, object method, uintptr_t* arguments) +{ + const unsigned Read = 4; + + MyClasspath* cp = static_cast(t->m->classpath); + + object file = reinterpret_cast(arguments[1]); + unsigned mask = arguments[2]; + object path = cast(file, cp->filePathField); + + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return mask == Read; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { + return mask == Read; + } + + unsigned length; + System::FileType type = finder->stat(ef.path, &length, true); + switch (type) { + case System::TypeDoesNotExist: return false; + case System::TypeUnknown: + case System::TypeFile: + case System::TypeDirectory: return mask == Read; + default: abort(t); + } + } else { + return 0; + } + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file, mask)) != 0; + } +} + +int64_t JNICALL +getFileLength +(Thread* t, object method, uintptr_t* arguments) +{ + MyClasspath* cp = static_cast(t->m->classpath); + + object file = reinterpret_cast(arguments[1]); + object path = cast(file, cp->filePathField); + + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return 0; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { + return 0; + } + + unsigned fileLength; + finder->stat(ef.path, &fileLength); + return fileLength; + } + + return 0; + } else { + return longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file)); + } +} + +void JNICALL +openFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object path = reinterpret_cast(arguments[1]); + + MyClasspath* cp = static_cast(t->m->classpath); + + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0 or ef.pathLength == 0) { + throwNew(t, Machine::FileNotFoundExceptionType); + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder == 0) { + throwNew(t, Machine::FileNotFoundExceptionType); + } + + System::Region* r = finder->find(ef.path); + if (r == 0) { + throwNew(t, Machine::FileNotFoundExceptionType); + } + + PROTECT(t, this_); + + ACQUIRE(t, t->m->referenceLock); + + int index = -1; + unsigned oldLength = root(t, Machine::VirtualFiles) + ? arrayLength(t, root(t, Machine::VirtualFiles)) : 0; + + for (unsigned i = 0; i < oldLength; ++i) { + if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) { + index = i; + break; + } + } + + if (index == -1) { + object newArray = growArray(t, root(t, Machine::VirtualFiles)); + setRoot(t, Machine::VirtualFiles, newArray); + index = oldLength; + } + + object region = makeRegion(t, r, 0); + set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), + region); + + cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField) + = index + VirtualFileBase; + } else { + t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, path); + } +} + +int64_t JNICALL +readByteFromFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + if (r->length() > regionPosition(t, region)) { + return r->start()[regionPosition(t, region)++]; + } else { + return -1; + } + } else { + throwNew(t, Machine::IoExceptionType); + } + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_)); + } +} + +int64_t JNICALL +readBytesFromFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object dst = reinterpret_cast(arguments[1]); + int32_t offset = arguments[2]; + int32_t length = arguments[3]; + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + int available = r->length() - regionPosition(t, region); + if (available == 0) { + return -1; + } + + if (length > available) { + length = available; + } + + memcpy(&byteArrayBody(t, dst, offset), + r->start() + regionPosition(t, region), + length); + + regionPosition(t, region) += length; + + return length; + } else { + throwNew(t, Machine::IoExceptionType); + } + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, dst, offset, length)); + } +} + +int64_t JNICALL +skipBytesInFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + int64_t count; memcpy(&count, arguments + 1, 8); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + int available = r->length() - regionPosition(t, region); + if (count > available) { + count = available; + } + + regionPosition(t, region) += count; + + return count; + } else { + throwNew(t, Machine::IoExceptionType); + } + } else { + return longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, count)); + } +} + +int64_t JNICALL +availableBytesInFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + return static_cast(regionRegion(t, region))->length() + - regionPosition(t, region); + } else { + throwNew(t, Machine::IoExceptionType); + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); + + return r ? intValue(t, r) : 0; + } +} + +void JNICALL +closeFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + int index = fd - VirtualFileBase; + object region = arrayBody(t, root(t, Machine::VirtualFiles), index); + + if (region) { + static_cast(regionRegion(t, region))->dispose(); + } + + set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), + 0); + } else { + t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); + } +} + +int64_t JNICALL +getBootstrapResource(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + PROTECT(t, name); + + object m = findMethodOrNull + (t, type(t, Machine::SystemClassLoaderType), + "findResource", "(Ljava/lang/String;)Ljava/net/URL;"); + + if (m) { + return reinterpret_cast + (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); + } else { + return 0; + } +} + +int64_t JNICALL +getBootstrapResources(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + PROTECT(t, name); + + object m = findMethodOrNull + (t, type(t, Machine::SystemClassLoaderType), + "findResources", "(Ljava/lang/String;)Ljava/util/Enumeration;"); + + if (m) { + return reinterpret_cast + (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); + } else { + return 0; + } +} + +extern "C" JNIEXPORT jint JNICALL +net_JNI_OnLoad(JavaVM*, void*); + +void JNICALL +loadLibrary(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[1]); + THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + bool absolute = arguments[2]; + +#ifdef AVIAN_OPENJDK_SRC + if (not absolute) { + if (strcmp(n, "net") == 0) { + bool ran; + + { ACQUIRE(t, t->m->classLock); + + local::MyClasspath* c = static_cast + (t->m->classpath); + + ran = c->ranNetOnLoad; + c->ranNetOnLoad = true; + } + + if (not ran) { + net_JNI_OnLoad(t->m, 0); + } + + return; + } else if (strcmp(n, "zip") == 0 + or strcmp(n, "nio") == 0) + { + return; + } + } +#endif // AVIAN_OPENJDK_SRC + + loadLibrary + (t, static_cast(t->m->classpath)->libraryPath, + RUNTIME_ARRAY_BODY(n), not absolute, false); +} + +// only safe to call during bootstrap when there's only one thread +// running: +void +intercept(Thread* t, object c, const char* name, const char* spec, + void* function) +{ + object m = findMethodOrNull(t, c, name, spec); + if (m) { + PROTECT(t, m); + + object clone = methodClone(t, m); + + // make clone private to prevent vtable updates at compilation + // time. Otherwise, our interception might be bypassed by calls + // through the vtable. + methodFlags(t, clone) |= ACC_PRIVATE; + + methodFlags(t, m) |= ACC_NATIVE; + + object native = makeNativeIntercept(t, function, true, clone); + + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, m); + + set(t, runtimeData, MethodRuntimeDataNative, native); + } +} + +void +interceptFileOperations(Thread* t) +{ + MyClasspath* cp = static_cast(t->m->classpath); + + { object fileClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/File"); + if (fileClass == 0) return; + + object filePathField = findFieldInClass2 + (t, fileClass, "path", "Ljava/lang/String;"); + if (filePathField == 0) return; + + cp->filePathField = fieldOffset(t, filePathField); + } + + { object fileDescriptorClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/FileDescriptor"); + if (fileDescriptorClass == 0) return; + + object fileDescriptorFdField = findFieldInClass2 + (t, fileDescriptorClass, "fd", "I"); + if (fileDescriptorFdField == 0) return; + + cp->fileDescriptorFdField = fieldOffset(t, fileDescriptorFdField); + } + + { object fileInputStreamClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/FileInputStream"); + if (fileInputStreamClass == 0) return; + + PROTECT(t, fileInputStreamClass); + + object fileInputStreamFdField = findFieldInClass2 + (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); + if (fileInputStreamFdField == 0) return; + + cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); + + intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", + voidPointer(openFile)); + + intercept(t, fileInputStreamClass, "read", "()I", + voidPointer(readByteFromFile)); + + intercept(t, fileInputStreamClass, "readBytes", "([BII)I", + voidPointer(readBytesFromFile)); + + intercept(t, fileInputStreamClass, "skip", "(J)J", + voidPointer(skipBytesInFile)); + + intercept(t, fileInputStreamClass, "available", "()I", + voidPointer(availableBytesInFile)); + + intercept(t, fileInputStreamClass, "close0", "()V", + voidPointer(closeFile)); + } + + { +#ifdef PLATFORM_WINDOWS + const char* const fsClassName = "java/io/WinNTFileSystem"; + const char* const gbaMethodName = "getBooleanAttributes"; +#else + const char* const fsClassName = "java/io/UnixFileSystem"; + const char* const gbaMethodName = "getBooleanAttributes0"; +#endif + + object fsClass = resolveClass + (t, root(t, Machine::BootLoader), fsClassName, false); + if (fsClass == 0) return; + + PROTECT(t, fsClass); + + intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", + voidPointer(getFileAttributes)); + + intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z", + voidPointer(checkFileAccess)); + + intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", + voidPointer(getFileLength)); + } + + intercept(t, type(t, Machine::ClassLoaderType), "loadLibrary", + "(Ljava/lang/Class;Ljava/lang/String;Z)V", + voidPointer(loadLibrary)); + + intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResource", + "(Ljava/lang/String;)Ljava/net/URL;", + voidPointer(getBootstrapResource)); + + intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResources", + "(Ljava/lang/String;)Ljava/util/Enumeration;", + voidPointer(getBootstrapResources)); +} + +unsigned +countMethods(Thread* t, object c, bool publicOnly) +{ + object table = classMethodTable(t, c); + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') + { + ++ count; + } + } + return count; +} + +unsigned +countFields(Thread* t, object c, bool publicOnly) +{ + object table = classFieldTable(t, c); + if (publicOnly) { + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmField = arrayBody(t, table, i); + if (fieldFlags(t, vmField) & ACC_PUBLIC) { + ++ count; + } + } + return count; + } else { + return objectArrayLength(t, table); + } +} + +unsigned +countConstructors(Thread* t, object c, bool publicOnly) +{ + object table = classMethodTable(t, c); + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and strcmp(reinterpret_cast + (&byteArrayBody(t, methodName(t, vmMethod), 0)), + "") == 0) + { + ++ count; + } + } + return count; +} + +object +resolveClassBySpec(Thread* t, object loader, const char* spec, + unsigned specLength) +{ + switch (*spec) { + case 'L': { + THREAD_RUNTIME_ARRAY(t, char, s, specLength - 1); + memcpy(RUNTIME_ARRAY_BODY(s), spec + 1, specLength - 2); + RUNTIME_ARRAY_BODY(s)[specLength - 2] = 0; + return resolveClass(t, loader, s); + } + + case '[': { + THREAD_RUNTIME_ARRAY(t, char, s, specLength + 1); + memcpy(RUNTIME_ARRAY_BODY(s), spec, specLength); + RUNTIME_ARRAY_BODY(s)[specLength] = 0; + return resolveClass(t, loader, s); + } + + default: + return primitiveClass(t, *spec); + } +} + +object +resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) +{ + return getJClass(t, resolveClassBySpec(t, loader, spec, specLength)); +} + +object +resolveParameterTypes(Thread* t, object loader, object spec, + unsigned* parameterCount, unsigned* returnTypeSpec) +{ + PROTECT(t, loader); + PROTECT(t, spec); + + object list = 0; + PROTECT(t, list); + + unsigned offset = 1; + unsigned count = 0; + while (byteArrayBody(t, spec, offset) != ')') { + switch (byteArrayBody(t, spec, offset)) { + case 'L': { + unsigned start = offset; + ++ offset; + while (byteArrayBody(t, spec, offset) != ';') ++ offset; + ++ offset; + + object type = resolveClassBySpec + (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), + offset - start); + + list = makePair(t, type, list); + + ++ count; + } break; + + case '[': { + unsigned start = offset; + while (byteArrayBody(t, spec, offset) == '[') ++ offset; + switch (byteArrayBody(t, spec, offset)) { + case 'L': + ++ offset; + while (byteArrayBody(t, spec, offset) != ';') ++ offset; + ++ offset; + break; + + default: + ++ offset; + break; + } + + object type = resolveClassBySpec + (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), + offset - start); + + list = makePair(t, type, list); + ++ count; + } break; + + default: + list = makePair + (t, primitiveClass(t, byteArrayBody(t, spec, offset)), list); + ++ offset; + ++ count; + break; + } + } + + *parameterCount = count; + *returnTypeSpec = offset + 1; + return list; +} + +object +resolveParameterJTypes(Thread* t, object loader, object spec, + unsigned* parameterCount, unsigned* returnTypeSpec) +{ + object list = resolveParameterTypes + (t, loader, spec, parameterCount, returnTypeSpec); + + PROTECT(t, list); + + object array = makeObjectArray + (t, type(t, Machine::JclassType), *parameterCount); + PROTECT(t, array); + + for (int i = *parameterCount - 1; i >= 0; --i) { + object c = getJClass(t, pairFirst(t, list)); + set(t, array, ArrayBody + (i * BytesPerWord), c); + list = pairSecond(t, list); + } + + return array; +} + +object +resolveExceptionJTypes(Thread* t, object loader, object addendum) +{ + if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { + return makeObjectArray(t, type(t, Machine::JclassType), 0); + } + + PROTECT(t, loader); + PROTECT(t, addendum); + + object array = makeObjectArray + (t, type(t, Machine::JclassType), + shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); + PROTECT(t, array); + + for (unsigned i = 0; i < shortArrayLength + (t, methodAddendumExceptionTable(t, addendum)); ++i) + { + uint16_t index = shortArrayBody + (t, methodAddendumExceptionTable(t, addendum), i) - 1; + + object o = singletonObject(t, addendumPool(t, addendum), index); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { + o = resolveClass(t, loader, referenceName(t, o)); + + set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), + o); + } + + o = getJClass(t, o); + + set(t, array, ArrayBody + (i * BytesPerWord), o); + } + + return array; +} + +void +setProperty(Thread* t, object method, object properties, + const char* name, const void* value, const char* format = "%s") +{ + PROTECT(t, method); + PROTECT(t, properties); + + object n = makeString(t, "%s", name); + PROTECT(t, n); + + object v = makeString(t, format, value); + + t->m->processor->invoke(t, method, properties, n, v); +} + +object +interruptLock(Thread* t, object thread) +{ + if (threadInterruptLock(t, thread) == 0) { + PROTECT(t, thread); + ACQUIRE(t, t->m->referenceLock); + + if (threadInterruptLock(t, thread) == 0) { + object head = makeMonitorNode(t, 0, 0); + object lock = makeMonitor(t, 0, 0, 0, head, head, 0); + set(t, thread, ThreadInterruptLock, lock); + } + } + + return threadInterruptLock(t, thread); +} + +bool +pipeAvailable(int fd, int* available) +{ +#ifdef PLATFORM_WINDOWS + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD n; + if (PeekNamedPipe(h, 0,0, 0, &n, 0)) { + *available = n; + } else { + if (GetLastError() != ERROR_BROKEN_PIPE) { + return false; + } + *available = 0; + } + + return true; +#else + return ioctl(fd, FIONREAD, available) >= 0; +#endif +} + +} // namespace local + +} // namespace + +namespace vm { + +Classpath* +makeClasspath(System* s, Allocator* allocator, const char* javaHome, + const char* embedPrefix) +{ + return new (allocator->allocate(sizeof(local::MyClasspath))) + local::MyClasspath(s, allocator, javaHome, embedPrefix); +} + +} // namespace vm + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getSuperclass +(Thread* t, object, uintptr_t* arguments) +{ + object super = classSuper + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); + + return super ? reinterpret_cast(getJClass(t, super)) : 0; +} + +extern "C" JNIEXPORT void +Avian_sun_misc_Unsafe_registerNatives +(Thread*, object, uintptr_t*) +{ + // ignore +} + +extern "C" JNIEXPORT int64_t +Avian_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoader_2Ljava_security_ProtectionDomain_2 +(Thread* t, object, uintptr_t* arguments) +{ + //object name = reinterpret_cast(arguments[1]); + object data = reinterpret_cast(arguments[2]); + int32_t offset = arguments[3]; + int32_t length = arguments[4]; + object loader = reinterpret_cast(arguments[5]); + //object domain = reinterpret_cast(arguments[6]); + + uint8_t* buffer = static_cast(t->m->heap->allocate(length)); + + THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, + t->m->heap->free(buffer, length)); + + memcpy(buffer, &byteArrayBody(t, data, offset), length); + + return reinterpret_cast + (getJClass(t, defineClass(t, loader, buffer, length))); +} + +extern "C" JNIEXPORT int64_t +Avian_sun_misc_Unsafe_allocateInstance +(Thread* t, object, uintptr_t* arguments) +{ + object c = jclassVmClass(t, reinterpret_cast(arguments[1])); + PROTECT(t, c); + + initClass(t, c); + + return reinterpret_cast(make(t, c)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_staticFieldOffset +(Thread* t, object, uintptr_t* arguments) +{ + object jfield = reinterpret_cast(arguments[1]); + return fieldOffset + (t, arrayBody + (t, classFieldTable + (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_arrayBaseOffset +(Thread*, object, uintptr_t*) +{ + return BytesPerWord * 2; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_arrayIndexScale +(Thread* t, object, uintptr_t* arguments) +{ + object c = jclassVmClass(t, reinterpret_cast(arguments[1])); + + if (classVmFlags(t, c) & PrimitiveFlag) { + const char* name = reinterpret_cast + (&byteArrayBody(t, local::getClassName(t, c), 0)); + + switch (*name) { + case 'b': return 1; + case 's': + case 'c': return 2; + case 'l': + case 'd': return 8; + case 'i': + case 'f': return 4; + default: abort(t); + } + } else { + return BytesPerWord; + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_staticFieldBase +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (classStaticTable + (t, jclassVmClass + (t, jfieldClazz(t, reinterpret_cast(arguments[1]))))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_objectFieldOffset +(Thread* t, object, uintptr_t* arguments) +{ + object jfield = reinterpret_cast(arguments[1]); + return fieldOffset + (t, arrayBody + (t, classFieldTable + (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getObject +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putObject +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uintptr_t value = arguments[4]; + + set(t, o, offset, reinterpret_cast(value)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getIntVolatile +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + int32_t result = cast(o, offset); + loadMemoryBarrier(); + return result; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int32_t value = arguments[4]; + + cast(o, offset) = value; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getBoolean +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putBoolean +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uint8_t value = arguments[4]; + + cast(o, offset) = value; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putLong__Ljava_lang_Object_2JJ +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int64_t value; memcpy(&value, arguments + 4, 8); + + cast(o, offset) = value; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getObjectVolatile +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + uintptr_t value = cast(o, offset); + loadMemoryBarrier(); + return value; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_compareAndSwapInt +(Thread*, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uint32_t expect = arguments[4]; + uint32_t update = arguments[5]; + + return atomicCompareAndSwap32 + (&cast(target, offset), expect, update); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_compareAndSwapObject +(Thread* t, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uintptr_t expect = arguments[4]; + uintptr_t update = arguments[5]; + + bool success = atomicCompareAndSwap + (&cast(target, offset), expect, update); + + if (success) { + mark(t, target, offset); + } + + return success; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_compareAndSwapLong +(Thread*, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uint64_t expect; memcpy(&expect, arguments + 4, 8); + uint64_t update; memcpy(&update, arguments + 6, 8); + + return atomicCompareAndSwap64 + (&cast(target, offset), expect, update); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_allocateMemory +(Thread* t, object, uintptr_t* arguments) +{ + void* p = malloc(arguments[1]); + if (p) { + return reinterpret_cast(p); + } else { + throwNew(t, Machine::OutOfMemoryErrorType); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_freeMemory +(Thread*, object, uintptr_t* arguments) +{ + void* p = reinterpret_cast(arguments[1]); + if (p) { + free(p); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_setMemory +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t count; memcpy(&count, arguments + 3, 8); + int8_t v = arguments[5]; + + memset(reinterpret_cast(p), v, count); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putLong__JJ +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t v; memcpy(&v, arguments + 3, 8); + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putInt__JI +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int32_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getByte__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getInt__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_pageSize +(Thread*, object, uintptr_t*) +{ + return local::PageSize; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_ensureClassInitialized +(Thread* t, object, uintptr_t* arguments) +{ + initClass(t, jclassVmClass(t, reinterpret_cast(arguments[1]))); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_unpark +(Thread* t, object, uintptr_t* arguments) +{ + object thread = reinterpret_cast(arguments[1]); + + monitorAcquire(t, local::interruptLock(t, thread)); + threadUnparked(t, thread) = true; + monitorNotify(t, local::interruptLock(t, thread)); + monitorRelease(t, local::interruptLock(t, thread)); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_park +(Thread* t, object, uintptr_t* arguments) +{ + bool absolute = arguments[1]; + int64_t time; memcpy(&time, arguments + 2, 8); + + if (absolute) { + time -= t->m->system->now(); + if (time <= 0) { + return; + } + } + + monitorAcquire(t, local::interruptLock(t, t->javaThread)); + while (not (threadUnparked(t, t->javaThread) + or monitorWait(t, local::interruptLock(t, t->javaThread), time))) + { } + threadUnparked(t, t->javaThread) = false; + monitorRelease(t, local::interruptLock(t, t->javaThread)); +} + +namespace { + +namespace local { + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetInterfaceVersion)() +{ + return local::InterfaceVersion; +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_IHashCode)(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + return objectHash(t, *o); +} + +uint64_t +jvmWait(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jlong milliseconds; memcpy(&milliseconds, arguments + 1, sizeof(jlong)); + + vm::wait(t, *o, milliseconds); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_MonitorWait)(Thread* t, jobject o, jlong milliseconds) +{ + uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)]; + arguments[0] = reinterpret_cast(o); + memcpy(arguments + 1, &milliseconds, sizeof(jlong)); + + run(t, jvmWait, arguments); +} + +uint64_t +jvmNotify(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + notify(t, *o); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_MonitorNotify)(Thread* t, jobject o) +{ + uintptr_t arguments[] = { reinterpret_cast(o) }; + + run(t, jvmNotify, arguments); +} + +uint64_t +jvmNotifyAll(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + notifyAll(t, *o); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o) +{ + uintptr_t arguments[] = { reinterpret_cast(o) }; + + run(t, jvmNotifyAll, arguments); +} + +uint64_t +jvmClone(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + return reinterpret_cast(makeLocalReference(t, clone(t, *o))); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_Clone)(Thread* t, jobject o) +{ + uintptr_t arguments[] = { reinterpret_cast(o) }; + + return reinterpret_cast(run(t, jvmClone, arguments)); +} + +uint64_t +jvmInternString(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + return reinterpret_cast(makeLocalReference(t, intern(t, *o))); +} + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_InternString)(Thread* t, jstring s) +{ + uintptr_t arguments[] = { reinterpret_cast(s) }; + + return reinterpret_cast(run(t, jvmInternString, arguments)); +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_CurrentTimeMillis)(Thread* t, jclass) +{ + return t->m->system->now(); +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_NanoTime)(Thread* t, jclass) +{ + return t->m->system->now() * 1000 * 1000; +} + +uint64_t +jvmArrayCopy(Thread* t, uintptr_t* arguments) +{ + jobject src = reinterpret_cast(arguments[0]); + jint srcOffset = arguments[1]; + jobject dst = reinterpret_cast(arguments[2]); + jint dstOffset = arguments[3]; + jint length = arguments[4]; + + arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_ArrayCopy)(Thread* t, jclass, jobject src, jint srcOffset, + jobject dst, jint dstOffset, jint length) +{ + uintptr_t arguments[] = { reinterpret_cast(src), + srcOffset, + reinterpret_cast(dst), + dstOffset, + length }; + + run(t, jvmArrayCopy, arguments); +} + +uint64_t +jvmInitProperties(Thread* t, uintptr_t* arguments) +{ + jobject properties = reinterpret_cast(arguments[0]); + + object method = resolveMethod + (t, root(t, Machine::BootLoader), "java/util/Properties", "setProperty", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); + + PROTECT(t, method); + +#ifdef PLATFORM_WINDOWS + local::setProperty(t, method, *properties, "line.separator", "\r\n"); + local::setProperty(t, method, *properties, "file.separator", "\\"); + local::setProperty(t, method, *properties, "path.separator", ";"); + local::setProperty(t, method, *properties, "os.name", "Windows"); + + TCHAR buffer[MAX_PATH]; + GetTempPath(MAX_PATH, buffer); + + local::setProperty(t, method, *properties, "java.io.tmpdir", buffer); + local::setProperty(t, method, *properties, "java.home", buffer); + local::setProperty(t, method, *properties, "user.home", + _wgetenv(L"USERPROFILE"), "%ls"); + + GetCurrentDirectory(MAX_PATH, buffer); + + local::setProperty(t, method, *properties, "user.dir", buffer); +#else + local::setProperty(t, method, *properties, "line.separator", "\n"); + local::setProperty(t, method, *properties, "file.separator", "/"); + local::setProperty(t, method, *properties, "path.separator", ":"); +# ifdef __APPLE__ + local::setProperty(t, method, *properties, "os.name", "Mac OS X"); +# else + local::setProperty(t, method, *properties, "os.name", "Linux"); +# endif + local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); + local::setProperty(t, method, *properties, "user.home", getenv("HOME")); + local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); +#endif + + local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", + "avian"); + + local::setProperty + (t, method, *properties, "java.home", + static_cast(t->m->classpath)->javaHome); + + local::setProperty + (t, method, *properties, "sun.boot.library.path", + static_cast(t->m->classpath)->libraryPath); + + local::setProperty(t, method, *properties, "file.encoding", "ASCII"); +#ifdef ARCH_x86_32 + local::setProperty(t, method, *properties, "os.arch", "x86"); +#elif defined ARCH_x86_64 + local::setProperty(t, method, *properties, "os.arch", "x86_64"); +#elif defined ARCH_powerpc + local::setProperty(t, method, *properties, "os.arch", "ppc"); +#elif defined ARCH_arm + local::setProperty(t, method, *properties, "os.arch", "arm"); +#else + local::setProperty(t, method, *properties, "os.arch", "unknown"); +#endif + + for (unsigned i = 0; i < t->m->propertyCount; ++i) { + const char* start = t->m->properties[i]; + const char* p = start; + while (*p and *p != '=') ++p; + + if (*p == '=') { + THREAD_RUNTIME_ARRAY(t, char, name, (p - start) + 1); + memcpy(name, start, p - start); + name[p - start] = 0; + local::setProperty + (t, method, *properties, RUNTIME_ARRAY_BODY(name), p + 1); + } + } + + return reinterpret_cast(properties); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_InitProperties)(Thread* t, jobject properties) +{ + uintptr_t arguments[] = { reinterpret_cast(properties) }; + + return reinterpret_cast(run(t, jvmInitProperties, arguments)); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_OnExit)(void (*)(void)) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Exit)(jint code) +{ + exit(code); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Halt)(jint code) +{ + exit(code); +} + +uint64_t +jvmGC(Thread* t, uintptr_t*) +{ + collect(t, Heap::MajorCollection); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_GC)() +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + run(t, jvmGC, 0); +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_MaxObjectInspectionAge)(void) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_TraceInstructions)(jboolean) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_TraceMethodCalls)(jboolean) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_TotalMemory)() +{ + return 0; +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_FreeMemory)() +{ + return 0; +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_MaxMemory)() +{ + return 0; +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_ActiveProcessorCount)() +{ + return 1; +} + +uint64_t +jvmLoadLibrary(Thread* t, uintptr_t* arguments) +{ + const char* path = reinterpret_cast(arguments[0]); + + THREAD_RUNTIME_ARRAY(t, char, p, strlen(path) + 1); + replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); + + return reinterpret_cast + (loadLibrary + (t, static_cast(t->m->classpath)->libraryPath, + RUNTIME_ARRAY_BODY(p), false, false)); +} + +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_LoadLibrary)(const char* path) +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + uintptr_t arguments[] = { reinterpret_cast(path) }; + + return reinterpret_cast(run(t, jvmLoadLibrary, arguments)); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_UnloadLibrary)(void*) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + if (library == RTLD_DEFAULT) { + library = t->m->libraries; + } + + return static_cast(library)->resolve(name); +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsSupportedJNIVersion)(jint version) +{ + return version <= JNI_VERSION_1_4; +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsNaN)(jdouble) { abort(); } + +uint64_t +jvmFillInStackTrace(Thread* t, uintptr_t* arguments) +{ + jobject throwable = reinterpret_cast(arguments[0]); + + object trace = getTrace(t, 1); + set(t, *throwable, ThrowableTrace, trace); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_FillInStackTrace)(Thread* t, jobject throwable) +{ + uintptr_t arguments[] = { reinterpret_cast(throwable) }; + + run(t, jvmFillInStackTrace, arguments); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_PrintStackTrace)(Thread*, jobject, jobject) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetStackTraceDepth)(Thread* t, jobject throwable) +{ + ENTER(t, Thread::ActiveState); + + return objectArrayLength(t, throwableTrace(t, *throwable)); +} + +uint64_t +jvmGetStackTraceElement(Thread* t, uintptr_t* arguments) +{ + jobject throwable = reinterpret_cast(arguments[0]); + jint index = arguments[1]; + + return reinterpret_cast + (makeLocalReference + (t, makeStackTraceElement + (t, objectArrayBody(t, throwableTrace(t, *throwable), index)))); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetStackTraceElement)(Thread* t, jobject throwable, jint index) +{ + uintptr_t arguments[] = { reinterpret_cast(throwable), index }; + + return reinterpret_cast(run(t, jvmGetStackTraceElement, arguments)); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_InitializeCompiler) (Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsSilentCompiler)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_CompileClass)(Thread*, jclass, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_CompileClasses)(Thread*, jclass, jstring) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_CompilerCommand)(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_EnableCompiler)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_DisableCompiler)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_StartThread)(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + startThread(t, *thread); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_StopThread)(Thread*, jobject, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsThreadAlive)(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + Thread* p = reinterpret_cast(threadPeer(t, *thread)); + return p and (p->flags & Thread::ActiveFlag) != 0; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SuspendThread)(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_ResumeThread)(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SetThreadPriority)(Thread*, jobject, jint) +{ + // ignore +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Yield)(Thread* t, jclass) +{ + t->m->system->yield(); +} + +uint64_t +jvmSleep(Thread* t, uintptr_t* arguments) +{ + jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong)); + + if (threadSleepLock(t, t->javaThread) == 0) { + object lock = makeJobject(t); + set(t, t->javaThread, ThreadSleepLock, lock); + } + + acquire(t, threadSleepLock(t, t->javaThread)); + vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); + release(t, threadSleepLock(t, t->javaThread)); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) +{ + uintptr_t arguments[sizeof(jlong) / BytesPerWord]; + memcpy(arguments, &milliseconds, sizeof(jlong)); + + run(t, jvmSleep, arguments); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_CurrentThread)(Thread* t, jclass) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, t->javaThread); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_CountStackFrames)(Thread*, jobject) { abort(); } + +uint64_t +jvmInterrupt(Thread* t, uintptr_t* arguments) +{ + jobject thread = reinterpret_cast(arguments[0]); + + monitorAcquire(t, local::interruptLock(t, *thread)); + Thread* p = reinterpret_cast(threadPeer(t, *thread)); + if (p) { + interrupt(t, p); + } else { + threadInterrupted(t, *thread) = true; + } + monitorRelease(t, local::interruptLock(t, *thread)); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Interrupt)(Thread* t, jobject thread) +{ + uintptr_t arguments[] = { reinterpret_cast(thread) }; + + run(t, jvmInterrupt, arguments); +} + +uint64_t +jvmIsInterrupted(Thread* t, uintptr_t* arguments) +{ + jobject thread = reinterpret_cast(arguments[0]); + jboolean clear = arguments[1]; + + monitorAcquire(t, local::interruptLock(t, *thread)); + bool v = threadInterrupted(t, *thread); + if (clear) { + threadInterrupted(t, *thread) = false; + } + monitorRelease(t, local::interruptLock(t, *thread)); + + return v; +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) +{ + uintptr_t arguments[] = { reinterpret_cast(thread), clear }; + + return run(t, jvmIsInterrupted, arguments); +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_HoldsLock)(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetAllThreads)(Thread*, jclass) { abort(); } + +uint64_t +jvmDumpThreads(Thread* t, uintptr_t* arguments) +{ + jobjectArray threads = reinterpret_cast(arguments[0]); + + unsigned threadsLength = objectArrayLength(t, *threads); + object arrayClass = resolveObjectArrayClass + (t, classLoader(t, type(t, Machine::StackTraceElementType)), + type(t, Machine::StackTraceElementType)); + object result = makeObjectArray(t, arrayClass, threadsLength); + PROTECT(t, result); + + for (unsigned threadsIndex = 0; threadsIndex < threadsLength; + ++ threadsIndex) + { + Thread* peer = reinterpret_cast + (threadPeer(t, objectArrayBody(t, *threads, threadsIndex))); + + if (peer) { + object trace = t->m->processor->getStackTrace(t, peer); + PROTECT(t, trace); + + unsigned traceLength = objectArrayLength(t, trace); + object array = makeObjectArray + (t, type(t, Machine::StackTraceElementType), traceLength); + PROTECT(t, array); + + for (unsigned traceIndex = 0; traceIndex < traceLength; ++ traceIndex) { + object ste = makeStackTraceElement + (t, objectArrayBody(t, trace, traceIndex)); + set(t, array, ArrayBody + (traceIndex * BytesPerWord), ste); + } + + set(t, result, ArrayBody + (threadsIndex * BytesPerWord), array); + } + } + + return reinterpret_cast(makeLocalReference(t, result)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) +{ + uintptr_t arguments[] = { reinterpret_cast(threads) }; + + return reinterpret_cast(run(t, jvmDumpThreads, arguments)); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_CurrentLoadedClass)(Thread*) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_CurrentClassLoader)(Thread*) { abort(); } + +uint64_t +jvmGetClassContext(Thread* t, uintptr_t*) +{ + object trace = getTrace(t, 1); + PROTECT(t, trace); + + object context = makeObjectArray + (t, type(t, Machine::JclassType), objectArrayLength(t, trace)); + PROTECT(t, context); + + for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { + object c = getJClass + (t, methodClass(t, traceElementMethod(t, objectArrayBody(t, trace, i)))); + + set(t, context, ArrayBody + (i * BytesPerWord), c); + } + + return reinterpret_cast(makeLocalReference(t, context)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassContext)(Thread* t) +{ + return reinterpret_cast(run(t, jvmGetClassContext, 0)); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_GetSystemPackage)(Thread*, jstring) +{ + return 0; +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetSystemPackages)(Thread*) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_AllocateNewObject)(Thread*, jobject, jclass, + jclass) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_AllocateNewArray)(Thread*, jobject, jclass, + jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_LatestUserDefinedLoader)(Thread*) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_LoadClass0)(Thread*, jobject, jclass, + jstring) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetArrayLength)(Thread* t, jobject array) +{ + ENTER(t, Thread::ActiveState); + + return cast(*array, BytesPerWord); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetArrayElement)(Thread* t, jobject array, jint index) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, objectArrayBody(t, *array, index)); +} + +extern "C" JNIEXPORT jvalue JNICALL +EXPORT(JVM_GetPrimitiveArrayElement)(Thread*, jobject, jint, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SetArrayElement)(Thread* t, jobject array, jint index, + jobject value) +{ + ENTER(t, Thread::ActiveState); + + set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SetPrimitiveArrayElement)(Thread*, jobject, jint, jvalue, + unsigned char) { abort(); } + +uint64_t +jvmNewArray(Thread* t, uintptr_t* arguments) +{ + jclass elementClass = reinterpret_cast(arguments[0]); + jint length = arguments[1]; + + object c = jclassVmClass(t, *elementClass); + + if (classVmFlags(t, c) & PrimitiveFlag) { + const char* name = reinterpret_cast + (&byteArrayBody(t, local::getClassName(t, c), 0)); + + switch (*name) { + case 'b': + if (name[1] == 'o') { + return reinterpret_cast + (makeLocalReference(t, makeBooleanArray(t, length))); + } else { + return reinterpret_cast + (makeLocalReference(t, makeByteArray(t, length))); + } + case 'c': return reinterpret_cast + (makeLocalReference(t, makeCharArray(t, length))); + case 'd': return reinterpret_cast + (makeLocalReference(t, makeDoubleArray(t, length))); + case 'f': return reinterpret_cast + (makeLocalReference(t, makeFloatArray(t, length))); + case 'i': return reinterpret_cast + (makeLocalReference(t, makeIntArray(t, length))); + case 'l': return reinterpret_cast + (makeLocalReference(t, makeLongArray(t, length))); + case 's': return reinterpret_cast + (makeLocalReference(t, makeShortArray(t, length))); + default: abort(t); + } + } else { + return reinterpret_cast + (makeLocalReference(t, makeObjectArray(t, c, length))); + } +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) +{ + uintptr_t arguments[] = { reinterpret_cast(elementClass), + length }; + + return reinterpret_cast(run(t, jvmNewArray, arguments)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_NewMultiArray)(Thread*, jclass, jintArray) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_GetCallerClass)(Thread* t, int target) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, getJClass(t, methodClass(t, getCaller(t, target)))); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) +{ + ENTER(t, Thread::ActiveState); + + switch (*name) { + case 'b': + if (name[1] == 'o') { + return makeLocalReference + (t, getJClass(t, type(t, Machine::JbooleanType))); + } else { + return makeLocalReference + (t, getJClass(t, type(t, Machine::JbyteType))); + } + case 'c': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JcharType))); + case 'd': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JdoubleType))); + case 'f': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JfloatType))); + case 'i': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JintType))); + case 'l': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JlongType))); + case 's': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JshortType))); + case 'v': + return makeLocalReference + (t, getJClass(t, type(t, Machine::JvoidType))); + default: + throwNew(t, Machine::IllegalArgumentExceptionType); + } +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_ResolveClass)(Thread*, jclass) { abort(); } + +uint64_t +jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments) +{ + const char* name = reinterpret_cast(arguments[0]); + jboolean init = arguments[1]; + jobject loader = reinterpret_cast(arguments[2]); + jboolean throwError = arguments[3]; + + THREAD_RESOURCE(t, jboolean, throwError, { + if (t->exception and throwError) { + object exception = t->exception; + t->exception = 0; + + t->exception = makeThrowable + (t, Machine::NoClassDefFoundErrorType, + throwableMessage(t, exception), + throwableTrace(t, exception), + throwableCause(t, exception)); + } + }); + + object c = resolveClass + (t, loader ? *loader : root(t, Machine::BootLoader), name); + + if (init) { + PROTECT(t, c); + + initClass(t, c); + } + + return reinterpret_cast(makeLocalReference(t, getJClass(t, c))); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, + jboolean init, jobject loader, + jboolean throwError) +{ + uintptr_t arguments[] = { reinterpret_cast(name), + init, + reinterpret_cast(loader), + throwError }; + + return reinterpret_cast + (run(t, jvmFindClassFromClassLoader, arguments)); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindClassFromBootLoader)(Thread* t, const char* name, + jboolean throwError) +{ + return EXPORT(JVM_FindClassFromClassLoader)(t, name, false, 0, throwError); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindClassFromClass)(Thread*, const char*, jboolean, jclass) +{ abort(); } + +uint64_t +jvmFindLoadedClass(Thread* t, uintptr_t* arguments) +{ + jobject loader = reinterpret_cast(arguments[0]); + jstring name = reinterpret_cast(arguments[1]); + + object spec = makeByteArray(t, stringLength(t, *name) + 1); + + { char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); + stringChars(t, *name, s); + replace('.', '/', s); + } + + object c = findLoadedClass(t, *loader, spec); + + return reinterpret_cast + (c ? makeLocalReference(t, getJClass(t, c)) : 0); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) +{ + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(name) }; + + return reinterpret_cast(run(t, jvmFindLoadedClass, arguments)); +} + +uint64_t +jvmDefineClass(Thread* t, uintptr_t* arguments) +{ + jobject loader = reinterpret_cast(arguments[0]); + const uint8_t* data = reinterpret_cast(arguments[1]); + jsize length = arguments[2]; + + return reinterpret_cast + (makeLocalReference + (t, getJClass(t, defineClass(t, *loader, data, length)))); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_DefineClass)(Thread* t, const char*, jobject loader, + const uint8_t* data, jsize length, jobject) +{ + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(data), + length }; + + return reinterpret_cast(run(t, jvmDefineClass, arguments)); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_DefineClassWithSource)(Thread* t, const char*, jobject loader, + const uint8_t* data, jsize length, jobject, + const char*) +{ + return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0); +} + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_GetClassName)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, jclassName(t, *c)); +} + +uint64_t +jvmGetClassInterfaces(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + + object table = classInterfaceTable(t, jclassVmClass(t, *c)); + if (table) { + PROTECT(t, table); + + unsigned stride = + (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; + + object array = makeObjectArray + (t, type(t, Machine::JclassType), arrayLength(t, table) / stride); + PROTECT(t, array); + + for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { + object interface = getJClass(t, arrayBody(t, table, i * stride)); + set(t, array, ArrayBody + (i * BytesPerWord), interface); + } + + return reinterpret_cast(makeLocalReference(t, array)); + } else { + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JclassType), 0))); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) +{ + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, jvmGetClassInterfaces, arguments)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetClassLoader)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object loader = classLoader(t, jclassVmClass(t, *c)); + + if (loader == root(t, Machine::BootLoader)) { + // sun.misc.Unsafe.getUnsafe expects a null result if the class + // loader is the boot classloader and will throw a + // SecurityException otherwise. + object caller = getCaller(t, 2); + if (caller and strcmp + (reinterpret_cast + (&byteArrayBody(t, className(t, methodClass(t, caller)), 0)), + "sun/misc/Unsafe") == 0) + { + return 0; + } else { + return makeLocalReference(t, root(t, Machine::BootLoader)); + } + } else { + return makeLocalReference(t, loader); + } +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsInterface)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) != 0; +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassSigners)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object runtimeData = getClassRuntimeDataIfExists(t, jclassVmClass(t, *c)); + + return runtimeData ? makeLocalReference + (t, classRuntimeDataSigners(t, runtimeData)) : 0; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) +{ + ENTER(t, Thread::ActiveState); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataSigners, *signers); +} + +uint64_t +jvmGetProtectionDomain(Thread* t, uintptr_t*) +{ + object openJDK = resolveClass + (t, root(t, Machine::BootLoader), "avian/OpenJDK"); + + object method = resolveMethod + (t, openJDK, "getProtectionDomain", "()Ljava/security/ProtectionDomain;"); + + return reinterpret_cast + (makeLocalReference(t, t->m->processor->invoke(t, method, 0))); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) +{ + return reinterpret_cast(run(t, jvmGetProtectionDomain, 0)); +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SetProtectionDomain)(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsArrayClass)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return classArrayDimensions(t, jclassVmClass(t, *c)) != 0; +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsPrimitiveClass)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return (classVmFlags(t, jclassVmClass(t, *c)) & PrimitiveFlag) != 0; +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_GetComponentType)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); + if (n != 'L' and n != '[') { + return makeLocalReference(t, getJClass(t, primitiveClass(t, n))); + } else { + return makeLocalReference + (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c)))); + } +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return classFlags(t, jclassVmClass(t, *c)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetDeclaredClasses)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_GetClassSignature)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jbyteArray JNICALL +EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object addendum = classAddendum(t, jclassVmClass(t, *c)); + return addendum + ? makeLocalReference(t, addendumAnnotationTable(t, addendum)) : 0; +} + +uint64_t +jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + jboolean publicOnly = arguments[1]; + + object table = classMethodTable(t, jclassVmClass(t, *c)); + if (table) { + PROTECT(t, table); + + object array = makeObjectArray + (t, type(t, Machine::JmethodType), + local::countMethods(t, jclassVmClass(t, *c), publicOnly)); + PROTECT(t, array); + + unsigned ai = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + PROTECT(t, vmMethod); + + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') + { + object name = intern + (t, t->m->classpath->makeString + (t, methodName(t, vmMethod), 0, byteArrayLength + (t, methodName(t, vmMethod)) - 1)); + PROTECT(t, name); + + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = local::resolveParameterJTypes + (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), + ¶meterCount, &returnTypeSpec); + PROTECT(t, parameterTypes); + + object returnType = local::resolveJType + (t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast + (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), + byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); + PROTECT(t, returnType); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, jclassVmClass(t, *c)), + methodAddendum(t, vmMethod)); + PROTECT(t, exceptionTypes); + + object signature = t->m->classpath->makeString + (t, methodSpec(t, vmMethod), 0, byteArrayLength + (t, methodSpec(t, vmMethod)) - 1); + + object annotationTable = methodAddendum(t, vmMethod) == 0 + ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); + + if (annotationTable) { + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, methodAddendum(t, vmMethod))); + } + + object method = makeJmethod + (t, true, *c, i, name, returnType, parameterTypes, exceptionTypes, + methodFlags(t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, + 0, 0, 0); + + assert(t, ai < objectArrayLength(t, array)); + + set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); + } + } + + return reinterpret_cast(makeLocalReference(t, array)); + } else { + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JmethodType), 0))); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) +{ + uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; + + return reinterpret_cast + (run(t, jvmGetClassDeclaredMethods, arguments)); +} + +uint64_t +jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + jboolean publicOnly = arguments[1]; + object table = classFieldTable(t, jclassVmClass(t, *c)); + if (table) { + PROTECT(t, table); + + object array = makeObjectArray + (t, type(t, Machine::JfieldType), + local::countFields(t, jclassVmClass(t, *c), publicOnly)); + PROTECT(t, array); + + unsigned ai = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmField = arrayBody(t, table, i); + PROTECT(t, vmField); + + if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { + object name = intern + (t, t->m->classpath->makeString + (t, fieldName(t, vmField), 0, byteArrayLength + (t, fieldName(t, vmField)) - 1)); + PROTECT(t, name); + + object type = local::resolveClassBySpec + (t, classLoader(t, jclassVmClass(t, *c)), + reinterpret_cast + (&byteArrayBody(t, fieldSpec(t, vmField), 0)), + byteArrayLength(t, fieldSpec(t, vmField)) - 1); + PROTECT(t, type); + + type = getJClass(t, type); + + object signature = t->m->classpath->makeString + (t, fieldSpec(t, vmField), 0, byteArrayLength + (t, fieldSpec(t, vmField)) - 1); + + object annotationTable = fieldAddendum(t, vmField) == 0 + ? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField)); + + if (annotationTable) { + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, fieldAddendum(t, vmField))); + } + + object field = makeJfield + (t, true, *c, i, name, type, fieldFlags + (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0, 0, 0); + + assert(t, ai < objectArrayLength(t, array)); + + set(t, array, ArrayBody + ((ai++) * BytesPerWord), field); + } + } + assert(t, ai == objectArrayLength(t, array)); + + return reinterpret_cast(makeLocalReference(t, array)); + } else { + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JfieldType), 0))); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) +{ + uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; + + return reinterpret_cast + (run(t, jvmGetClassDeclaredFields, arguments)); +} + +uint64_t +jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + jboolean publicOnly = arguments[1]; + + object table = classMethodTable(t, jclassVmClass(t, *c)); + if (table) { + PROTECT(t, table); + + object array = makeObjectArray + (t, type(t, Machine::JconstructorType), + local::countConstructors(t, jclassVmClass(t, *c), publicOnly)); + PROTECT(t, array); + + unsigned ai = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + PROTECT(t, vmMethod); + + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and strcmp(reinterpret_cast + (&byteArrayBody(t, methodName(t, vmMethod), 0)), + "") == 0) + { + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = local::resolveParameterJTypes + (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), + ¶meterCount, &returnTypeSpec); + PROTECT(t, parameterTypes); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, jclassVmClass(t, *c)), + methodAddendum(t, vmMethod)); + PROTECT(t, exceptionTypes); + + object signature = t->m->classpath->makeString + (t, methodSpec(t, vmMethod), 0, byteArrayLength + (t, methodSpec(t, vmMethod)) - 1); + + object annotationTable = methodAddendum(t, vmMethod) == 0 + ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); + + if (annotationTable) { + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, methodAddendum(t, vmMethod))); + } + + object method = makeJconstructor + (t, true, *c, i, parameterTypes, exceptionTypes, methodFlags + (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, 0); + + assert(t, ai < objectArrayLength(t, array)); + + set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); + } + } + + return reinterpret_cast(makeLocalReference(t, array)); + } else { + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JconstructorType), 0))); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, + jboolean publicOnly) +{ + uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; + + return reinterpret_cast + (run(t, jvmGetClassDeclaredConstructors, arguments)); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetClassAccessFlags)(Thread* t, jclass c) +{ + return EXPORT(JVM_GetClassModifiers)(t, c); +} + +uint64_t +jvmInvokeMethod(Thread* t, uintptr_t* arguments) +{ + jobject method = reinterpret_cast(arguments[0]); + jobject instance = reinterpret_cast(arguments[1]); + jobjectArray args = reinterpret_cast(arguments[2]); + + object vmMethod = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jmethodClazz(t, *method))), + jmethodSlot(t, *method)); + + if (methodFlags(t, vmMethod) & ACC_STATIC) { + instance = 0; + } + + object result; + if (args) { + result = t->m->processor->invokeArray + (t, vmMethod, instance ? *instance : 0, *args); + } else { + result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); + } + + return reinterpret_cast(makeLocalReference(t, result)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, + jobjectArray args) +{ + uintptr_t arguments[] = { reinterpret_cast(method), + reinterpret_cast(instance), + reinterpret_cast(args) }; + + return reinterpret_cast(run(t, jvmInvokeMethod, arguments)); +} + +uint64_t +jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments) +{ + jobject constructor = reinterpret_cast(arguments[0]); + jobjectArray args = reinterpret_cast(arguments[1]); + + object instance = make + (t, jclassVmClass(t, jconstructorClazz(t, *constructor))); + PROTECT(t, instance); + + object method = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jconstructorClazz(t, *constructor))), + jconstructorSlot(t, *constructor)); + + if (args) { + t->m->processor->invokeArray(t, method, instance, *args); + } else { + t->m->processor->invoke(t, method, instance); + } + + return reinterpret_cast(makeLocalReference(t, instance)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, + jobjectArray args) +{ + uintptr_t arguments[] = { reinterpret_cast(constructor), + reinterpret_cast(args) }; + + return reinterpret_cast + (run(t, jvmNewInstanceFromConstructor, arguments)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetClassConstantPool)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object vmClass = jclassVmClass(t, *c); + object addendum = classAddendum(t, vmClass); + object pool; + if (addendum) { + pool = addendumPool(t, addendum); + } else { + pool = 0; + } + + if (pool == 0) { + pool = classRuntimeDataPool(t, getClassRuntimeData(t, vmClass)); + } + + return makeLocalReference(t, makeConstantPool(t, pool)); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_ConstantPoolGetSize)(Thread* t, jobject, jobject pool) +{ + if (pool == 0) return 0; + + ENTER(t, Thread::ActiveState); + + return singletonCount(t, *pool); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_ConstantPoolGetClassAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_ConstantPoolGetClassAtIfLoaded)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_ConstantPoolGetMethodAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_ConstantPoolGetMethodAtIfLoaded)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_ConstantPoolGetFieldAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_ConstantPoolGetFieldAtIfLoaded)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_ConstantPoolGetMemberRefInfoAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_ConstantPoolGetIntAt)(Thread* t, jobject, jobject pool, jint index) +{ + ENTER(t, Thread::ActiveState); + + return singletonValue(t, *pool, index - 1); +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_ConstantPoolGetLongAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jfloat JNICALL +EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jdouble JNICALL +EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint) +{ abort(); } + +uint64_t +jvmConstantPoolGetUTF8At(Thread* t, uintptr_t* arguments) +{ + jobject pool = reinterpret_cast(arguments[0]); + jint index = arguments[1]; + + object array = singletonObject(t, *pool, index - 1); + + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1))); +} + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index) +{ + uintptr_t arguments[] = { reinterpret_cast(pool), index }; + + return reinterpret_cast + (run(t, jvmConstantPoolGetUTF8At, arguments)); +} + +void +maybeWrap(Thread* t, bool wrapException) +{ + if (t->exception + and wrapException + and not (instanceOf(t, type(t, Machine::ErrorType), t->exception) + or instanceOf + (t, type(t, Machine::RuntimeExceptionType), t->exception))) + { + object exception = t->exception; + t->exception = 0; + + PROTECT(t, exception); + + object paeClass = resolveClass + (t, root(t, Machine::BootLoader), + "java/security/PrivilegedActionException"); + PROTECT(t, paeClass); + + object paeConstructor = resolveMethod + (t, paeClass, "", "(Ljava/lang/Exception;)V"); + PROTECT(t, paeConstructor); + + object result = make(t, paeClass); + PROTECT(t, result); + + t->m->processor->invoke(t, paeConstructor, result, exception); + + t->exception = result; + } +} + +uint64_t +jvmDoPrivileged(Thread* t, uintptr_t* arguments) +{ + jobject action = reinterpret_cast(arguments[0]); + jboolean wrapException = arguments[1]; + + // todo: cache these class and method lookups in the t->m->classpath + // object: + + object privilegedAction = resolveClass + (t, root(t, Machine::BootLoader), "java/security/PrivilegedAction"); + + object method; + if (instanceOf(t, privilegedAction, *action)) { + method = resolveMethod + (t, privilegedAction, "run", "()Ljava/lang/Object;"); + } else { + object privilegedExceptionAction = resolveClass + (t, root(t, Machine::BootLoader), + "java/security/PrivilegedExceptionAction"); + + method = resolveMethod + (t, privilegedExceptionAction, "run", "()Ljava/lang/Object;"); + } + + THREAD_RESOURCE(t, jboolean, wrapException, maybeWrap(t, wrapException)); + + return reinterpret_cast + (makeLocalReference(t, t->m->processor->invoke(t, method, *action))); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_DoPrivileged) +(Thread* t, jclass, jobject action, jobject, jboolean wrapException) +{ + uintptr_t arguments[] = { reinterpret_cast(action), + wrapException }; + + return reinterpret_cast(run(t, jvmDoPrivileged, arguments)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetInheritedAccessControlContext)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetStackAccessControlContext)(Thread*, jclass) +{ + return 0; +} + +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_RegisterSignal)(jint, void*) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_RaiseSignal)(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_FindSignal)(const char*) +{ + return -1; +} + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_DesiredAssertionStatus)(Thread*, jclass, jclass) +{ + return false; +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_AssertionStatusDirectives)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_SupportsCX8)() +{ + return true; +} + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetClassNameUTF)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_GetClassCPTypes)(Thread*, jclass, unsigned char*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetClassCPEntriesCount)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetClassFieldsCount)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetClassMethodsCount)(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_GetMethodIxExceptionIndexes)(Thread*, jclass, jint, + unsigned short*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxExceptionsCount)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_GetMethodIxByteCode)(Thread*, jclass, jint, + unsigned char*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxByteCodeLength)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_GetMethodIxExceptionTableEntry)(Thread*, jclass, jint, + jint, + local::JVM_ExceptionTableEntryType*) +{ abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxExceptionTableLength)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetFieldIxModifiers)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxModifiers)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxLocalsCount)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxArgsSize)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetMethodIxMaxStack)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsConstructorIx)(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetMethodIxSignatureUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPFieldNameUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPMethodNameUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPMethodSignatureUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPFieldSignatureUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPClassNameUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPFieldClassNameUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +EXPORT(JVM_GetCPMethodClassNameUTF)(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetCPFieldModifiers)(Thread*, jclass, int, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetCPMethodModifiers)(Thread*, jclass, int, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_ReleaseUTF)(const char*) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsSameClassPackage)(Thread*, jclass, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetLastErrorString)(char* dst, int length) +{ + strncpy(dst, strerror(errno), length); + return strlen(dst); +} + +extern "C" JNIEXPORT char* JNICALL +EXPORT(JVM_NativePath)(char* path) +{ + return path; +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Open)(const char* path, jint flags, jint mode) +{ + return OPEN(path, flags, mode); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Close)(jint fd) +{ + return CLOSE(fd); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Read)(jint fd, char* dst, jint length) +{ + return READ(fd, dst, length); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Write)(jint fd, char* src, jint length) +{ + return WRITE(fd, src, length); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Available)(jint fd, jlong* result) +{ + struct STAT buffer; + int n; + if (FSTAT(fd, &buffer) >= 0 + and (S_ISCHR(buffer.st_mode) + or S_ISFIFO(buffer.st_mode) + or S_ISSOCK(buffer.st_mode)) + and local::pipeAvailable(fd, &n)) + { + *result = n; + return 1; + } + + int current = LSEEK(fd, 0, SEEK_CUR); + if (current == -1) return 0; + + int end = LSEEK(fd, 0, SEEK_END); + if (end == -1) return 0; + + if (LSEEK(fd, current, SEEK_SET) == -1) return 0; + + *result = end - current; + return 1; +} + +extern "C" JNIEXPORT jlong JNICALL +EXPORT(JVM_Lseek)(jint fd, jlong offset, jint seek) +{ + return LSEEK(fd, offset, seek); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_SetLength)(jint, jlong) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Sync)(jint fd) +{ +#ifdef PLATFORM_WINDOWS + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + + if (FlushFileBuffers(h)) { + return 0; + } else { + errno = EIO; + return -1; + } +#else + return fsync(fd); +#endif +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_InitializeSocketLibrary)() +{ +#ifdef PLATFORM_WINDOWS + static bool wsaInitialized = false; + if (not wsaInitialized) { + WSADATA data; + int r = WSAStartup(MAKEWORD(2, 2), &data); + if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { + return -1; + } else { + wsaInitialized = true; + } + } +#endif + return 0; +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Socket)(jint domain, jint type, jint protocol) +{ + return socket(domain, type, protocol); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_SocketClose)(jint socket) +{ +#ifdef PLATFORM_WINDOWS + return closesocket(socket); +#else + return close(socket); +#endif +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_SocketShutdown)(jint socket, jint how) +{ + return shutdown(socket, how); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Recv)(jint socket, char* dst, jint count, jint flags) +{ + return recv(socket, dst, count, flags); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Send)(jint socket, char* src, jint count, jint flags) +{ + return send(socket, src, count, flags); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Timeout)(int, long) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Listen)(jint socket, jint count) +{ + return listen(socket, count); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Connect)(jint socket, sockaddr* address, jint addressLength) +{ + return connect(socket, address, addressLength); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Bind)(jint, struct sockaddr*, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_Accept)(jint socket, struct sockaddr* address, jint* addressLength) +{ + socklen_t length = *addressLength; + int r = accept(socket, address, &length); + *addressLength = length; + return r; +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_RecvFrom)(jint, char*, int, + int, struct sockaddr*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_SendTo)(jint, char*, int, + int, struct sockaddr*, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_SocketAvailable)(jint, jint*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetSockName)(jint socket, struct sockaddr* address, + int* addressLength) +{ + socklen_t length = *addressLength; + int r = getsockname(socket, address, &length); + *addressLength = length; + return r; +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_GetSockOpt)(jint, int, int, char*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_SetSockOpt)(jint, int, int, const char*, int) { abort(); } + +extern "C" JNIEXPORT struct protoent* JNICALL +EXPORT(JVM_GetProtoByName)(char*) { abort(); } + +extern "C" JNIEXPORT struct hostent* JNICALL +EXPORT(JVM_GetHostByAddr)(const char*, int, int) { abort(); } + +extern "C" JNIEXPORT struct hostent* JNICALL +EXPORT(JVM_GetHostByName)(char*) { abort(); } + +extern "C" JNIEXPORT int JNICALL +EXPORT(JVM_GetHostName)(char* name, int length) +{ + return gethostname(name, length); +} + +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_RawMonitorCreate)(void) +{ + System* s = local::globalMachine->system; + System::Monitor* lock; + if (s->success(s->make(&lock))) { + return lock; + } else { + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_RawMonitorDestroy)(void* lock) +{ + static_cast(lock)->dispose(); +} + +extern "C" JNIEXPORT jint JNICALL +EXPORT(JVM_RawMonitorEnter)(void* lock) +{ + static_cast(lock)->acquire + (static_cast + (local::globalMachine->localThread->get())->systemThread); + + return 0; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_RawMonitorExit)(void* lock) +{ + static_cast(lock)->release + (static_cast + (local::globalMachine->localThread->get())->systemThread); +} + +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_GetManagement)(jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_InitAgentProperties)(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetEnclosingMethodInfo)(JNIEnv*, jclass) { abort(); } + +extern "C" JNIEXPORT jintArray JNICALL +EXPORT(JVM_GetThreadStateValues)(JNIEnv*, jint) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetThreadStateNames)(JNIEnv*, jint, jintArray) { abort(); } + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_GetVersionInfo)(JNIEnv*, local::jvm_version_info*, size_t) +{ abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_CX8Field)(JNIEnv*, jobject*, jfieldID*, jlong, jlong) +{ abort(); } + +} // namespace local + +} // namespace + +extern "C" JNIEXPORT int +jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) +{ + return vm::vsnprintf(dst, size, format, a); +} + +extern "C" JNIEXPORT int +jio_vfprintf(FILE* stream, const char* format, va_list a) +{ + return vfprintf(stream, format, a); +} + +#ifdef PLATFORM_WINDOWS +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_GetThreadInterruptEvent)() +{ abort(); } + +namespace { HMODULE jvmHandle = 0; } + +extern "C" int JDK_InitJvmHandle() +{ + jvmHandle = GetModuleHandle(0); + return jvmHandle != 0; +} + +extern "C" void* JDK_FindJvmEntry(const char* name) +{ + return voidPointer(GetProcAddress(jvmHandle, name)); +} + +# ifdef AVIAN_OPENJDK_SRC + +extern "C" char* findJavaTZ_md(const char*, const char*); + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_util_TimeZone_getSystemTimeZoneID +(Thread* t, object, uintptr_t* arguments) +{ + // On Windows, findJavaTZ_md loads tzmappings from the filesystem + // using fopen, so we have no opportunity to make it read straight + // from the embedded JAR file as with files read from Java code. + // Therefore, we must extract tzmappings to a temporary location + // before calling findJavaTZ_md. We could avoid this by + // implementing findJavaTZ_md ourselves from scratch, but that would + // be a lot of code to implement and maintain. + + object country = reinterpret_cast(arguments[1]); + + THREAD_RUNTIME_ARRAY(t, char, countryChars, stringLength(t, country) + 1); + stringChars(t, country, RUNTIME_ARRAY_BODY(countryChars)); + + local::MyClasspath* cp = static_cast(t->m->classpath); + + local::EmbeddedFile ef(cp, cp->tzMappings, cp->tzMappingsLength); + if (ef.jar == 0 or ef.jarLength == 0 or ef.pathLength == 0) { + return 0; + } + + Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); + if (finder == 0) { + return 0; + } + + System::Region* r = finder->find(ef.path); + if (r == 0) { + return 0; + } + + THREAD_RESOURCE(t, System::Region*, r, r->dispose()); + + char tmpPath[MAX_PATH + 1]; + GetTempPathA(MAX_PATH, tmpPath); + + char tmpDir[MAX_PATH + 1]; + vm::snprintf(tmpDir, MAX_PATH, "%s/avian-tmp", tmpPath); + if (_mkdir(tmpDir) != 0 and errno != EEXIST) { + return 0; + } + + THREAD_RESOURCE(t, char*, tmpDir, rmdir(tmpDir)); + + char libDir[MAX_PATH + 1]; + vm::snprintf(libDir, MAX_PATH, "%s/lib", tmpDir); + if (mkdir(libDir) != 0 and errno != EEXIST) { + return 0; + } + + THREAD_RESOURCE(t, char*, libDir, rmdir(libDir)); + + char file[MAX_PATH + 1]; + vm::snprintf(file, MAX_PATH, "%s/tzmappings", libDir); + FILE* out = vm::fopen(file, "wb"); + if (out == 0) { + return 0; + } + + THREAD_RESOURCE(t, char*, file, unlink(file)); + THREAD_RESOURCE(t, FILE*, out, fclose(out)); + + if (fwrite(r->start(), 1, r->length(), out) != r->length() + or fflush(out) != 0) + { + return 0; + } + + char* javaTZ = findJavaTZ_md(tmpDir, RUNTIME_ARRAY_BODY(countryChars)); + if (javaTZ) { + THREAD_RESOURCE(t, char*, javaTZ, free(javaTZ)); + + return reinterpret_cast(makeString(t, "%s", javaTZ)); + } else { + return 0; + } +} +# else // not AVIAN_OPENJDK_SRC +extern "C" JNIEXPORT int +jio_snprintf(char* dst, size_t size, const char* format, ...) +{ + va_list a; + va_start(a, format); + + int r = jio_vsnprintf(dst, size, format, a); + + va_end(a); + + return r; +} + +extern "C" JNIEXPORT int +jio_fprintf(FILE* stream, const char* format, ...) +{ + va_list a; + va_start(a, format); + + int r = jio_vfprintf(stream, format, a); + + va_end(a); + + return r; +} +# endif // not AVIAN_OPENJDK_SRC +#endif // PLATFORM_WINDOWS diff --git a/src/common.h b/src/common.h index 1a672feb6d..13957bedfd 100644 --- a/src/common.h +++ b/src/common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -59,6 +59,16 @@ typedef uint64_t uintptr_t; # error "unsupported architecture" # endif +namespace vm { + +inline intptr_t& +alias(void* p, unsigned offset) +{ + return *reinterpret_cast(static_cast(p) + offset); +} + +} // namespace vm + #else // not _MSC_VER # include "stdint.h" @@ -86,6 +96,17 @@ typedef uint64_t uintptr_t; # error "unsupported architecture" # endif +namespace vm { + +typedef intptr_t __attribute__((__may_alias__)) intptr_alias_t; +inline intptr_alias_t& +alias(void* p, unsigned offset) +{ + return *reinterpret_cast(static_cast(p) + offset); +} + +} // namespace vm + #endif // not _MSC_VER #undef JNIEXPORT @@ -132,7 +153,7 @@ typedef uint64_t uintptr_t; #endif #ifdef __APPLE__ -# define SO_SUFFIX ".jnilib" +# define SO_SUFFIX ".dylib" #elif defined PLATFORM_WINDOWS # define SO_SUFFIX ".dll" #else @@ -143,6 +164,16 @@ typedef uint64_t uintptr_t; #define MACRO_MakeNameXY(FX, LINE) MACRO_XY(FX, LINE) #define MAKE_NAME(FX) MACRO_MakeNameXY(FX, __LINE__) +#define RESOURCE(type, name, release) \ + class MAKE_NAME(Resource_) { \ + public: \ + MAKE_NAME(Resource_)(type name): name(name) { } \ + ~MAKE_NAME(Resource_)() { release; } \ + \ + private: \ + type name; \ + } MAKE_NAME(resource_)(name); + inline void* operator new(size_t, void* p) throw() { return p; } namespace vm { @@ -301,67 +332,98 @@ log(unsigned n) return r; } +template inline unsigned wordOf(unsigned i) { - return i / BitsPerWord; + return i / (sizeof(T) * 8); +} + +inline unsigned +wordOf(unsigned i) +{ + return wordOf(i); +} + +template +inline unsigned +bitOf(unsigned i) +{ + return i % (sizeof(T) * 8); } inline unsigned bitOf(unsigned i) { - return i % BitsPerWord; + return bitOf(i); +} + +template +inline unsigned +indexOf(unsigned word, unsigned bit) +{ + return (word * (sizeof(T) * 8)) + bit; } inline unsigned indexOf(unsigned word, unsigned bit) { - return (word * BitsPerWord) + bit; + return indexOf(word, bit); } +template inline void -markBit(uintptr_t* map, unsigned i) +markBit(T* map, unsigned i) { - map[wordOf(i)] |= static_cast(1) << bitOf(i); + map[wordOf(i)] |= static_cast(1) << bitOf(i); } +template inline void -clearBit(uintptr_t* map, unsigned i) +clearBit(T* map, unsigned i) { - map[wordOf(i)] &= ~(static_cast(1) << bitOf(i)); + map[wordOf(i)] &= ~(static_cast(1) << bitOf(i)); } +template inline unsigned -getBit(uintptr_t* map, unsigned i) +getBit(T* map, unsigned i) { - return (map[wordOf(i)] & (static_cast(1) << bitOf(i))) - >> bitOf(i); + return (map[wordOf(i)] & (static_cast(1) << bitOf(i))) + >> bitOf(i); } +// todo: the following (clearBits, setBits, and getBits) could be made +// more efficient by operating on a word at a time instead of a bit at +// a time: + +template inline void -clearBits(uintptr_t* map, unsigned bitsPerRecord, unsigned index) +clearBits(T* map, unsigned bitsPerRecord, unsigned index) { for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { - clearBit(map, i); + clearBit(map, i); } } +template inline void -setBits(uintptr_t* map, unsigned bitsPerRecord, int index, unsigned v) +setBits(T* map, unsigned bitsPerRecord, int index, unsigned v) { for (int i = index + bitsPerRecord - 1; i >= index; --i) { - if (v & 1) markBit(map, i); else clearBit(map, i); + if (v & 1) markBit(map, i); else clearBit(map, i); v >>= 1; } } +template inline unsigned -getBits(uintptr_t* map, unsigned bitsPerRecord, unsigned index) +getBits(T* map, unsigned bitsPerRecord, unsigned index) { unsigned v = 0; for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { v <<= 1; - v |= getBit(map, i); + v |= getBit(map, i); } return v; } @@ -465,6 +527,16 @@ replace(char a, char b, char* c) for (; *c; ++c) if (*c == a) *c = b; } +inline void +replace(char a, char b, char* dst, const char* src) +{ + unsigned i = 0; + for (; src[i]; ++ i) { + dst[i] = src[i] == a ? b : src[i]; + } + dst[i] = 0; +} + class Machine; class Thread; diff --git a/src/compile-arm.S b/src/compile-arm.S new file mode 100644 index 0000000000..8af887fdbb --- /dev/null +++ b/src/compile-arm.S @@ -0,0 +1,243 @@ +/* Copyright (c) 2010, 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. */ + +#include "types.h" + +.text + +#define BYTES_PER_WORD 4 + +#define LOCAL(x) .L##x + +#ifdef __APPLE__ +# define GLOBAL(x) _##x +#else +# define GLOBAL(x) x +#endif + +#define THREAD_STACK 2148 +#define THREAD_SCRATCH 2152 +#define THREAD_CONTINUATION 2156 +#define THREAD_EXCEPTION 44 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 +#define THREAD_EXCEPTION_OFFSET 2164 +#define THREAD_EXCEPTION_HANDLER 2168 + +#define CONTINUATION_NEXT 4 +#define CONTINUATION_ADDRESS 16 +#define CONTINUATION_RETURN_ADDRESS_OFFSET 20 +#define CONTINUATION_FRAME_POINTER_OFFSET 24 +#define CONTINUATION_LENGTH 28 +#define CONTINUATION_BODY 32 + +.globl GLOBAL(vmInvoke) +GLOBAL(vmInvoke): + /* + arguments + r0 : thread + r1 : function + r2 : arguments + r3 : argumentFootprint + [sp, #0] : frameSize (not used) + [sp, #4] : returnType + */ + + // save all non-volatile registers + stmfd sp!, {r4-r11, lr} + + // save return type + ldr r4, [sp, #4] + str r4, [sp, #-4]! + + str sp, [r0, #THREAD_SCRATCH] + + // align stack, if necessary + eor r4, sp, r3 + tst r4, #4 + subne sp, sp, #4 + + // copy arguments into place + sub sp, r3 + mov r4, #0 + b LOCAL(vmInvoke_argumentTest) + +LOCAL(vmInvoke_argumentLoop): + ldr r5, [r2, r4] + str r5, [sp, r4] + add r4, r4, #BYTES_PER_WORD + +LOCAL(vmInvoke_argumentTest): + cmp r4, r3 + blt LOCAL(vmInvoke_argumentLoop) + + // we use r8 to hold the thread pointer, by convention + mov r8, r0 + + // load and call function address + blx r1 + +.globl GLOBAL(vmInvoke_returnAddress) +GLOBAL(vmInvoke_returnAddress): + // restore stack pointer + ldr sp, [r8, #THREAD_SCRATCH] + + // clear MyThread::stack to avoid confusing another thread calling + // java.lang.Thread.getStackTrace on this one. See + // MyProcess::getStackTrace in compile.cpp for details on how we get + // a reliable stack trace from a thread that might be interrupted at + // any point in its execution. + mov r5, #0 + str r5, [r8, #THREAD_STACK] + +.globl GLOBAL(vmInvoke_safeStack) +GLOBAL(vmInvoke_safeStack): + +#ifdef AVIAN_CONTINUATIONS + // call the next continuation, if any + ldr r5,[r8,#THREAD_CONTINUATION] + cmp r5,#0 + beq LOCAL(vmInvoke_exit) + + ldr r6,[r5,#CONTINUATION_LENGTH] + lsl r6,r6,#2 + neg r7,r6 + add r7,r7,#-80 + mov r4,sp + str r4,[sp,r7]! + + add r7,r5,#CONTINUATION_BODY + + mov r11,#0 + b LOCAL(vmInvoke_continuationTest) + +LOCAL(vmInvoke_continuationLoop): + ldr r9,[r7,r11] + str r9,[sp,r11] + add r11,r11,#4 + +LOCAL(vmInvoke_continuationTest): + cmp r11,r6 + ble LOCAL(vmInvoke_continuationLoop) + + ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET] + ldr r10,LOCAL(vmInvoke_returnAddress_word) + ldr r11,LOCAL(vmInvoke_getAddress_word) +LOCAL(vmInvoke_getAddress): + add r11,pc,r11 + ldr r11,[r11,r10] + str r11,[sp,r7] + + ldr r7,[r5,#CONTINUATION_NEXT] + str r7,[r8,#THREAD_CONTINUATION] + + // call the continuation unless we're handling an exception + ldr r7,[r8,#THREAD_EXCEPTION] + cmp r7,#0 + bne LOCAL(vmInvoke_handleException) + ldr r7,[r5,#CONTINUATION_ADDRESS] + bx r7 + +LOCAL(vmInvoke_handleException): + // we're handling an exception - call the exception handler instead + mov r11,#0 + str r11,[r8,#THREAD_EXCEPTION] + ldr r11,[r8,#THREAD_EXCEPTION_STACK_ADJUSTMENT] + ldr r9,[sp] + neg r11,r11 + str r9,[sp,r11]! + ldr r11,[r8,#THREAD_EXCEPTION_OFFSET] + str r7,[sp,r11] + + ldr r7,[r8,#THREAD_EXCEPTION_HANDLER] + bx r7 + +LOCAL(vmInvoke_exit): +#endif // AVIAN_CONTINUATIONS + + mov ip, #0 + str ip, [r8, #THREAD_STACK] + + // restore return type + ldr ip, [sp], #4 + + // restore callee-saved registers + ldmfd sp!, {r4-r11, lr} + +LOCAL(vmInvoke_void): + cmp ip, #VOID_TYPE + beq LOCAL(vmInvoke_return) + +LOCAL(vmInvoke_int64): + cmp ip, #INT64_TYPE + beq LOCAL(vmInvoke_return) + +LOCAL(vmInvoke_int32): + mov r1, #0 + +LOCAL(vmInvoke_return): + bx lr + +.globl GLOBAL(vmJumpAndInvoke) +GLOBAL(vmJumpAndInvoke): +#ifdef AVIAN_CONTINUATIONS + // r0: thread + // r1: address + // r2: stack + // r3: argumentFootprint + // [sp,#0]: arguments + // [sp,#4]: frameSize + + ldr r5,[sp,#0] + ldr r6,[sp,#4] + + // allocate new frame, adding room for callee-saved registers + sub r2,r2,r6 + sub r2,r2,#80 + + mov r8,r0 + + // copy arguments into place + mov r6,#0 + b LOCAL(vmJumpAndInvoke_argumentTest) + +LOCAL(vmJumpAndInvoke_argumentLoop): + ldr r12,[r5,r6] + str r12,[r2,r6] + add r6,r6,#4 + +LOCAL(vmJumpAndInvoke_argumentTest): + cmp r6,r4 + ble LOCAL(vmJumpAndInvoke_argumentLoop) + + // the arguments have been copied, so we can set the real stack + // pointer now + mov sp,r2 + + // set return address to vmInvoke_returnAddress + ldr r10,LOCAL(vmInvoke_returnAddress_word) + ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word) +LOCAL(vmJumpAndInvoke_getAddress): + add r11,pc,r11 + ldr lr,[r11,r10] + + bx r1 + +LOCAL(vmInvoke_returnAddress_word): + .word GLOBAL(vmInvoke_returnAddress)(GOT) +LOCAL(vmInvoke_getAddress_word): + .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8) +LOCAL(vmJumpAndInvoke_getAddress_word): + .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8) + +#else // not AVIAN_CONTINUATIONS + // vmJumpAndInvoke should only be called when continuations are + // enabled + bkpt +#endif // not AVIAN_CONTINUATIONS diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index b732f893ea..7e40816105 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -24,7 +24,7 @@ # define GLOBAL(x) x #endif -#define THREAD_STACK 2152 +#define THREAD_STACK 2148 #define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 #define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 @@ -241,43 +241,42 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // r3: thread // r4: address - // r5: (unused) - // r6: stack - // r7: argumentFootprint - // r8: arguments - // r9: frameSize + // r5: stack + // r6: argumentFootprint + // r7: arguments + // r8: frameSize // restore (pseudo)-stack pointer (we don't want to touch the real // stack pointer, since we haven't copied the arguments yet) - lwz r6,0(r6) + lwz r5,0(r5) - // make everything between r1 and r6 one big stack frame while we + // make everything between r1 and r5 one big stack frame while we // shuffle things around - stw r6,0(r1) + stw r5,0(r1) // allocate new frame, adding room for callee-saved registers - subfic r10,r9,-80 - stwux r6,r6,r10 + subfic r10,r8,-80 + stwux r5,r5,r10 mr r13,r3 // copy arguments into place - li r9,0 - addi r11,r6,ARGUMENT_BASE + li r8,0 + addi r11,r5,ARGUMENT_BASE b LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - lwzx r12,r8,r9 - stwx r12,r11,r9 - addi r9,r9,4 + lwzx r12,r7,r8 + stwx r12,r11,r8 + addi r8,r8,4 LOCAL(vmJumpAndInvoke_argumentTest): - cmplw r9,r7 + cmplw r8,r6 ble LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now - mr r1,r6 + mr r1,r5 // set return address to vmInvoke_returnAddress bl LOCAL(vmJumpAndInvoke_getPC) diff --git a/src/compile-x86.S b/src/compile-x86.S index 7dd9349f40..3f839ce3c5 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -12,7 +12,8 @@ #define LOCAL(x) .L##x -#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ +#if defined __APPLE__ \ + || ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__) # define GLOBAL(x) _##x #else # define GLOBAL(x) x @@ -22,11 +23,18 @@ #ifdef __x86_64__ -#define THREAD_STACK 2216 +#define THREAD_STACK 2224 +#define THREAD_SCRATCH 2232 +#ifdef AVIAN_USE_FRAME_POINTER +# define ALIGNMENT_ADJUSTMENT 0 +#else +# define ALIGNMENT_ADJUSTMENT 8 +#endif + #if defined __MINGW32__ || defined __CYGWIN32__ -#define CALLEE_SAVED_REGISTER_FOOTPRINT 64 +#define CALLEE_SAVED_REGISTER_FOOTPRINT 64 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): @@ -40,22 +48,25 @@ GLOBAL(vmInvoke): // 48(%rbp) : frameSize // 56(%rbp) : returnType (ignored) - // allocate stack space, adding room for callee-saved registers - movl 48(%rbp),%eax - subq %rax,%rsp + // allocate stack space for callee-saved registers subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + + // remember this stack position, since we won't be able to rely on + // %rbp being restored when the call returns + movq %rsp,THREAD_SCRATCH(%rcx) // save callee-saved registers - movq %rsp,%r11 - addq %rax,%r11 - - movq %rbx,0(%r11) - movq %r12,8(%r11) - movq %r13,16(%r11) - movq %r14,24(%r11) - movq %r15,32(%r11) - movq %rsi,40(%r11) - movq %rdi,48(%r11) + movq %rbx,0(%rsp) + movq %r12,8(%rsp) + movq %r13,16(%rsp) + movq %r14,24(%rsp) + movq %r15,32(%rsp) + movq %rsi,40(%rsp) + movq %rdi,48(%rsp) + + // allocate stack space for arguments + movl 48(%rbp),%eax + subq %rax,%rsp // we use rbx to hold the thread pointer, by convention mov %rcx,%rbx @@ -79,7 +90,7 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer - movq %rbp,%rsp + movq THREAD_SCRATCH(%rbx),%rsp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See @@ -95,19 +106,17 @@ GLOBAL(vmInvoke_safeStack): # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS - // restore callee-saved registers (below the stack pointer, but in - // the red zone) - movq %rsp,%r11 - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r11 - - movq 0(%r11),%rbx - movq 8(%r11),%r12 - movq 16(%r11),%r13 - movq 24(%r11),%r14 - movq 32(%r11),%r15 - movq 40(%r11),%rsi - movq 48(%r11),%rdi + // restore callee-saved registers + movq 0(%rsp),%rbx + movq 8(%rsp),%r12 + movq 16(%rsp),%r13 + movq 24(%rsp),%r14 + movq 32(%rsp),%r15 + movq 40(%rsp),%rsi + movq 48(%rsp),%rdi + addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + // return popq %rbp ret @@ -117,47 +126,39 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // %rcx: thread // %rdx: address - // %r8 : base - // %r9 : (unused) - // 40(%rsp): argumentFootprint - // 48(%rsp): arguments - // 56(%rsp): frameSize - - movq %r8,%rbp + // %r8 : stack + // %r9 : argumentFootprint + // 40(%rsp): arguments + // 48(%rsp): frameSize - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - movq %rbp,%r9 - // allocate new frame, adding room for callee-saved registers - movl 56(%rsp),%eax - subq %rax,%r9 - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9 + movl 48(%rsp),%eax + subq %rax,%r8 + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r8 movq %rcx,%rbx // set return address leaq GLOBAL(vmInvoke_returnAddress)(%rip),%r10 - movq %r10,(%r9) + movq %r10,(%r8) // copy arguments into place movq $0,%r11 - movl 48(%rsp),%r8d movl 40(%rsp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - movq (%r8,%r11,1),%r10 - movq %r10,8(%r9,%r11,1) + movq (%rax,%r11,1),%r10 + movq %r10,8(%r8,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): - cmpq %rax,%r11 + cmpq %9,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now - movq %r9,%rsp + movq %r8,%rsp jmp *%rdx #else // not AVIAN_CONTINUATIONS @@ -168,7 +169,7 @@ LOCAL(vmJumpAndInvoke_argumentTest): #else // not __MINGW32__ || __CYGWIN32__ -#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 +#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): @@ -182,20 +183,23 @@ GLOBAL(vmInvoke): // %r8 : frameSize // %r9 : returnType (ignored) - // allocate stack space, adding room for callee-saved registers - subq %r8,%rsp + // allocate stack space for callee-saved registers subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + // remember this stack position, since we won't be able to rely on + // %rbp being restored when the call returns + movq %rsp,THREAD_SCRATCH(%rdi) + // save callee-saved registers - movq %rsp,%r9 - addq %r8,%r9 - - movq %rbx,0(%r9) - movq %r12,8(%r9) - movq %r13,16(%r9) - movq %r14,24(%r9) - movq %r15,32(%r9) - + movq %rbx,0(%rsp) + movq %r12,8(%rsp) + movq %r13,16(%rsp) + movq %r14,24(%rsp) + movq %r15,32(%rsp) + + // allocate stack space for arguments + subq %r8,%rsp + // we use rbx to hold the thread pointer, by convention mov %rdi,%rbx @@ -218,7 +222,7 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer - movq %rbp,%rsp + movq THREAD_SCRATCH(%rbx),%rsp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See @@ -233,18 +237,16 @@ GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS + + // restore callee-saved registers + movq 0(%rsp),%rbx + movq 8(%rsp),%r12 + movq 16(%rsp),%r13 + movq 24(%rsp),%r14 + movq 32(%rsp),%r15 + + addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp - // restore callee-saved registers (below the stack pointer, but in - // the red zone) - movq %rsp,%r9 - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9 - - movq 0(%r9),%rbx - movq 8(%r9),%r12 - movq 16(%r9),%r13 - movq 24(%r9),%r14 - movq 32(%r9),%r15 - // return popq %rbp ret @@ -254,45 +256,37 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // %rdi: thread // %rsi: address - // %rdx: base - // %rcx: (unused) - // %r8 : argumentFootprint - // %r9 : arguments - // 8(%rsp): frameSize - - movq %rdx,%rbp - - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - movq %rbp,%rcx + // %rdx: stack + // %rcx: argumentFootprint + // %r8 : arguments + // %r9 : frameSize // allocate new frame, adding room for callee-saved registers - movl 8(%rsp),%eax - subq %rax,%rcx - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rcx + subq %r9,%rdx + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rdx movq %rdi,%rbx // set return address movq GLOBAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 - movq %r10,(%rcx) + movq %r10,(%rdx) // copy arguments into place movq $0,%r11 jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - movq (%r9,%r11,1),%r10 - movq %r10,8(%rcx,%r11,1) + movq (%r8,%r11,1),%r10 + movq %r10,8(%rdx,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): - cmpq %r8,%r11 + cmpq %rcx,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now - movq %rcx,%rsp + movq %rdx,%rsp jmp *%rsi #else // not AVIAN_CONTINUATIONS @@ -305,10 +299,17 @@ LOCAL(vmJumpAndInvoke_argumentTest): #elif defined __i386__ -#define THREAD_STACK 2144 - -#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 - +#define THREAD_STACK 2148 +#define THREAD_SCRATCH 2152 + +#ifdef AVIAN_USE_FRAME_POINTER +# define ALIGNMENT_ADJUSTMENT 0 +#else +# define ALIGNMENT_ADJUSTMENT 12 +#endif + +#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 + ALIGNMENT_ADJUSTMENT + .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushl %ebp @@ -320,21 +321,24 @@ GLOBAL(vmInvoke): // 20(%ebp): argumentFootprint // 24(%ebp): frameSize // 28(%ebp): returnType - - // allocate stack space, adding room for callee-saved registers - subl 24(%ebp),%esp + + // allocate stack space for callee-saved registers subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp - // save callee-saved registers - movl %esp,%ecx - addl 24(%ebp),%ecx + // remember this stack position, since we won't be able to rely on + // %rbp being restored when the call returns + movl 8(%ebp),%eax + movl %esp,THREAD_SCRATCH(%eax) - movl %ebx,0(%ecx) - movl %esi,4(%ecx) - movl %edi,8(%ecx) + movl %ebx,0(%esp) + movl %esi,4(%esp) + movl %edi,8(%esp) + + // allocate stack space for arguments + subl 24(%ebp),%esp // we use ebx to hold the thread pointer, by convention - mov 8(%ebp),%ebx + mov %eax,%ebx // copy arguments into place movl $0,%ecx @@ -355,11 +359,8 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): - // restore stack pointer, preserving the area containing saved - // registers - movl %ebp,%ecx - subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx - movl %ecx,%esp + // restore stack pointer + movl THREAD_SCRATCH(%ebx),%esp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See @@ -379,11 +380,11 @@ GLOBAL(vmInvoke_safeStack): movl 0(%esp),%ebx movl 4(%esp),%esi movl 8(%esp),%edi - - // handle return value based on expected type - movl 28(%ebp),%ecx addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp + + // handle return value based on expected type + movl 28(%esp),%ecx LOCAL(vmInvoke_void): cmpl $VOID_TYPE,%ecx @@ -411,20 +412,15 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // 4(%esp): thread // 8(%esp): address - // 12(%esp): base - // 16(%esp): (unused) - // 20(%esp): argumentFootprint - // 24(%esp): arguments - // 28(%esp): frameSize + // 12(%esp): stack + // 16(%esp): argumentFootprint + // 20(%esp): arguments + // 24(%esp): frameSize - movl 12(%esp),%ebp - - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - movl %ebp,%ecx + movl 12(%esp),%ecx // allocate new frame, adding room for callee-saved registers - subl 28(%esp),%ecx + subl 24(%esp),%ecx subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx movl 4(%esp),%ebx @@ -446,8 +442,8 @@ LOCAL(vmJumpAndInvoke_offset): // copy arguments into place movl $0,%esi - movl 20(%esp),%edx - movl 24(%esp),%eax + movl 16(%esp),%edx + movl 20(%esp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): diff --git a/src/compile.cpp b/src/compile.cpp index e5d7a7df2d..37374f03c0 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -29,13 +29,10 @@ extern "C" void vmInvoke_safeStack(); extern "C" void -vmJumpAndInvoke(void* thread, void* function, void* base, void* stack, +vmJumpAndInvoke(void* thread, void* function, void* stack, unsigned argumentFootprint, uintptr_t* arguments, unsigned frameSize); -extern "C" void -vmCall(); - namespace { namespace local { @@ -61,6 +58,20 @@ const unsigned InitialZoneCapacityInBytes = 64 * 1024; const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024; +enum Root { + CallTable, + MethodTree, + MethodTreeSentinal, + ObjectPools, + StaticTableArray, + VirtualThunks, + ReceiveMethod, + WindMethod, + RewindMethod +}; + +const unsigned RootCount = RewindMethod + 1; + inline bool isVmInvokeUnsafeStack(void* ip) { @@ -76,26 +87,28 @@ class MyThread: public Thread { public: CallTrace(MyThread* t, object method): t(t), - base(t->base), stack(t->stack), + scratch(t->scratch), continuation(t->continuation), nativeMethod((methodFlags(t, method) & ACC_NATIVE) ? method : 0), targetMethod(0), originalMethod(method), next(t->trace) { - doTransition(t, 0, 0, 0, 0, this); + doTransition(t, 0, 0, 0, this); } ~CallTrace() { assert(t, t->stack == 0); - doTransition(t, 0, stack, base, continuation, next); + t->scratch = scratch; + + doTransition(t, 0, stack, continuation, next); } MyThread* t; - void* base; void* stack; + void* scratch; object continuation; object nativeMethod; object targetMethod; @@ -118,11 +131,10 @@ class MyThread: public Thread { Context* context; }; - Context(MyThread* t, void* ip, void* stack, void* base, - object continuation, CallTrace* trace): + Context(MyThread* t, void* ip, void* stack, object continuation, + CallTrace* trace): ip(ip), stack(stack), - base(base), continuation(continuation), trace(trace), protector(t, this) @@ -130,7 +142,6 @@ class MyThread: public Thread { void* ip; void* stack; - void* base; object continuation; CallTrace* trace; MyProtector protector; @@ -138,18 +149,22 @@ class MyThread: public Thread { class TraceContext: public Context { public: - TraceContext(MyThread* t, void* ip, void* stack, void* base, - object continuation, CallTrace* trace): - Context(t, ip, stack, base, continuation, trace), + TraceContext(MyThread* t, void* ip, void* stack, object continuation, + CallTrace* trace): + Context(t, ip, stack, continuation, trace), t(t), + link(0), + javaStackLimit(0), next(t->traceContext) { t->traceContext = this; } - TraceContext(MyThread* t): - Context(t, t->ip, t->stack, t->base, t->continuation, t->trace), + TraceContext(MyThread* t, void* link): + Context(t, t->ip, t->stack, t->continuation, t->trace), t(t), + link(link), + javaStackLimit(0), next(t->traceContext) { t->traceContext = this; @@ -160,20 +175,22 @@ class MyThread: public Thread { } MyThread* t; + void* link; + void* javaStackLimit; TraceContext* next; }; - static void doTransition(MyThread* t, void* ip, void* stack, void* base, + static void doTransition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { // in this function, we "atomically" update the thread context // fields in such a way to ensure that another thread may // interrupt us at any time and still get a consistent, accurate - // stack trace. See MyProcess::getStackTrace for details. + // stack trace. See MyProcessor::getStackTrace for details. assert(t, t->transition == 0); - Context c(t, ip, stack, base, continuation, trace); + Context c(t, ip, stack, continuation, trace); compileTimeMemoryBarrier(); @@ -182,7 +199,6 @@ class MyThread: public Thread { compileTimeMemoryBarrier(); t->ip = ip; - t->base = base; t->stack = stack; t->continuation = continuation; t->trace = trace; @@ -196,8 +212,8 @@ class MyThread: public Thread { bool useNativeFeatures): Thread(m, javaThread, parent), ip(0), - base(0), stack(0), + scratch(0), continuation(0), exceptionStackAdjustment(0), exceptionOffset(0), @@ -211,14 +227,15 @@ class MyThread: public Thread { ? parent->arch : makeArchitecture(m->system, useNativeFeatures)), transition(0), - traceContext(0) + traceContext(0), + stackLimit(0) { arch->acquire(); } void* ip; - void* base; void* stack; + void* scratch; object continuation; uintptr_t exceptionStackAdjustment; uintptr_t exceptionOffset; @@ -231,13 +248,14 @@ class MyThread: public Thread { Assembler::Architecture* arch; Context* transition; TraceContext* traceContext; + uintptr_t stackLimit; }; void -transition(MyThread* t, void* ip, void* stack, void* base, object continuation, +transition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { - MyThread::doTransition(t, ip, stack, base, continuation, trace); + MyThread::doTransition(t, ip, stack, continuation, trace); } unsigned @@ -259,10 +277,10 @@ object findMethod(Thread* t, object method, object instance) { if ((methodFlags(t, method) & ACC_STATIC) == 0) { - if (methodVirtual(t, method)) { - return findVirtualMethod(t, method, objectClass(t, instance)); - } else if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { + if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { return findInterfaceMethod(t, method, objectClass(t, instance)); + } else if (methodVirtual(t, method)) { + return findVirtualMethod(t, method, objectClass(t, instance)); } } return method; @@ -277,8 +295,7 @@ resolveTarget(MyThread* t, void* stack, object method) PROTECT(t, method); PROTECT(t, class_); - resolveSystemClass(t, className(t, class_)); - if (UNLIKELY(t->exception)) return 0; + resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); } if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { @@ -294,18 +311,17 @@ resolveTarget(MyThread* t, object class_, unsigned index) if (classVmFlags(t, class_) & BootstrapFlag) { PROTECT(t, class_); - resolveSystemClass(t, className(t, class_)); - if (UNLIKELY(t->exception)) return 0; + resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); } return arrayBody(t, classVirtualTable(t, class_), index); } object& -methodTree(MyThread* t); +root(Thread* t, Root root); -object -methodTreeSentinal(MyThread* t); +void +setRoot(Thread* t, Root root, object value); unsigned compiledSize(intptr_t address) @@ -313,6 +329,12 @@ compiledSize(intptr_t address) return reinterpret_cast(address)[-1]; } +intptr_t +methodCompiled(Thread* t, object method) +{ + return codeCompiled(t, methodCode(t, method)); +} + intptr_t compareIpToMethodBounds(Thread* t, intptr_t ip, object method) { @@ -348,8 +370,69 @@ methodForIp(MyThread* t, void* ip) // compile(MyThread*, Allocator*, BootContext*, object)): loadMemoryBarrier(); - return treeQuery(t, methodTree(t), reinterpret_cast(ip), - methodTreeSentinal(t), compareIpToMethodBounds); + return treeQuery(t, root(t, MethodTree), reinterpret_cast(ip), + root(t, MethodTreeSentinal), compareIpToMethodBounds); +} + +unsigned +localSize(MyThread* t, object method) +{ + unsigned size = codeMaxLocals(t, methodCode(t, method)); + if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) + == ACC_SYNCHRONIZED) + { + ++ size; + } + return size; +} + +unsigned +alignedFrameSize(MyThread* t, object method) +{ + return t->arch->alignFrameSize + (localSize(t, method) + - methodParameterFootprint(t, method) + + codeMaxStack(t, methodCode(t, method)) + + t->arch->frameFootprint(MaxNativeCallFootprint)); +} + +void +nextFrame(MyThread* t, void** ip, void** sp, object method, object target) +{ + object code = methodCode(t, method); + intptr_t start = codeCompiled(t, code); + void* link; + void* javaStackLimit; + + if (t->traceContext) { + link = t->traceContext->link; + javaStackLimit = t->traceContext->javaStackLimit; + } else { + link = 0; + javaStackLimit = 0; + } + + // fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s ip %p sp %p\n", + // &byteArrayBody(t, className(t, methodClass(t, method)), 0), + // &byteArrayBody(t, methodName(t, method), 0), + // &byteArrayBody(t, methodSpec(t, method), 0), + // target + // ? &byteArrayBody(t, className(t, methodClass(t, target)), 0) + // : 0, + // target + // ? &byteArrayBody(t, methodName(t, target), 0) + // : 0, + // target + // ? &byteArrayBody(t, methodSpec(t, target), 0) + // : 0, + // *ip, *sp); + + t->arch->nextFrame + (reinterpret_cast(start), compiledSize(start), + alignedFrameSize(t, method), link, javaStackLimit, + target ? methodParameterFootprint(t, target) : -1, ip, sp); + + // fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp); } class MyStackWalker: public Processor::StackWalker { @@ -372,6 +455,7 @@ class MyStackWalker: public Processor::StackWalker { virtual void visit(Heap::Visitor* v) { v->visit(&(walker->method_)); + v->visit(&(walker->target)); v->visit(&(walker->continuation)); } @@ -382,17 +466,16 @@ class MyStackWalker: public Processor::StackWalker { t(t), state(Start), method_(0), + target(0), protector(this) { if (t->traceContext) { ip_ = t->traceContext->ip; - base = t->traceContext->base; stack = t->traceContext->stack; trace = t->traceContext->trace; continuation = t->traceContext->continuation; } else { ip_ = 0; - base = t->base; stack = t->stack; trace = t->trace; continuation = t->continuation; @@ -403,10 +486,10 @@ class MyStackWalker: public Processor::StackWalker { t(w->t), state(w->state), ip_(w->ip_), - base(w->base), stack(w->stack), trace(w->trace), method_(w->method_), + target(w->target), continuation(w->continuation), protector(this) { } @@ -440,6 +523,7 @@ class MyStackWalker: public Processor::StackWalker { case Next: if (stack) { + target = method_; method_ = methodForIp(t, ip_); if (method_) { state = Method; @@ -458,7 +542,6 @@ class MyStackWalker: public Processor::StackWalker { if (trace) { continuation = trace->continuation; stack = trace->stack; - base = trace->base; ip_ = t->arch->frameIp(stack); trace = trace->next; @@ -489,8 +572,7 @@ class MyStackWalker: public Processor::StackWalker { break; case Method: - t->arch->nextFrame(&stack, &base); - ip_ = t->arch->frameIp(stack); + nextFrame(t, &ip_, &stack, method_, target); break; case NativeMethod: @@ -541,36 +623,14 @@ class MyStackWalker: public Processor::StackWalker { MyThread* t; State state; void* ip_; - void* base; void* stack; MyThread::CallTrace* trace; object method_; + object target; object continuation; MyProtector protector; }; -unsigned -localSize(MyThread* t, object method) -{ - unsigned size = codeMaxLocals(t, methodCode(t, method)); - if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) - == ACC_SYNCHRONIZED) - { - ++ size; - } - return size; -} - -unsigned -alignedFrameSize(MyThread* t, object method) -{ - return t->arch->alignFrameSize - (localSize(t, method) - - methodParameterFootprint(t, method) - + codeMaxStack(t, methodCode(t, method)) - + t->arch->frameFootprint(MaxNativeCallFootprint)); -} - int localOffset(MyThread* t, int v, object method) { @@ -888,6 +948,17 @@ class BootContext { class Context { public: + class MyResource: public Thread::Resource { + public: + MyResource(Context* c): Resource(c->thread), c(c) { } + + virtual void release() { + c->dispose(); + } + + Context* c; + }; + class MyProtector: public Thread::Protector { public: MyProtector(Context* c): Protector(c->thread), c(c) { } @@ -995,14 +1066,20 @@ class Context { } } - virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned) { + virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned, + bool* threadParameter) + { + *threadParameter = false; + if (size == 8) { switch (op) { case Divide: + *threadParameter = true; return local::getThunk(t, divideLongThunk); case Remainder: - return local::getThunk(t, moduloLongThunk); + *threadParameter = true; + return local::getThunk(t, moduloLongThunk); case FloatAdd: return local::getThunk(t, addDoubleThunk); @@ -1039,9 +1116,11 @@ class Context { assert(t, size == 4); switch (op) { case Divide: + *threadParameter = true; return local::getThunk(t, divideIntThunk); case Remainder: + *threadParameter = true; return local::getThunk(t, moduloIntThunk); case FloatAdd: @@ -1095,9 +1174,13 @@ class Context { visitTable(makeVisitTable(t, &zone, method)), rootTable(makeRootTable(t, &zone, method)), subroutineTable(0), + executableAllocator(0), + executableStart(0), + executableSize(0), objectPoolCount(0), traceLogCount(0), dirtyRoots(false), + leaf(true), eventLog(t->m->system, t->m->heap, 1024), protector(this) { } @@ -1116,16 +1199,31 @@ class Context { visitTable(0), rootTable(0), subroutineTable(0), + executableAllocator(0), + executableStart(0), + executableSize(0), objectPoolCount(0), traceLogCount(0), dirtyRoots(false), + leaf(true), eventLog(t->m->system, t->m->heap, 0), protector(this) { } ~Context() { - if (compiler) compiler->dispose(); + dispose(); + } + + void dispose() { + if (compiler) { + compiler->dispose(); + } + assembler->dispose(); + + if (executableAllocator) { + executableAllocator->free(executableStart, executableSize); + } } MyThread* thread; @@ -1141,9 +1239,13 @@ class Context { uint16_t* visitTable; uintptr_t* rootTable; Subroutine** subroutineTable; + Allocator* executableAllocator; + void* executableStart; + unsigned executableSize; unsigned objectPoolCount; unsigned traceLogCount; bool dirtyRoots; + bool leaf; Vector eventLog; MyProtector protector; }; @@ -1216,10 +1318,8 @@ class Frame { } ~Frame() { - if (t->exception == 0) { - if (level > 1) { - context->eventLog.append(PopContextEvent); - } + if (level > 1) { + context->eventLog.append(PopContextEvent); } } @@ -1869,22 +1969,19 @@ releaseLock(MyThread* t, object method, void* stack) } void -findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, +findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, void** targetStack, object* targetContinuation) { void* ip; - void* base; void* stack; object continuation; if (t->traceContext) { ip = t->traceContext->ip; - base = t->traceContext->base; stack = t->traceContext->stack; continuation = t->traceContext->continuation; } else { ip = 0; - base = t->base; stack = t->stack; continuation = t->continuation; } @@ -1903,13 +2000,14 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, if (handler) { *targetIp = handler; - *targetBase = base; - t->arch->nextFrame(&stack, &base); + nextFrame(t, &ip, &stack, method, target); void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); + *targetFrame = static_cast + (stack) + t->arch->framePointerOffset(); *targetStack = sp; *targetContinuation = continuation; @@ -1917,8 +2015,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->exception = 0; } else { - t->arch->nextFrame(&stack, &base); - ip = t->arch->frameIp(stack); + nextFrame(t, &ip, &stack, method, target); if (t->exception) { releaseLock(t, method, stack); @@ -1928,7 +2025,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, } } else { *targetIp = ip; - *targetBase = base; + *targetFrame = 0; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); *targetContinuation = continuation; @@ -1969,11 +2066,9 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, } object -makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, - void** targetStack) +makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) { void* ip = t->arch->frameIp(t->stack); - void* base = t->base; void* stack = t->stack; object context = t->continuation @@ -2006,7 +2101,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, top += argumentFootprint - alignment; } - t->arch->nextFrame(&stack, &base); + void* nextIp = ip; + nextFrame(t, &nextIp, &stack, method, target); void** bottom = static_cast(stack) + t->arch->frameReturnAddressSize(); @@ -2017,14 +2113,14 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, object c = makeContinuation (t, 0, context, method, ip, - ((frameSize - + t->arch->frameFooterSize() - + t->arch->returnAddressOffset() - - t->arch->frameReturnAddressSize()) * BytesPerWord), - ((frameSize - + t->arch->frameFooterSize() - + t->arch->framePointerOffset() - - t->arch->frameReturnAddressSize()) * BytesPerWord), + (frameSize + + t->arch->frameFooterSize() + + t->arch->returnAddressOffset() + - t->arch->frameReturnAddressSize()) * BytesPerWord, + (frameSize + + t->arch->frameFooterSize() + + t->arch->framePointerOffset() + - t->arch->frameReturnAddressSize()) * BytesPerWord, totalSize); memcpy(&continuationBody(t, c, 0), top, totalSize * BytesPerWord); @@ -2036,12 +2132,11 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, } last = c; - ip = t->arch->frameIp(stack); + ip = nextIp; target = method; } else { *targetIp = ip; - *targetBase = base; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); } @@ -2057,27 +2152,24 @@ void NO_RETURN unwind(MyThread* t) { void* ip; - void* base; + void* frame; void* stack; object continuation; - findUnwindTarget(t, &ip, &base, &stack, &continuation); + findUnwindTarget(t, &ip, &frame, &stack, &continuation); - transition(t, ip, stack, base, continuation, t->trace); + transition(t, ip, stack, continuation, t->trace); - vmJump(ip, base, stack, t, 0, 0); + vmJump(ip, frame, stack, t, 0, 0); } -object& -objectPools(MyThread* t); +class MyCheckpoint: public Thread::Checkpoint { + public: + MyCheckpoint(MyThread* t): Checkpoint(t) { } -object& -windMethod(MyThread* t); - -object& -rewindMethod(MyThread* t); - -object& -receiveMethod(MyThread* t); + virtual void unwind() { + local::unwind(static_cast(t)); + } +}; uintptr_t defaultThunk(MyThread* t); @@ -2091,6 +2183,9 @@ bootNativeThunk(MyThread* t); uintptr_t aioobThunk(MyThread* t); +uintptr_t +stackOverflowThunk(MyThread* t); + uintptr_t virtualThunk(MyThread* t, unsigned index); @@ -2111,7 +2206,6 @@ void tryInitClass(MyThread* t, object class_) { initClass(t, class_); - if (UNLIKELY(t->exception)) unwind(t); } FixedAllocator* @@ -2133,17 +2227,12 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) compile(t, codeAllocator(t), 0, target); } - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - if (methodFlags(t, target) & ACC_NATIVE) { - t->trace->nativeMethod = target; - } - return methodAddress(t, target); + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; } + return methodAddress(t, target); } else { - t->exception = makeNullPointerException(t); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2341,27 +2430,80 @@ absoluteInt(int32_t a) return a > 0 ? a : -a; } -int64_t -divideLong(int64_t b, int64_t a) +unsigned +traceSize(Thread* t) { - return a / b; + class Counter: public Processor::StackVisitor { + public: + Counter(): count(0) { } + + virtual bool visit(Processor::StackWalker*) { + ++ count; + return true; + } + + unsigned count; + } counter; + + t->m->processor->walkStack(t, &counter); + + return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray) + + (counter.count * FixedSizeOfTraceElement); +} + +void NO_RETURN +throwArithmetic(MyThread* t) +{ + if (ensure(t, FixedSizeOfArithmeticException + traceSize(t))) { + atomicOr(&(t->flags), Thread::TracingFlag); + THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); + + throwNew(t, Machine::ArithmeticExceptionType); + } else { + // not enough memory available for a new exception and stack trace + // -- use a preallocated instance instead + throw_(t, root(t, Machine::ArithmeticException)); + } } int64_t -divideInt(int32_t b, int32_t a) +divideLong(MyThread* t, int64_t b, int64_t a) { - return a / b; + if (LIKELY(b)) { + return a / b; + } else { + throwArithmetic(t); + } } int64_t -moduloLong(int64_t b, int64_t a) +divideInt(MyThread* t, int32_t b, int32_t a) { - return a % b; + if (LIKELY(b)) { + return a / b; + } else { + throwArithmetic(t); + } } int64_t -moduloInt(int32_t b, int32_t a) { - return a % b; +moduloLong(MyThread* t, int64_t b, int64_t a) +{ + if (LIKELY(b)) { + return a % b; + } else { + throwArithmetic(t); + } +} + +int64_t +moduloInt(MyThread* t, int32_t b, int32_t a) +{ + if (LIKELY(b)) { + return a % b; + } else { + throwArithmetic(t); + } } uint64_t @@ -2407,15 +2549,12 @@ longToFloat(int64_t a) } uint64_t -makeBlankObjectArray(MyThread* t, object loader, object class_, int32_t length) +makeBlankObjectArray(MyThread* t, object class_, int32_t length) { if (length >= 0) { - return reinterpret_cast - (makeObjectArray(t, loader, class_, length)); + return reinterpret_cast(makeObjectArray(t, class_, length)); } else { - object message = makeString(t, "%d", length); - t->exception = makeNegativeArraySizeException(t, message); - unwind(t); + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", length); } } @@ -2462,9 +2601,7 @@ makeBlankArray(MyThread* t, unsigned type, int32_t length) return reinterpret_cast(constructor(t, length)); } else { - object message = makeString(t, "%d", length); - t->exception = makeNegativeArraySizeException(t, message); - unwind(t); + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", length); } } @@ -2497,8 +2634,7 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value) if (LIKELY(o)) { set(t, o, offset, value); } else { - t->exception = makeNullPointerException(t); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2508,8 +2644,7 @@ acquireMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { acquire(t, o); } else { - t->exception = makeNullPointerException(t); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2519,8 +2654,7 @@ releaseMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { release(t, o); } else { - t->exception = makeNullPointerException(t); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2530,12 +2664,12 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, { PROTECT(t, class_); - RUNTIME_ARRAY(int32_t, counts, dimensions); + THREAD_RUNTIME_ARRAY(t, int32_t, counts, dimensions); for (int i = dimensions - 1; i >= 0; --i) { RUNTIME_ARRAY_BODY(counts)[i] = countStack[dimensions - i - 1]; if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { - object message = makeString(t, "%d", RUNTIME_ARRAY_BODY(counts)[i]); - t->exception = makeNegativeArraySizeException(t, message); + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", + RUNTIME_ARRAY_BODY(counts)[i]); return 0; } } @@ -2553,77 +2687,50 @@ uint64_t makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, int32_t offset) { - object r = makeMultidimensionalArray2 - (t, class_, static_cast(t->stack) + offset, dimensions); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } -} - -unsigned -traceSize(Thread* t) -{ - class Counter: public Processor::StackVisitor { - public: - Counter(): count(0) { } - - virtual bool visit(Processor::StackWalker*) { - ++ count; - return true; - } - - unsigned count; - } counter; - - t->m->processor->walkStack(t, &counter); - - return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray) - + (counter.count * FixedSizeOfTraceElement); + return reinterpret_cast + (makeMultidimensionalArray2 + (t, class_, static_cast(t->stack) + offset, dimensions)); } void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { - if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { - t->tracing = true; - t->exception = makeArrayIndexOutOfBoundsException(t, 0); - t->tracing = false; + if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { + atomicOr(&(t->flags), Thread::TracingFlag); + THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); + + throwNew(t, Machine::ArrayIndexOutOfBoundsExceptionType); } else { // not enough memory available for a new exception and stack trace // -- use a preallocated instance instead - t->exception = t->m->arrayIndexOutOfBoundsException; + throw_(t, root(t, Machine::ArrayIndexOutOfBoundsException)); } +} - unwind(t); +void NO_RETURN +throwStackOverflow(MyThread* t) +{ + throwNew(t, Machine::StackOverflowErrorType); } void NO_RETURN throw_(MyThread* t, object o) { if (LIKELY(o)) { - t->exception = o; + vm::throw_(t, o); } else { - t->exception = makeNullPointerException(t); + throwNew(t, Machine::NullPointerExceptionType); } - -// printTrace(t, t->exception); - - unwind(t); } void checkCast(MyThread* t, object class_, object o) { if (UNLIKELY(o and not isAssignableFrom(t, class_, objectClass(t, o)))) { - object message = makeString - (t, "%s as %s", + throwNew + (t, Machine::ClassCastExceptionType, "%s as %s", &byteArrayBody(t, className(t, objectClass(t, o)), 0), &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeClassCastException(t, message); - unwind(t); } } @@ -2645,10 +2752,18 @@ makeNew64(Thread* t, object class_) return reinterpret_cast(makeNew(t, class_)); } +uint64_t +getJClass64(Thread* t, object class_) +{ + return reinterpret_cast(getJClass(t, class_)); +} + void gcIfNecessary(MyThread* t) { - if (UNLIKELY(t->useBackupHeap)) { + stress(t); + + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } } @@ -2881,6 +2996,8 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) if (methodFlags(t, method) & ACC_SYNCHRONIZED) { Compiler::Operand* lock; if (methodFlags(t, method) & ACC_STATIC) { + PROTECT(t, method); + lock = frame->append(methodClass(t, method)); } else { lock = loadLocal(frame->context, 1, savedTargetIndex(t, method)); @@ -3049,7 +3166,7 @@ integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip, } saveStateAndCompile(t, frame, newIp); - return t->exception == 0; + return true; } bool @@ -3116,7 +3233,7 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, } saveStateAndCompile(t, frame, newIp); - return t->exception == 0; + return true; } bool @@ -3155,7 +3272,7 @@ void compile(MyThread* t, Frame* initialFrame, unsigned ip, int exceptionHandlerStart) { - RUNTIME_ARRAY(uint8_t, stackMap, + THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, initialFrame->context->method))); Frame myFrame(initialFrame, RUNTIME_ARRAY_BODY(stackMap)); Frame* frame = &myFrame; @@ -3208,6 +3325,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); + frame->trace(0, 0); } if (CheckArrayBounds) { @@ -3300,6 +3418,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); + frame->trace(0, 0); } if (CheckArrayBounds) { @@ -3389,7 +3508,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; Compiler::Operand* length = frame->popInt(); @@ -3401,9 +3519,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, frame->trace(0, 0), BytesPerWord, Compiler::ObjectType, - 4, c->register_(t->arch->thread()), - frame->append(classLoader(t, methodClass(t, context->method))), - frame->append(class_), length)); + 3, c->register_(t->arch->thread()), frame->append(class_), length)); } break; case areturn: { @@ -3462,7 +3578,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; Compiler::Operand* instance = c->peek(1, 0); @@ -3499,8 +3614,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popLong(); if (not floatBranch(t, frame, code, ip, 8, false, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3516,8 +3629,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popLong(); if (not floatBranch(t, frame, code, ip, 8, true, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3616,8 +3727,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popInt(); if (not floatBranch(t, frame, code, ip, 4, false, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3631,8 +3740,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popInt(); if (not floatBranch(t, frame, code, ip, 4, true, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3690,13 +3797,14 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; if ((fieldFlags(t, field) & ACC_VOLATILE) and BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), @@ -3710,6 +3818,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (instruction == getstatic) { assert(t, fieldFlags(t, field) & ACC_STATIC); + PROTECT(t, field); + if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { @@ -3732,6 +3842,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); + frame->trace(0, 0); } } @@ -3907,6 +4018,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case idiv: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushInt(c->div(4, a, b)); } break; @@ -3927,7 +4044,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case if_icmpeq: @@ -3968,7 +4084,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case ifeq: @@ -4010,7 +4125,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case ifnull: @@ -4030,7 +4144,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case iinc: { @@ -4084,7 +4197,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; frame->pushInt (c->call @@ -4095,11 +4207,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokeinterface: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); ip += 2; object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); @@ -4107,7 +4220,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned instance = parameterFootprint - 1; - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + int returnCode = methodReturnCode(t, target); + + unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = c->stackCall (c->call @@ -4123,20 +4238,21 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), + operandTypeForFieldCode(t, returnCode), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + pushReturnValue(t, frame, returnCode, result); } } break; case invokespecial: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; object class_ = methodClass(t, context->method); if (isSpecialMethod(t, target, class_)) { @@ -4151,10 +4267,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokestatic: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; assert(t, methodFlags(t, target) & ACC_STATIC); @@ -4165,10 +4282,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokevirtual: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); @@ -4210,6 +4328,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case irem: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushInt(c->rem(4, a, b)); } break; @@ -4296,7 +4420,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->jmp(frame->machineIp(newIp)); saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; frame->endSubroutine(start); } break; @@ -4330,8 +4453,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popLong(); if (not integerBranch(t, frame, code, ip, 8, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -4364,13 +4485,20 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); - if (objectClass(t, v) - == arrayBody(t, t->m->types, Machine::ReferenceType)) - { - object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; + if (objectClass(t, v) == type(t, Machine::ReferenceType)) { + v = resolveClassInPool(t, context->method, index - 1); + } - frame->pushObject(frame->append(class_)); + if (objectClass(t, v) == type(t, Machine::ClassType)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClass64Thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), frame->append(v))); } else { frame->pushObject(frame->append(v)); } @@ -4399,6 +4527,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case ldiv_: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushLong(c->div(8, a, b)); } break; @@ -4454,7 +4588,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (pairCount) { Compiler::Operand* start = 0; - RUNTIME_ARRAY(uint32_t, ipTable, pairCount); + THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, pairCount); for (int32_t i = 0; i < pairCount; ++i) { unsigned index = ip + (i * 8); int32_t key = codeReadInt32(t, code, index); @@ -4483,7 +4617,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, for (int32_t i = 0; i < pairCount; ++i) { compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]); - if (UNLIKELY(t->exception)) return; c->restoreState(state); } @@ -4504,6 +4637,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case lrem: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushLong(c->rem(8, a, b)); } break; @@ -4591,7 +4730,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint8_t dimensions = codeBody(t, code, ip++); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; PROTECT(t, class_); unsigned offset @@ -4618,7 +4756,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { frame->pushObject @@ -4673,7 +4810,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; object staticTable = 0; @@ -4683,6 +4819,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, tryInitClassThunk), Compiler::AddressType), @@ -4700,6 +4838,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); + frame->trace(0, 0); } } @@ -4708,6 +4847,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), @@ -4745,6 +4886,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* table; if (instruction == putstatic) { + PROTECT(t, field); + table = frame->append(staticTable); } else { table = frame->popObject(); @@ -4866,7 +5009,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, int32_t top = codeReadInt32(t, code, ip); Compiler::Operand* start = 0; - RUNTIME_ARRAY(uint32_t, ipTable, top - bottom + 1); + THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, top - bottom + 1); for (int32_t i = 0; i < top - bottom + 1; ++i) { unsigned index = ip + (i * 4); uint32_t newIp = base + codeReadInt32(t, code, index); @@ -4912,7 +5055,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, for (int32_t i = 0; i < top - bottom + 1; ++i) { compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]); - if (UNLIKELY(t->exception)) return; c->restoreState(state); } @@ -4932,7 +5074,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case iinc: { uint16_t index = codeReadInt16(t, code, ip); - uint16_t count = codeReadInt16(t, code, ip); + int16_t count = codeReadInt16(t, code, ip); storeLocal (context, 1, @@ -4997,7 +5139,7 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } } -void +object translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, intptr_t start) { @@ -5034,7 +5176,6 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool (t, method, exceptionHandlerCatchType(oldHandler) - 1); - if (UNLIKELY(t->exception)) return; } else { type = 0; } @@ -5042,11 +5183,13 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type); } - set(t, methodCode(t, method), CodeExceptionHandlerTable, newTable); + return newTable; + } else { + return 0; } } -void +object translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) { object oldTable = codeLineNumberTable(t, code); @@ -5066,7 +5209,9 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) lineNumberLine(newLine) = lineNumberLine(oldLine); } - set(t, code, CodeLineNumberTable, newTable); + return newTable; + } else { + return 0; } } @@ -5143,7 +5288,8 @@ calculateTryCatchRoots(Context* context, SubroutinePath* subroutinePath, unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, - unsigned eventIndex, SubroutinePath* subroutinePath = 0) + unsigned eventIndex, SubroutinePath* subroutinePath = 0, + uintptr_t* resultRoots = 0) { // for each instruction with more than one predecessor, and for each // stack position, determine if there exists a path to that @@ -5153,7 +5299,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned mapSize = frameMapSizeInWords(t, context->method); - RUNTIME_ARRAY(uintptr_t, roots, mapSize); + THREAD_RUNTIME_ARRAY(t, uintptr_t, roots, mapSize); if (originalRoots) { memcpy(RUNTIME_ARRAY_BODY(roots), originalRoots, mapSize * BytesPerWord); } else { @@ -5176,11 +5322,12 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, switch (e) { case PushContextEvent: { eventIndex = calculateFrameMaps - (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath); + (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath, + resultRoots); } break; case PopContextEvent: - return eventIndex; + goto exit; case IpEvent: { ip = context->eventLog.get2(eventIndex); @@ -5346,18 +5493,41 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, makeRootTable(t, &(context->zone), context->method)); } + THREAD_RUNTIME_ARRAY(t, uintptr_t, subroutineRoots, mapSize); + calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), call->subroutine->logIndex, - path); + path, RUNTIME_ARRAY_BODY(subroutineRoots)); + + for (unsigned wi = 0; wi < mapSize; ++wi) { + RUNTIME_ARRAY_BODY(roots)[wi] + &= RUNTIME_ARRAY_BODY(subroutineRoots)[wi]; + } } break; case PopSubroutineEvent: - return static_cast(-1); + eventIndex = static_cast(-1); + goto exit; default: abort(t); } } + exit: + if (resultRoots and ip != -1) { + if (DebugFrameMaps) { + fprintf(stderr, "result roots at ip %3d: ", ip); + printSet(*RUNTIME_ARRAY_BODY(roots), mapSize); + if (subroutinePath) { + fprintf(stderr, " "); + print(subroutinePath); + } + fprintf(stderr, "\n"); + } + + memcpy(resultRoots, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord); + } + return eventIndex; } @@ -5391,14 +5561,14 @@ codeSingletonSizeInBytes(MyThread*, unsigned codeSizeInBytes) } uint8_t* -finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name) +finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name, + unsigned length) { - uint8_t* start = static_cast - (allocator->allocate(pad(a->length()))); + uint8_t* start = static_cast(allocator->allocate(pad(length))); a->writeTo(start); - logCompile(t, start, a->length(), 0, name, 0); + logCompile(t, start, length, 0, name, 0); return start; } @@ -5518,23 +5688,23 @@ compareSubroutineTracePointers(const void* va, const void* vb) object makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, - TraceElement** elements, unsigned pathFootprint, - unsigned mapCount) + TraceElement** elements, unsigned elementCount, + unsigned pathFootprint, unsigned mapCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); unsigned indexOffset = sizeof(FrameMapTableHeader); unsigned mapsOffset = indexOffset - + (context->traceLogCount * sizeof(FrameMapTableIndexElement)); + + (elementCount * sizeof(FrameMapTableIndexElement)); unsigned pathsOffset = mapsOffset + (ceiling(mapCount * mapSize, 32) * 4); object table = makeByteArray(t, pathsOffset + pathFootprint); int8_t* body = &byteArrayBody(t, table, 0); - new (body) FrameMapTableHeader(context->traceLogCount); + new (body) FrameMapTableHeader(elementCount); unsigned nextTableIndex = pathsOffset; unsigned nextMapIndex = 0; - for (unsigned i = 0; i < context->traceLogCount; ++i) { + for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; unsigned mapBase = nextMapIndex; @@ -5584,7 +5754,7 @@ makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, pathIndex = subroutine->tableIndex; - RUNTIME_ARRAY(SubroutineTrace*, traces, p->subroutineTraceCount); + THREAD_RUNTIME_ARRAY(t, SubroutineTrace*, traces, p->subroutineTraceCount); unsigned i = 0; for (SubroutineTrace* trace = p->subroutineTrace; trace; trace = trace->next) @@ -5636,27 +5806,26 @@ makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, object makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, - TraceElement** elements) + TraceElement** elements, unsigned elementCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); object table = makeIntArray - (t, context->traceLogCount - + ceiling(context->traceLogCount * mapSize, 32)); + (t, elementCount + ceiling(elementCount * mapSize, 32)); - assert(t, intArrayLength(t, table) == context->traceLogCount + assert(t, intArrayLength(t, table) == elementCount + simpleFrameMapTableSize(t, context->method, table)); - for (unsigned i = 0; i < context->traceLogCount; ++i) { + for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; intArrayBody(t, table, i) = static_cast(p->address->value()) - reinterpret_cast(start); - assert(t, context->traceLogCount + ceiling((i + 1) * mapSize, 32) + assert(t, elementCount + ceiling((i + 1) * mapSize, 32) <= intArrayLength(t, table)); if (mapSize) { - copyFrameMap(&intArrayBody(t, table, context->traceLogCount), p->map, + copyFrameMap(&intArrayBody(t, table, elementCount), p->map, mapSize, i * mapSize, p, 0); } } @@ -5664,7 +5833,7 @@ makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, return table; } -uint8_t* +void finish(MyThread* t, Allocator* allocator, Context* context) { Compiler* c = context->compiler; @@ -5694,12 +5863,25 @@ finish(MyThread* t, Allocator* allocator, Context* context) trap(); } - unsigned codeSize = c->compile(); - uintptr_t* code = static_cast - (allocator->allocate(pad(codeSize) + pad(c->poolSize()) + BytesPerWord)); + // todo: this is a CPU-intensive operation, so consider doing it + // earlier before we've acquired the global class lock to improve + // parallelism (the downside being that it may end up being a waste + // of cycles if another thread compiles the same method in parallel, + // which might be mitigated by fine-grained, per-method locking): + unsigned codeSize = c->compile + (context->leaf ? 0 : stackOverflowThunk(t), + difference(&(t->stackLimit), t)); + + unsigned total = pad(codeSize) + pad(c->poolSize()) + BytesPerWord; + + uintptr_t* code = static_cast(allocator->allocate(total)); code[0] = codeSize; uint8_t* start = reinterpret_cast(code + 1); + context->executableAllocator = allocator; + context->executableStart = code; + context->executableSize = total; + if (context->objectPool) { object pool = allocate3 (t, allocator, Machine::ImmortalAllocation, @@ -5709,8 +5891,8 @@ finish(MyThread* t, Allocator* allocator, Context* context) initArray(t, pool, context->objectPoolCount + 1); mark(t, pool, 0); - set(t, pool, ArrayBody, objectPools(t)); - objectPools(t) = pool; + set(t, pool, ArrayBody, root(t, ObjectPools)); + setRoot(t, ObjectPools, pool); unsigned i = 1; for (PoolElement* p = context->objectPool; p; p = p->next) { @@ -5735,71 +5917,73 @@ finish(MyThread* t, Allocator* allocator, Context* context) } } - translateExceptionHandlerTable - (t, c, context->method, reinterpret_cast(start)); - if (UNLIKELY(t->exception)) return 0; + { object newExceptionHandlerTable = translateExceptionHandlerTable + (t, c, context->method, reinterpret_cast(start)); - translateLineNumberTable(t, c, methodCode(t, context->method), - reinterpret_cast(start)); + PROTECT(t, newExceptionHandlerTable); - { object code = methodCode(t, context->method); + object newLineNumberTable = translateLineNumberTable + (t, c, methodCode(t, context->method), + reinterpret_cast(start)); - code = makeCode(t, 0, - codeExceptionHandlerTable(t, code), - codeLineNumberTable(t, code), - codeMaxStack(t, code), - codeMaxLocals(t, code), - 0); + object code = methodCode(t, context->method); + + code = makeCode + (t, 0, newExceptionHandlerTable, newLineNumberTable, + reinterpret_cast(start), codeMaxStack(t, code), + codeMaxLocals(t, code), 0); set(t, context->method, MethodCode, code); } if (context->traceLogCount) { - RUNTIME_ARRAY(TraceElement*, elements, context->traceLogCount); + THREAD_RUNTIME_ARRAY(t, TraceElement*, elements, context->traceLogCount); unsigned index = 0; unsigned pathFootprint = 0; unsigned mapCount = 0; for (TraceElement* p = context->traceLog; p; p = p->next) { assert(t, index < context->traceLogCount); - SubroutineTrace* trace = p->subroutineTrace; - unsigned myMapCount = 1; - if (trace) { - for (Subroutine* s = trace->path->call->subroutine; - s; s = s->stackNext) - { - unsigned callCount = s->callCount; - myMapCount *= callCount; - if (not s->visited) { - s->visited = true; - pathFootprint += sizeof(FrameMapTablePath) - + (sizeof(int32_t) * callCount); + if (p->address) { + SubroutineTrace* trace = p->subroutineTrace; + unsigned myMapCount = 1; + if (trace) { + for (Subroutine* s = trace->path->call->subroutine; + s; s = s->stackNext) + { + unsigned callCount = s->callCount; + myMapCount *= callCount; + if (not s->visited) { + s->visited = true; + pathFootprint += sizeof(FrameMapTablePath) + + (sizeof(int32_t) * callCount); + } } } - } - mapCount += myMapCount; + mapCount += myMapCount; - RUNTIME_ARRAY_BODY(elements)[index++] = p; + RUNTIME_ARRAY_BODY(elements)[index++] = p; - if (p->target) { - insertCallNode - (t, makeCallNode - (t, p->address->value(), p->target, p->flags, 0)); + if (p->target) { + insertCallNode + (t, makeCallNode + (t, p->address->value(), p->target, p->flags, 0)); + } } } - qsort(RUNTIME_ARRAY_BODY(elements), context->traceLogCount, + qsort(RUNTIME_ARRAY_BODY(elements), index, sizeof(TraceElement*), compareTraceElementPointers); object map; if (pathFootprint) { map = makeGeneralFrameMapTable - (t, context, start, RUNTIME_ARRAY_BODY(elements), pathFootprint, + (t, context, start, RUNTIME_ARRAY_BODY(elements), index, pathFootprint, mapCount); } else { map = makeSimpleFrameMapTable - (t, context, start, RUNTIME_ARRAY_BODY(elements)); + (t, context, start, RUNTIME_ARRAY_BODY(elements), index); } set(t, methodCode(t, context->method), CodePool, map); @@ -5829,12 +6013,10 @@ finish(MyThread* t, Allocator* allocator, Context* context) } syncInstructionCache(start, codeSize); - - return start; } -uint8_t* -compile(MyThread* t, Allocator* allocator, Context* context) +void +compile(MyThread* t, Context* context) { Compiler* c = context->compiler; @@ -5848,7 +6030,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) c->init(codeLength(t, methodCode(t, context->method)), footprint, locals, alignedFrameSize(t, context->method)); - RUNTIME_ARRAY(uint8_t, stackMap, + THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); Frame frame(context, RUNTIME_ARRAY_BODY(stackMap)); @@ -5899,7 +6081,6 @@ compile(MyThread* t, Allocator* allocator, Context* context) Compiler::State* state = c->saveState(); compile(t, &frame, 0); - if (UNLIKELY(t->exception)) return 0; context->dirtyRoots = false; unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); @@ -5910,7 +6091,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) unsigned visitCount = exceptionHandlerTableLength(t, eht); - RUNTIME_ARRAY(bool, visited, visitCount); + THREAD_RUNTIME_ARRAY(t, bool, visited, visitCount); memset(RUNTIME_ARRAY_BODY(visited), 0, visitCount * sizeof(bool)); while (visitCount) { @@ -5929,7 +6110,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) RUNTIME_ARRAY_BODY(visited)[i] = true; progress = true; - RUNTIME_ARRAY(uint8_t, stackMap, + THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); @@ -5952,7 +6133,6 @@ compile(MyThread* t, Allocator* allocator, Context* context) } compile(t, &frame2, exceptionHandlerIp(eh), start); - if (UNLIKELY(t->exception)) return 0; context->eventLog.append(PopContextEvent); @@ -5968,8 +6148,6 @@ compile(MyThread* t, Allocator* allocator, Context* context) context->dirtyRoots = false; calculateFrameMaps(t, context, 0, 0); } - - return finish(t, allocator, context); } void @@ -5984,55 +6162,41 @@ compileMethod2(MyThread* t, void* ip) object node = findCallNode(t, ip); object target = callNodeTarget(t, node); - if (LIKELY(t->exception == 0)) { - PROTECT(t, node); - PROTECT(t, target); + PROTECT(t, node); + PROTECT(t, target); - t->trace->targetMethod = target; + t->trace->targetMethod = target; - compile(t, codeAllocator(t), 0, target); + THREAD_RESOURCE0(t, static_cast(t)->trace->targetMethod = 0); - t->trace->targetMethod = 0; - } + compile(t, codeAllocator(t), 0, target); - if (false) { - compile(t, codeAllocator(t), 0, resolveMethod - (t, t->m->loader, - "org/eclipse/swt/widgets/TableItem", - "getBounds", - "(IIZZZZJ)Lorg/eclipse/swt/internal/win32/RECT;")); - } - - if (UNLIKELY(t->exception)) { - return 0; + uintptr_t address; + if ((methodFlags(t, target) & ACC_NATIVE) + and useLongJump(t, reinterpret_cast(ip))) + { + address = bootNativeThunk(t); } else { - uintptr_t address; - if ((methodFlags(t, target) & ACC_NATIVE) - and useLongJump(t, reinterpret_cast(ip))) - { - address = bootNativeThunk(t); - } else { - address = methodAddress(t, target); - } - uint8_t* updateIp = static_cast(ip); - - UnaryOperation op; - if (callNodeFlags(t, node) & TraceElement::LongCall) { - if (callNodeFlags(t, node) & TraceElement::TailCall) { - op = AlignedLongJump; - } else { - op = AlignedLongCall; - } - } else if (callNodeFlags(t, node) & TraceElement::TailCall) { - op = AlignedJump; - } else { - op = AlignedCall; - } - - updateCall(t, op, updateIp, reinterpret_cast(address)); - - return reinterpret_cast(address); + address = methodAddress(t, target); } + uint8_t* updateIp = static_cast(ip); + + UnaryOperation op; + if (callNodeFlags(t, node) & TraceElement::LongCall) { + if (callNodeFlags(t, node) & TraceElement::TailCall) { + op = AlignedLongJump; + } else { + op = AlignedLongCall; + } + } else if (callNodeFlags(t, node) & TraceElement::TailCall) { + op = AlignedJump; + } else { + op = AlignedCall; + } + + updateCall(t, op, updateIp, reinterpret_cast(address)); + + return reinterpret_cast(address); } uint64_t @@ -6046,13 +6210,7 @@ compileMethod(MyThread* t) ip = t->arch->frameIp(t->stack); } - void* r = compileMethod2(t, ip); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } + return reinterpret_cast(compileMethod2(t, ip)); } void* @@ -6070,28 +6228,22 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) } t->trace->targetMethod = arrayBody(t, classVirtualTable(t, c), index); + THREAD_RESOURCE0(t, static_cast(t)->trace->targetMethod = 0;); + PROTECT(t, class_); object target = resolveTarget(t, class_, index); PROTECT(t, target); - if (LIKELY(t->exception == 0)) { - compile(t, codeAllocator(t), 0, target); - } + compile(t, codeAllocator(t), 0, target); - t->trace->targetMethod = 0; - - if (UNLIKELY(t->exception)) { - return 0; + void* address = reinterpret_cast(methodAddress(t, target)); + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; } else { - void* address = reinterpret_cast(methodAddress(t, target)); - if (methodFlags(t, target) & ACC_NATIVE) { - t->trace->nativeMethod = target; - } else { - classVtable(t, class_, methodOffset(t, target)) = address; - } - return address; + classVtable(t, class_, methodOffset(t, target)) = address; } + return address; } uint64_t @@ -6103,75 +6255,33 @@ compileVirtualMethod(MyThread* t) unsigned index = t->virtualCallIndex; t->virtualCallIndex = 0; - void* r = compileVirtualMethod2(t, class_, index); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } -} - -void -resolveNative(MyThread* t, object method) -{ - PROTECT(t, method); - - assert(t, methodFlags(t, method) & ACC_NATIVE); - - initClass(t, methodClass(t, method)); - - if (LIKELY(t->exception == 0) - and unresolved(t, methodCompiled(t, method))) - { - void* function = resolveNativeMethod(t, method); - if (UNLIKELY(function == 0)) { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = makeUnsatisfiedLinkError(t, message); - return; - } - - // ensure other threads see updated methodVmFlags before - // methodCompiled, since we don't want them using the slow calling - // convention on a function that expects the fast calling - // convention: - storeStoreMemoryBarrier(); - - methodCompiled(t, method) = reinterpret_cast(function); - } + return reinterpret_cast(compileVirtualMethod2(t, class_, index)); } uint64_t -invokeNativeFast(MyThread* t, object method) +invokeNativeFast(MyThread* t, object method, void* function) { - return reinterpret_cast(methodCompiled(t, method)) - (t, method, - static_cast(t->stack) - + t->arch->frameFooterSize() - + t->arch->frameReturnAddressSize()); + FastNativeFunction f; memcpy(&f, &function, sizeof(void*)); + return f(t, method, + static_cast(t->stack) + + t->arch->frameFooterSize() + + t->arch->frameReturnAddressSize()); } uint64_t -invokeNativeSlow(MyThread* t, object method) +invokeNativeSlow(MyThread* t, object method, void* function) { PROTECT(t, method); - object class_ = methodClass(t, method); - PROTECT(t, class_); - unsigned footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { ++ footprint; } unsigned count = methodParameterCount(t, method) + 2; - RUNTIME_ARRAY(uintptr_t, args, footprint); + THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned argOffset = 0; - RUNTIME_ARRAY(uint8_t, types, count); + THREAD_RUNTIME_ARRAY(t, uint8_t, types, count); unsigned typeOffset = 0; RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); @@ -6181,9 +6291,13 @@ invokeNativeSlow(MyThread* t, object method) + t->arch->frameFooterSize() + t->arch->frameReturnAddressSize(); + object jclass = 0; + PROTECT(t, jclass); + if (methodFlags(t, method) & ACC_STATIC) { + jclass = getJClass(t, methodClass(t, method)); RUNTIME_ARRAY_BODY(args)[argOffset++] - = reinterpret_cast(&class_); + = reinterpret_cast(&jclass); } else { RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(sp++); @@ -6227,7 +6341,6 @@ invokeNativeSlow(MyThread* t, object method) } } - void* function = reinterpret_cast(methodCompiled(t, method)); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); uint64_t result; @@ -6242,7 +6355,7 @@ invokeNativeSlow(MyThread* t, object method) if (methodFlags(t, method) & ACC_STATIC) { acquire(t, methodClass(t, method)); } else { - acquire(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[0])); + acquire(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[1])); } } @@ -6250,6 +6363,10 @@ invokeNativeSlow(MyThread* t, object method) { ENTER(t, Thread::IdleState); + bool noThrow = t->checkpoint->noThrow; + t->checkpoint->noThrow = true; + THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow); + result = t->m->system->call (function, RUNTIME_ARRAY_BODY(args), @@ -6263,7 +6380,7 @@ invokeNativeSlow(MyThread* t, object method) if (methodFlags(t, method) & ACC_STATIC) { release(t, methodClass(t, method)); } else { - release(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[0])); + release(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[1])); } } @@ -6273,43 +6390,45 @@ invokeNativeSlow(MyThread* t, object method) &byteArrayBody(t, methodName(t, method), 0)); } - if (LIKELY(t->exception == 0)) { - switch (returnCode) { - case ByteField: - case BooleanField: - result = static_cast(result); - break; + if (UNLIKELY(t->exception)) { + object exception = t->exception; + t->exception = 0; + vm::throw_(t, exception); + } - case CharField: - result = static_cast(result); - break; + switch (returnCode) { + case ByteField: + case BooleanField: + result = static_cast(result); + break; - case ShortField: - result = static_cast(result); - break; + case CharField: + result = static_cast(result); + break; - case FloatField: - case IntField: - result = static_cast(result); - break; + case ShortField: + result = static_cast(result); + break; - case LongField: - case DoubleField: - break; + case FloatField: + case IntField: + result = static_cast(result); + break; - case ObjectField: - result = static_cast(result) ? *reinterpret_cast - (static_cast(result)) : 0; - break; + case LongField: + case DoubleField: + break; - case VoidField: - result = 0; - break; + case ObjectField: + result = static_cast(result) ? *reinterpret_cast + (static_cast(result)) : 0; + break; - default: abort(t); - } - } else { + case VoidField: result = 0; + break; + + default: abort(t); } while (t->reference != reference) { @@ -6322,10 +6441,11 @@ invokeNativeSlow(MyThread* t, object method) uint64_t invokeNative2(MyThread* t, object method) { - if (methodVmFlags(t, method) & FastNative) { - return invokeNativeFast(t, method); + object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); + if (nativeFast(t, native)) { + return invokeNativeFast(t, method, nativeFunction(t, native)); } else { - return invokeNativeSlow(t, method); + return invokeNativeSlow(t, method, nativeFunction(t, native)); } } @@ -6354,41 +6474,34 @@ invokeNative(MyThread* t) uint64_t result = 0; t->trace->targetMethod = t->trace->nativeMethod; + + THREAD_RESOURCE0(t, { + static_cast(t)->trace->targetMethod = 0; + static_cast(t)->trace->nativeMethod = 0; + }); - if (LIKELY(t->exception == 0)) { - resolveNative(t, t->trace->nativeMethod); + resolveNative(t, t->trace->nativeMethod); - if (LIKELY(t->exception == 0)) { - result = invokeNative2(t, t->trace->nativeMethod); - } - } + result = invokeNative2(t, t->trace->nativeMethod); unsigned parameterFootprint = methodParameterFootprint (t, t->trace->targetMethod); - t->trace->targetMethod = 0; - t->trace->nativeMethod = 0; + uintptr_t* stack = static_cast(t->stack); - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - uintptr_t* stack = static_cast(t->stack); - - if (TailCalls - and t->arch->argumentFootprint(parameterFootprint) - > t->arch->stackAlignmentInWords()) - { - stack += t->arch->argumentFootprint(parameterFootprint) - - t->arch->stackAlignmentInWords(); - } - - stack += t->arch->frameReturnAddressSize(); - - transition(t, t->arch->frameIp(t->stack), stack, t->base, t->continuation, - t->trace); - - return result; + if (TailCalls + and t->arch->argumentFootprint(parameterFootprint) + > t->arch->stackAlignmentInWords()) + { + stack += t->arch->argumentFootprint(parameterFootprint) + - t->arch->stackAlignmentInWords(); } + + stack += t->arch->frameReturnAddressSize(); + + transition(t, t->arch->frameIp(t->stack), stack, t->continuation, t->trace); + + return result; } void @@ -6481,9 +6594,7 @@ findFrameMap(MyThread* t, void* stack, object method, int32_t offset, int32_t** map, unsigned* start) { object table = codePool(t, methodCode(t, method)); - if (objectClass(t, table) - == arrayBody(t, t->m->types, Machine::IntArrayType)) - { + if (objectClass(t, table) == type(t, Machine::IntArrayType)) { findFrameMapInSimpleTable(t, method, table, offset, map, start); } else { findFrameMapInGeneralTable(t, stack, method, table, offset, map, start); @@ -6559,11 +6670,11 @@ void visitStack(MyThread* t, Heap::Visitor* v) { void* ip = t->arch->frameIp(t->stack); - void* base = t->base; void* stack = t->stack; MyThread::CallTrace* trace = t->trace; object targetMethod = (trace ? trace->targetMethod : 0); + object target = targetMethod; while (stack) { if (targetMethod) { @@ -6575,19 +6686,24 @@ visitStack(MyThread* t, Heap::Visitor* v) if (method) { PROTECT(t, method); - t->arch->nextFrame(&stack, &base); + void* nextIp = ip; + nextFrame(t, &nextIp, &stack, method, target); visitStackAndLocals(t, v, stack, method, ip); - ip = t->arch->frameIp(stack); + ip = nextIp; + + target = method; } else if (trace) { stack = trace->stack; - base = trace->base; ip = t->arch->frameIp(stack); trace = trace->next; if (trace) { targetMethod = trace->targetMethod; + target = targetMethod; + } else { + target = 0; } } else { break; @@ -6635,24 +6751,27 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) void callContinuation(MyThread* t, object continuation, object result, - object exception, void* ip, void* base, void* stack) + object exception, void* ip, void* stack) { assert(t, t->exception == 0); if (exception) { t->exception = exception; - MyThread::TraceContext c(t, ip, stack, base, continuation, t->trace); + MyThread::TraceContext c(t, ip, stack, continuation, t->trace); - findUnwindTarget(t, &ip, &base, &stack, &continuation); + void* frame; + findUnwindTarget(t, &ip, &frame, &stack, &continuation); } t->trace->nativeMethod = 0; t->trace->targetMethod = 0; - transition(t, ip, stack, base, continuation, t->trace); + popResources(t); - vmJump(ip, base, stack, t, reinterpret_cast(result), 0); + transition(t, ip, stack, continuation, t->trace); + + vmJump(ip, 0, stack, t, reinterpret_cast(result), 0); } int8_t* @@ -6710,7 +6829,7 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } void -jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) +jumpAndInvoke(MyThread* t, object method, void* stack, ...) { t->trace->targetMethod = 0; @@ -6721,16 +6840,19 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) } unsigned argumentCount = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, arguments, argumentCount); + THREAD_RUNTIME_ARRAY(t, uintptr_t, arguments, argumentCount); va_list a; va_start(a, stack); for (unsigned i = 0; i < argumentCount; ++i) { RUNTIME_ARRAY_BODY(arguments)[i] = va_arg(a, uintptr_t); } va_end(a); + + assert(t, t->exception == 0); + + popResources(t); vmJumpAndInvoke (t, reinterpret_cast(methodAddress(t, method)), - base, stack, argumentCount * BytesPerWord, RUNTIME_ARRAY_BODY(arguments), @@ -6746,8 +6868,7 @@ callContinuation(MyThread* t, object continuation, object result, enum { Call, Unwind, - Rewind, - Throw + Rewind } action; object nextContinuation = 0; @@ -6800,67 +6921,54 @@ callContinuation(MyThread* t, object continuation, object result, nextContinuation = continuationContextContinuation(t, rewindContext); action = Rewind; - if (rewindMethod(t) == 0) { + if (root(t, RewindMethod) == 0) { PROTECT(t, nextContinuation); object method = resolveMethod - (t, t->m->loader, "avian/Continuations", "rewind", + (t, root(t, Machine::BootLoader), "avian/Continuations", "rewind", "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" "Ljava/lang/Throwable;)V"); - - if (method) { - rewindMethod(t) = method; - - compile(t, local::codeAllocator(t), 0, method); - if (UNLIKELY(t->exception)) { - action = Throw; - } - } else { - action = Throw; - } + PROTECT(t, method); + + compile(t, local::codeAllocator(t), 0, method); + + setRoot(t, RewindMethod, method); } } else { action = Call; } } else { - t->exception = makeIncompatibleContinuationException(t); - action = Throw; + throwNew(t, Machine::IncompatibleContinuationExceptionType); } } else { action = Call; } void* ip; - void* base; + void* frame; void* stack; object threadContinuation; - findUnwindTarget(t, &ip, &base, &stack, &threadContinuation); + findUnwindTarget(t, &ip, &frame, &stack, &threadContinuation); switch (action) { case Call: { - callContinuation(t, continuation, result, exception, ip, base, stack); + callContinuation(t, continuation, result, exception, ip, stack); } break; case Unwind: { - callContinuation(t, nextContinuation, result, 0, ip, base, stack); + callContinuation(t, nextContinuation, result, 0, ip, stack); } break; case Rewind: { - transition(t, 0, 0, 0, nextContinuation, t->trace); + transition(t, 0, 0, nextContinuation, t->trace); jumpAndInvoke - (t, rewindMethod(t), base, stack, + (t, root(t, RewindMethod), stack, continuationContextBefore(t, continuationContext(t, nextContinuation)), continuation, result, exception); } break; - case Throw: { - transition(t, ip, stack, base, threadContinuation, t->trace); - - vmJump(ip, base, stack, t, 0, 0); - } break; - default: abort(t); } @@ -6871,87 +6979,72 @@ callWithCurrentContinuation(MyThread* t, object receiver) { object method = 0; void* ip = 0; - void* base = 0; void* stack = 0; { PROTECT(t, receiver); - if (receiveMethod(t) == 0) { + if (root(t, ReceiveMethod) == 0) { object m = resolveMethod - (t, t->m->loader, "avian/CallbackReceiver", "receive", + (t, root(t, Machine::BootLoader), "avian/CallbackReceiver", "receive", "(Lavian/Callback;)Ljava/lang/Object;"); if (m) { - receiveMethod(t) = m; + setRoot(t, ReceiveMethod, m); - object continuationClass = arrayBody - (t, t->m->types, Machine::ContinuationType); + object continuationClass = type(t, Machine::ContinuationType); if (classVmFlags(t, continuationClass) & BootstrapFlag) { - resolveSystemClass(t, vm::className(t, continuationClass)); + resolveSystemClass + (t, root(t, Machine::BootLoader), + vm::className(t, continuationClass)); } } } - if (LIKELY(t->exception == 0)) { - method = findInterfaceMethod - (t, receiveMethod(t), objectClass(t, receiver)); - PROTECT(t, method); + method = findInterfaceMethod + (t, root(t, ReceiveMethod), objectClass(t, receiver)); + PROTECT(t, method); - compile(t, local::codeAllocator(t), 0, method); + compile(t, local::codeAllocator(t), 0, method); - if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); - } - } + t->continuation = makeCurrentContinuation(t, &ip, &stack); } - if (LIKELY(t->exception == 0)) { - jumpAndInvoke(t, method, base, stack, receiver, t->continuation); - } else { - unwind(t); - } + jumpAndInvoke(t, method, stack, receiver, t->continuation); } void dynamicWind(MyThread* t, object before, object thunk, object after) { void* ip = 0; - void* base = 0; void* stack = 0; { PROTECT(t, before); PROTECT(t, thunk); PROTECT(t, after); - if (windMethod(t) == 0) { + if (root(t, WindMethod) == 0) { object method = resolveMethod - (t, t->m->loader, "avian/Continuations", "wind", + (t, root(t, Machine::BootLoader), "avian/Continuations", "wind", "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" - "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); + "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); if (method) { - windMethod(t) = method; + setRoot(t, WindMethod, method); compile(t, local::codeAllocator(t), 0, method); } } - if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); + t->continuation = makeCurrentContinuation(t, &ip, &stack); - object newContext = makeContinuationContext - (t, continuationContext(t, t->continuation), before, after, - t->continuation, t->trace->originalMethod); + object newContext = makeContinuationContext + (t, continuationContext(t, t->continuation), before, after, + t->continuation, t->trace->originalMethod); - set(t, t->continuation, ContinuationContext, newContext); - } + set(t, t->continuation, ContinuationContext, newContext); } - if (LIKELY(t->exception == 0)) { - jumpAndInvoke(t, windMethod(t), base, stack, before, thunk, after); - } else { - unwind(t); - } + jumpAndInvoke(t, root(t, WindMethod), stack, before, thunk, after); } class ArgumentList { @@ -7082,7 +7175,18 @@ object invoke(Thread* thread, object method, ArgumentList* arguments) { MyThread* t = static_cast(thread); - + + uintptr_t stackLimit = t->stackLimit; + uintptr_t stackPosition = reinterpret_cast(&t); + if (stackLimit == 0) { + t->stackLimit = stackPosition - StackSizeInBytes; + } else if (stackPosition < stackLimit) { + throwNew(t, Machine::StackOverflowErrorType); + } + + THREAD_RESOURCE(t, uintptr_t, stackLimit, + static_cast(t)->stackLimit = stackLimit); + unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); @@ -7090,6 +7194,8 @@ invoke(Thread* thread, object method, ArgumentList* arguments) { MyThread::CallTrace trace(t, method); + MyCheckpoint checkpoint(t); + assert(t, arguments->position == arguments->size); result = vmInvoke @@ -7103,10 +7209,13 @@ invoke(Thread* thread, object method, ArgumentList* arguments) } if (t->exception) { - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } - return 0; + + object exception = t->exception; + t->exception = 0; + vm::throw_(t, exception); } object r; @@ -7140,11 +7249,12 @@ invoke(Thread* thread, object method, ArgumentList* arguments) return r; } -class SegFaultHandler: public System::SignalHandler { +class SignalHandler: public System::SignalHandler { public: - SegFaultHandler(): m(0) { } + SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): + m(0), type(type), root(root), fixedSize(fixedSize) { } - virtual bool handleSignal(void** ip, void** base, void** stack, + virtual bool handleSignal(void** ip, void** frame, void** stack, void** thread) { MyThread* t = static_cast(m->localThread->get()); @@ -7156,24 +7266,24 @@ class SegFaultHandler: public System::SignalHandler { MyThread::TraceContext context (t, static_cast(*ip) + 1, static_cast(*stack) - t->arch->frameReturnAddressSize(), - *base, t->continuation, t->trace); + t->continuation, t->trace); - if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { - t->tracing = true; - t->exception = makeNullPointerException(t); - t->tracing = false; + if (ensure(t, fixedSize + traceSize(t))) { + atomicOr(&(t->flags), Thread::TracingFlag); + t->exception = makeThrowable(t, type); + atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { - // not enough memory available for a new NPE and stack trace - // -- use a preallocated instance instead - t->exception = t->m->nullPointerException; + // not enough memory available for a new exception and stack + // trace -- use a preallocated instance instead + t->exception = vm::root(t, root); } -// printTrace(t, t->exception); + // printTrace(t, t->exception); object continuation; - findUnwindTarget(t, ip, base, stack, &continuation); + findUnwindTarget(t, ip, frame, stack, &continuation); - transition(t, ip, stack, base, continuation, t->trace); + transition(t, ip, stack, continuation, t->trace); *thread = t; @@ -7189,6 +7299,9 @@ class SegFaultHandler: public System::SignalHandler { } Machine* m; + Machine::Type type; + Machine::Root root; + unsigned fixedSize; }; bool @@ -7205,12 +7318,12 @@ boot(MyThread* t, BootImage* image); class MyProcessor; -void -compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p); - MyProcessor* processor(MyThread* t); +void +compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p); + class MyProcessor: public Processor { public: class Thunk { @@ -7234,22 +7347,21 @@ class MyProcessor: public Processor { Thunk defaultVirtual; Thunk native; Thunk aioob; + Thunk stackOverflow; Thunk table; }; MyProcessor(System* s, Allocator* allocator, bool useNativeFeatures): s(s), allocator(allocator), - callTable(0), - methodTree(0), - methodTreeSentinal(0), - objectPools(0), - staticTableArray(0), - virtualThunks(0), - receiveMethod(0), - windMethod(0), - rewindMethod(0), + roots(0), bootImage(0), + segFaultHandler(Machine::NullPointerExceptionType, + Machine::NullPointerException, + FixedSizeOfNullPointerException), + divideByZeroHandler(Machine::ArithmeticExceptionType, + Machine::ArithmeticException, + FixedSizeOfArithmeticException), codeAllocator(s, 0, 0), callTableSize(0), useNativeFeatures(useNativeFeatures) @@ -7264,6 +7376,8 @@ class MyProcessor: public Processor { t->init(); if (false) { + fprintf(stderr, "%d\n", difference(&(t->stack), t)); + fprintf(stderr, "%d\n", difference(&(t->scratch), t)); fprintf(stderr, "%d\n", difference(&(t->continuation), t)); fprintf(stderr, "%d\n", difference(&(t->exception), t)); fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t)); @@ -7289,10 +7403,13 @@ class MyProcessor: public Processor { object class_, object code) { + if (code) { + codeCompiled(t, code) = local::defaultThunk(static_cast(t)); + } + return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code, - local::defaultThunk(static_cast(t))); + offset, 0, 0, name, spec, addendum, class_, code); } virtual object @@ -7317,8 +7434,9 @@ class MyProcessor: public Processor { { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, - objectMask, name, sourceFile, super, interfaceTable, virtualTable, - fieldTable, methodTable, staticTable, addendum, loader, vtableLength); + 0, objectMask, name, sourceFile, super, interfaceTable, + virtualTable, fieldTable, methodTable, staticTable, addendum, loader, + vtableLength); } virtual void @@ -7349,15 +7467,7 @@ class MyProcessor: public Processor { MyThread* t = static_cast(vmt); if (t == t->m->rootThread) { - v->visit(&callTable); - v->visit(&methodTree); - v->visit(&methodTreeSentinal); - v->visit(&objectPools); - v->visit(&staticTableArray); - v->visit(&virtualThunks); - v->visit(&receiveMethod); - v->visit(&windMethod); - v->visit(&rewindMethod); + v->visit(&roots); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { @@ -7427,7 +7537,7 @@ class MyProcessor: public Processor { virtual object invokeArray(Thread* t, object method, object this_, object arguments) { - if (UNLIKELY(t->exception)) return 0; + assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); @@ -7440,8 +7550,8 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, array, size); - RUNTIME_ARRAY(bool, objectMask, size); + THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); + THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, arguments); @@ -7451,18 +7561,14 @@ class MyProcessor: public Processor { compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); - if (LIKELY(t->exception == 0)) { - return local::invoke(t, method, &list); - } - - return 0; + return local::invoke(t, method, &list); } virtual object invokeList(Thread* t, object method, object this_, bool indirectObjects, va_list arguments) { - if (UNLIKELY(t->exception)) return 0; + assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); @@ -7475,32 +7581,18 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, array, size); - RUNTIME_ARRAY(bool, objectMask, size); + THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); + THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, indirectObjects, arguments); PROTECT(t, method); - if (false) { - compile(static_cast(t), - local::codeAllocator(static_cast(t)), 0, - resolveMethod(t, t->m->loader, - "com/ecovate/nat/logic/Cache", - "findInCache", - "(Ljava/lang/String;Ljava/lang/String;JZ)Lcom/ecovate/shared/xmlrpc/Resource;")); - trap(); - } - compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); - if (LIKELY(t->exception == 0)) { - return local::invoke(t, method, &list); - } - - return 0; + return local::invoke(t, method, &list); } virtual object @@ -7508,34 +7600,29 @@ class MyProcessor: public Processor { const char* methodName, const char* methodSpec, object this_, va_list arguments) { - if (UNLIKELY(t->exception)) return 0; + assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); - unsigned size = parameterFootprint(t, methodSpec, false); - RUNTIME_ARRAY(uintptr_t, array, size); - RUNTIME_ARRAY(bool, objectMask, size); + unsigned size = parameterFootprint(t, methodSpec, this_ == 0); + THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); + THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, methodSpec, false, arguments); object method = resolveMethod (t, loader, className, methodName, methodSpec); - if (LIKELY(t->exception == 0)) { - assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); - PROTECT(t, method); + assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); + + PROTECT(t, method); - compile(static_cast(t), - local::codeAllocator(static_cast(t)), 0, method); + compile(static_cast(t), + local::codeAllocator(static_cast(t)), 0, method); - if (LIKELY(t->exception == 0)) { - return local::invoke(t, method, &list); - } - } - - return 0; + return local::invoke(t, method, &list); } virtual void dispose(Thread* vmt) { @@ -7571,18 +7658,17 @@ class MyProcessor: public Processor { t(t), p(p), target(target), trace(0) { } - virtual void visit(void* ip, void* base, void* stack) { - MyThread::TraceContext c(target); + virtual void visit(void* ip, void* stack, void* link) { + MyThread::TraceContext c(target, link); if (methodForIp(t, ip)) { // we caught the thread in Java code - use the register values c.ip = ip; - c.base = base; c.stack = stack; + c.javaStackLimit = stack; } else if (target->transition) { // we caught the thread in native code while in the middle - // of updating the context fields (MyThread::stack, - // MyThread::base, etc.) + // of updating the context fields (MyThread::stack, etc.) static_cast(c) = *(target->transition); } else if (isVmInvokeUnsafeStack(ip)) { // we caught the thread in native code just after returning @@ -7591,38 +7677,33 @@ class MyProcessor: public Processor { // Java frame, if any, can be found in // MyThread::continuation or MyThread::trace c.ip = 0; - c.base = 0; c.stack = 0; } else if (target->stack and (not isThunkUnsafeStack(t, ip)) and (not isVirtualThunk(t, ip))) { // we caught the thread in a thunk or native code, and the - // saved stack and base pointers indicate the most recent - // Java frame on the stack + // saved stack pointer indicates the most recent Java frame + // on the stack c.ip = t->arch->frameIp(target->stack); - c.base = target->base; c.stack = target->stack; } else if (isThunk(t, ip) or isVirtualThunk(t, ip)) { - // we caught the thread in a thunk where the stack and base - // registers indicate the most recent Java frame on the - // stack + // we caught the thread in a thunk where the stack register + // indicates the most recent Java frame on the stack c.ip = t->arch->frameIp(stack); - c.base = base; c.stack = stack; } else { // we caught the thread in native code, and the most recent // Java frame, if any, can be found in // MyThread::continuation or MyThread::trace c.ip = 0; - c.base = 0; c.stack = 0; } if (ensure(t, traceSize(target))) { - t->tracing = true; + atomicOr(&(t->flags), Thread::TracingFlag); trace = makeTrace(t, target); - t->tracing = false; + atomicAnd(&(t->flags), ~Thread::TracingFlag); } } @@ -7634,13 +7715,13 @@ class MyProcessor: public Processor { t->m->system->visit(t->systemThread, target->systemThread, &visitor); - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { PROTECT(t, visitor.trace); collect(t, Heap::MinorCollection); } - return visitor.trace ? visitor.trace : makeArray(t, 0); + return visitor.trace ? visitor.trace : makeObjectArray(t, 0); } virtual void initialize(BootImage* image, uint8_t* code, unsigned capacity) { @@ -7663,10 +7744,10 @@ class MyProcessor: public Processor { *addresses = bootContext.addresses; } - virtual void visitRoots(HeapWalker* w) { - bootImage->methodTree = w->visitRoot(methodTree); - bootImage->methodTreeSentinal = w->visitRoot(methodTreeSentinal); - bootImage->virtualThunks = w->visitRoot(virtualThunks); + virtual void visitRoots(Thread* t, HeapWalker* w) { + bootImage->methodTree = w->visitRoot(root(t, MethodTree)); + bootImage->methodTreeSentinal = w->visitRoot(root(t, MethodTreeSentinal)); + bootImage->virtualThunks = w->visitRoot(root(t, VirtualThunks)); } virtual unsigned* makeCallTable(Thread* t, HeapWalker* w) { @@ -7677,8 +7758,10 @@ class MyProcessor: public Processor { (t->m->heap->allocate(callTableSize * sizeof(unsigned) * 2)); unsigned index = 0; - for (unsigned i = 0; i < arrayLength(t, callTable); ++i) { - for (object p = arrayBody(t, callTable, i); p; p = callNodeNext(t, p)) { + for (unsigned i = 0; i < arrayLength(t, root(t, CallTable)); ++i) { + for (object p = arrayBody(t, root(t, CallTable), i); + p; p = callNodeNext(t, p)) + { table[index++] = callNodeAddress(t, p) - reinterpret_cast(codeAllocator.base); table[index++] = w->map()->find(callNodeTarget(t, p)) @@ -7699,11 +7782,16 @@ class MyProcessor: public Processor { if (image) { local::boot(static_cast(t), image); } else { - callTable = makeArray(t, 128); + roots = makeArray(t, RootCount); - methodTree = methodTreeSentinal = makeTreeNode(t, 0, 0, 0); - set(t, methodTree, TreeNodeLeft, methodTreeSentinal); - set(t, methodTree, TreeNodeRight, methodTreeSentinal); + setRoot(t, CallTable, makeArray(t, 128)); + + setRoot(t, MethodTreeSentinal, makeTreeNode(t, 0, 0, 0)); + setRoot(t, MethodTree, root(t, MethodTreeSentinal)); + set(t, root(t, MethodTree), TreeNodeLeft, + root(t, MethodTreeSentinal)); + set(t, root(t, MethodTree), TreeNodeRight, + root(t, MethodTreeSentinal)); } local::compileThunks(static_cast(t), &codeAllocator, this); @@ -7711,6 +7799,10 @@ class MyProcessor: public Processor { segFaultHandler.m = t->m; expect(t, t->m->system->success (t->m->system->handleSegFault(&segFaultHandler))); + + divideByZeroHandler.m = t->m; + expect(t, t->m->system->success + (t->m->system->handleDivideByZero(÷ByZeroHandler))); } virtual void callWithCurrentContinuation(Thread* t, object receiver) { @@ -7763,17 +7855,10 @@ class MyProcessor: public Processor { System* s; Allocator* allocator; - object callTable; - object methodTree; - object methodTreeSentinal; - object objectPools; - object staticTableArray; - object virtualThunks; - object receiveMethod; - object windMethod; - object rewindMethod; + object roots; BootImage* bootImage; - SegFaultHandler segFaultHandler; + SignalHandler segFaultHandler; + SignalHandler divideByZeroHandler; FixedAllocator codeAllocator; ThunkCollection thunks; ThunkCollection bootThunks; @@ -7814,7 +7899,7 @@ isThunkUnsafeStack(MyProcessor::Thunk* thunk, void* ip) bool isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) { - const unsigned NamedThunkCount = 4; + const unsigned NamedThunkCount = 5; MyProcessor::Thunk table[NamedThunkCount + ThunkCount]; @@ -7822,6 +7907,7 @@ isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) table[1] = thunks->defaultVirtual; table[2] = thunks->native; table[3] = thunks->aioob; + table[4] = thunks->stackOverflow; for (unsigned i = 0; i < ThunkCount; ++i) { new (table + NamedThunkCount + i) MyProcessor::Thunk @@ -7842,11 +7928,10 @@ isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) bool isVirtualThunk(MyThread* t, void* ip) { - MyProcessor* p = processor(t); - - for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); i += 2) { - uintptr_t start = wordArrayBody(t, p->virtualThunks, i); - uintptr_t end = start + wordArrayBody(t, p->virtualThunks, i + 1); + for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) + { + uintptr_t start = wordArrayBody(t, root(t, VirtualThunks), i); + uintptr_t end = start + wordArrayBody(t, root(t, VirtualThunks), i + 1); if (reinterpret_cast(ip) >= start and reinterpret_cast(ip) < end) @@ -7880,8 +7965,7 @@ findCallNode(MyThread* t, void* address) // compile(MyThread*, Allocator*, BootContext*, object)): loadMemoryBarrier(); - MyProcessor* p = processor(t); - object table = p->callTable; + object table = root(t, CallTable); intptr_t key = reinterpret_cast(address); unsigned index = static_cast(key) & (arrayLength(t, table) - 1); @@ -7961,8 +8045,8 @@ insertCallNode(MyThread* t, object table, unsigned* size, object node) void insertCallNode(MyThread* t, object node) { - MyProcessor* p = processor(t); - p->callTable = insertCallNode(t, p->callTable, &(p->callTableSize), node); + setRoot(t, CallTable, insertCallNode + (t, root(t, CallTable), &(processor(t)->callTableSize), node)); } object @@ -7981,14 +8065,19 @@ makeClassMap(Thread* t, unsigned* table, unsigned count, uintptr_t* heap) } object -makeStaticTableArray(Thread* t, unsigned* table, unsigned count, - uintptr_t* heap) +makeStaticTableArray(Thread* t, unsigned* bootTable, unsigned bootCount, + unsigned* appTable, unsigned appCount, uintptr_t* heap) { - object array = makeArray(t, count); + object array = makeArray(t, bootCount + appCount); - for (unsigned i = 0; i < count; ++i) { + for (unsigned i = 0; i < bootCount; ++i) { set(t, array, ArrayBody + (i * BytesPerWord), - classStaticTable(t, bootObject(heap, table[i]))); + classStaticTable(t, bootObject(heap, bootTable[i]))); + } + + for (unsigned i = 0; i < appCount; ++i) { + set(t, array, ArrayBody + ((bootCount + i) * BytesPerWord), + classStaticTable(t, bootObject(heap, appTable[i]))); } return array; @@ -8093,23 +8182,23 @@ fixupCode(Thread* t, uintptr_t* map, unsigned size, uint8_t* code, } void -fixupMethods(Thread* t, BootImage* image, uint8_t* code) +fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) { - for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { + for (HashMapIterator it(t, map); it.hasMore();) { object c = tripleSecond(t, it.next()); if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { + if (methodCode(t, method)) { assert(t, (methodCompiled(t, method) - image->codeBase) <= image->codeSize); - methodCompiled(t, method) + codeCompiled(t, methodCode(t, method)) = (methodCompiled(t, method) - image->codeBase) + reinterpret_cast(code); - if (DebugCompile and (methodFlags(t, method) & ACC_NATIVE) == 0) { + if (DebugCompile) { logCompile (static_cast(t), reinterpret_cast(methodCompiled(t, method)), @@ -8147,6 +8236,8 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) = thunkToThunk(image->thunks.defaultVirtual, code); p->bootThunks.native = thunkToThunk(image->thunks.native, code); p->bootThunks.aioob = thunkToThunk(image->thunks.aioob, code); + p->bootThunks.stackOverflow + = thunkToThunk(image->thunks.stackOverflow, code); p->bootThunks.table = thunkToThunk(image->thunks.table, code); updateCall(t, LongCall, code + image->compileMethodCall, @@ -8161,6 +8252,9 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) updateCall(t, LongCall, code + image->throwArrayIndexOutOfBoundsCall, voidPointer(throwArrayIndexOutOfBounds)); + updateCall(t, LongCall, code + image->throwStackOverflowCall, + voidPointer(throwStackOverflow)); + #define THUNK(s) \ updateCall(t, LongJump, code + image->s##Call, voidPointer(s)); @@ -8172,12 +8266,11 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) void fixupVirtualThunks(MyThread* t, BootImage* image, uint8_t* code) { - MyProcessor* p = processor(t); - - for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); i += 2) { - if (wordArrayBody(t, p->virtualThunks, i)) { - wordArrayBody(t, p->virtualThunks, i) - = (wordArrayBody(t, p->virtualThunks, i) - image->codeBase) + for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) + { + if (wordArrayBody(t, root(t, VirtualThunks), i)) { + wordArrayBody(t, root(t, VirtualThunks), i) + = (wordArrayBody(t, root(t, VirtualThunks), i) - image->codeBase) + reinterpret_cast(code); } } @@ -8188,8 +8281,9 @@ boot(MyThread* t, BootImage* image) { assert(t, image->magic == BootImage::Magic); - unsigned* classTable = reinterpret_cast(image + 1); - unsigned* stringTable = classTable + image->classCount; + unsigned* bootClassTable = reinterpret_cast(image + 1); + unsigned* appClassTable = bootClassTable + image->bootClassCount; + unsigned* stringTable = appClassTable + image->appClassCount; unsigned* callTable = stringTable + image->stringCount; uintptr_t* heapMap = reinterpret_cast @@ -8213,39 +8307,60 @@ boot(MyThread* t, BootImage* image) t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); - t->m->loader = bootObject(heap, image->loader); t->m->types = bootObject(heap, image->types); - MyProcessor* p = static_cast(t->m->processor); - - p->methodTree = bootObject(heap, image->methodTree); - p->methodTreeSentinal = bootObject(heap, image->methodTreeSentinal); + t->m->roots = makeArray(t, Machine::RootCount); - p->virtualThunks = bootObject(heap, image->virtualThunks); + setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); + setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); + + MyProcessor* p = static_cast(t->m->processor); + + p->roots = makeArray(t, RootCount); + + setRoot(t, MethodTree, bootObject(heap, image->methodTree)); + setRoot(t, MethodTreeSentinal, bootObject(heap, image->methodTreeSentinal)); + + setRoot(t, VirtualThunks, bootObject(heap, image->virtualThunks)); fixupCode(t, codeMap, codeMapSizeInWords, code, heap); syncInstructionCache(code, image->codeSize); - t->m->classMap = makeClassMap(t, classTable, image->classCount, heap); + { object map = makeClassMap(t, bootClassTable, image->bootClassCount, heap); + set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); + } - t->m->stringMap = makeStringMap(t, stringTable, image->stringCount, heap); + systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = t->m->bootFinder; + + { object map = makeClassMap(t, appClassTable, image->appClassCount, heap); + set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); + } + + systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = t->m->appFinder; + + setRoot(t, Machine::StringMap, makeStringMap + (t, stringTable, image->stringCount, heap)); p->callTableSize = image->callCount; - p->callTable = makeCallTable - (t, heap, callTable, image->callCount, - reinterpret_cast(code)); - p->staticTableArray = makeStaticTableArray - (t, classTable, image->classCount, heap); + setRoot(t, CallTable, makeCallTable + (t, heap, callTable, image->callCount, + reinterpret_cast(code))); + setRoot(t, StaticTableArray, makeStaticTableArray + (t, bootClassTable, image->bootClassCount, + appClassTable, image->appClassCount, heap)); + fixupThunks(t, image, code); fixupVirtualThunks(t, image, code); - fixupMethods(t, image, code); + fixupMethods + (t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code); + fixupMethods(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code); - t->m->bootstrapClassMap = makeHashMap(t, 0, 0); + setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); } intptr_t @@ -8283,7 +8398,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = defaultContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.default_.frameSavedOffset = a->length(); @@ -8293,14 +8408,12 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(defaultContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrame(); + a->popFrame(t->arch->alignFrameSize(1)); Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); - a->endBlock(false)->resolve(0, 0); - - p->thunks.default_.length = a->length(); + p->thunks.default_.length = a->endBlock(false)->resolve(0, 0); } ThunkContext defaultVirtualContext(t, &zone); @@ -8329,7 +8442,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->apply(Move, BytesPerWord, RegisterOperand, &index, BytesPerWord, MemoryOperand, &virtualCallIndex); - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.defaultVirtual.frameSavedOffset = a->length(); @@ -8339,21 +8452,19 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(defaultVirtualContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrame(); + a->popFrame(t->arch->alignFrameSize(1)); Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); - a->endBlock(false)->resolve(0, 0); - - p->thunks.defaultVirtual.length = a->length(); + p->thunks.defaultVirtual.length = a->endBlock(false)->resolve(0, 0); } ThunkContext nativeContext(t, &zone); { Assembler* a = nativeContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.native.frameSavedOffset = a->length(); @@ -8363,18 +8474,17 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(nativeContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrameAndUpdateStackAndReturn(difference(&(t->stack), t)); + a->popFrameAndUpdateStackAndReturn + (t->arch->alignFrameSize(1), difference(&(t->stack), t)); - a->endBlock(false)->resolve(0, 0); - - p->thunks.native.length = a->length(); + p->thunks.native.length = a->endBlock(false)->resolve(0, 0); } ThunkContext aioobContext(t, &zone); { Assembler* a = aioobContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.aioob.frameSavedOffset = a->length(); @@ -8384,29 +8494,43 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(aioobContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->endBlock(false)->resolve(0, 0); + p->thunks.aioob.length = a->endBlock(false)->resolve(0, 0); + } - p->thunks.aioob.length = a->length(); + ThunkContext stackOverflowContext(t, &zone); + + { Assembler* a = stackOverflowContext.context.assembler; + + a->saveFrame(difference(&(t->stack), t)); + + p->thunks.stackOverflow.frameSavedOffset = a->length(); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); + + Assembler::Constant proc(&(stackOverflowContext.promise)); + a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); + + p->thunks.stackOverflow.length = a->endBlock(false)->resolve(0, 0); } ThunkContext tableContext(t, &zone); { Assembler* a = tableContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.table.frameSavedOffset = a->length(); Assembler::Constant proc(&(tableContext.promise)); a->apply(LongJump, BytesPerWord, ConstantOperand, &proc); - a->endBlock(false)->resolve(0, 0); - - p->thunks.table.length = a->length(); + p->thunks.table.length = a->endBlock(false)->resolve(0, 0); } p->thunks.default_.start = finish - (t, allocator, defaultContext.context.assembler, "default"); + (t, allocator, defaultContext.context.assembler, "default", + p->thunks.default_.length); BootImage* image = p->bootImage; uint8_t* imageBase = p->codeAllocator.base; @@ -8421,7 +8545,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } p->thunks.defaultVirtual.start = finish - (t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual"); + (t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual", + p->thunks.defaultVirtual.length); { void* call; defaultVirtualContext.promise.listener->resolve @@ -8434,7 +8559,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } p->thunks.native.start = finish - (t, allocator, nativeContext.context.assembler, "native"); + (t, allocator, nativeContext.context.assembler, "native", + p->thunks.native.length); { void* call; nativeContext.promise.listener->resolve @@ -8446,7 +8572,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } p->thunks.aioob.start = finish - (t, allocator, aioobContext.context.assembler, "aioob"); + (t, allocator, aioobContext.context.assembler, "aioob", + p->thunks.aioob.length); { void* call; aioobContext.promise.listener->resolve @@ -8459,6 +8586,21 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } } + p->thunks.stackOverflow.start = finish + (t, allocator, stackOverflowContext.context.assembler, "stackOverflow", + p->thunks.stackOverflow.length); + + { void* call; + stackOverflowContext.promise.listener->resolve + (reinterpret_cast(voidPointer(throwStackOverflow)), + &call); + + if (image) { + image->throwStackOverflowCall + = static_cast(call) - imageBase; + } + } + p->thunks.table.start = static_cast (allocator->allocate(p->thunks.table.length * ThunkCount)); @@ -8468,6 +8610,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) = thunkToThunk(p->thunks.defaultVirtual, imageBase); image->thunks.native = thunkToThunk(p->thunks.native, imageBase); image->thunks.aioob = thunkToThunk(p->thunks.aioob, imageBase); + image->thunks.stackOverflow + = thunkToThunk(p->thunks.stackOverflow, imageBase); image->thunks.table = thunkToThunk(p->thunks.table, imageBase); } @@ -8498,30 +8642,6 @@ processor(MyThread* t) return static_cast(t->m->processor); } -object& -objectPools(MyThread* t) -{ - return processor(t)->objectPools; -} - -object& -windMethod(MyThread* t) -{ - return processor(t)->windMethod; -} - -object& -rewindMethod(MyThread* t) -{ - return processor(t)->rewindMethod; -} - -object& -receiveMethod(MyThread* t) -{ - return processor(t)->receiveMethod; -} - uintptr_t defaultThunk(MyThread* t) { @@ -8559,6 +8679,12 @@ aioobThunk(MyThread* t) return reinterpret_cast(processor(t)->thunks.aioob.start); } +uintptr_t +stackOverflowThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->thunks.stackOverflow.start); +} + bool unresolved(MyThread* t, uintptr_t methodAddress) { @@ -8582,9 +8708,7 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) Assembler::Constant thunk(&defaultVirtualThunkPromise); a->apply(Jump, BytesPerWord, ConstantOperand, &thunk); - a->endBlock(false)->resolve(0, 0); - - *size = a->length(); + *size = a->endBlock(false)->resolve(0, 0); uint8_t* start = static_cast(codeAllocator(t)->allocate(*size)); @@ -8598,32 +8722,30 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) uintptr_t virtualThunk(MyThread* t, unsigned index) { - MyProcessor* p = processor(t); - - if (p->virtualThunks == 0 - or wordArrayLength(t, p->virtualThunks) <= index * 2) + if (root(t, VirtualThunks) == 0 + or wordArrayLength(t, root(t, VirtualThunks)) <= index * 2) { object newArray = makeWordArray(t, nextPowerOfTwo((index + 1) * 2)); - if (p->virtualThunks) { + if (root(t, VirtualThunks)) { memcpy(&wordArrayBody(t, newArray, 0), - &wordArrayBody(t, p->virtualThunks, 0), - wordArrayLength(t, p->virtualThunks) * BytesPerWord); + &wordArrayBody(t, root(t, VirtualThunks), 0), + wordArrayLength(t, root(t, VirtualThunks)) * BytesPerWord); } - p->virtualThunks = newArray; + setRoot(t, VirtualThunks, newArray); } - if (wordArrayBody(t, p->virtualThunks, index * 2) == 0) { + if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { ACQUIRE(t, t->m->classLock); - if (wordArrayBody(t, p->virtualThunks, index * 2) == 0) { + if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { unsigned size; uintptr_t thunk = compileVirtualThunk(t, index, &size); - wordArrayBody(t, p->virtualThunks, index * 2) = thunk; - wordArrayBody(t, p->virtualThunks, (index * 2) + 1) = size; + wordArrayBody(t, root(t, VirtualThunks), index * 2) = thunk; + wordArrayBody(t, root(t, VirtualThunks), (index * 2) + 1) = size; } } - return wordArrayBody(t, p->virtualThunks, index * 2); + return wordArrayBody(t, root(t, VirtualThunks), index * 2); } void @@ -8634,78 +8756,109 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, if (bootContext == 0) { initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return; } - if (methodAddress(t, method) == defaultThunk(t)) { - ACQUIRE(t, t->m->classLock); - - if (methodAddress(t, method) == defaultThunk(t)) { - assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } - Context context(t, bootContext, method); - uint8_t* compiled = compile(t, allocator, &context); - if (UNLIKELY(t->exception)) return; + assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); - if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", compiled); + // We must avoid acquiring any locks until after the first pass of + // compilation, since this pass may trigger classloading operations + // involving application classloaders and thus the potential for + // deadlock. To make this safe, we use a private clone of the + // method so that we won't be confused if another thread updates the + // original while we're working. + + object clone = methodClone(t, method); + + loadMemoryBarrier(); + + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } + + PROTECT(t, clone); + + Context context(t, bootContext, clone); + compile(t, &context); + + { object ehTable = codeExceptionHandlerTable(t, methodCode(t, clone)); + + if (ehTable) { + PROTECT(t, ehTable); + + // resolve all exception handler catch types before we acquire + // the class lock: + for (unsigned i = 0; i < exceptionHandlerTableLength(t, ehTable); ++i) { + ExceptionHandler* handler = exceptionHandlerTableBody(t, ehTable, i); + if (exceptionHandlerCatchType(handler)) { + resolveClassInPool + (t, clone, exceptionHandlerCatchType(handler) - 1); + } } - - // We can't set the MethodCompiled field on the original method - // before it is placed into the method tree, since another - // thread might call the method, from which stack unwinding - // would fail (since there is not yet an entry in the method - // tree). However, we can't insert the original method into the - // tree before setting the MethodCompiled field on it since we - // rely on that field to determine its position in the tree. - // Therefore, we insert a clone in its place. Later, we'll - // replace the clone with the original to save memory. - - object clone = makeMethod - (t, methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - methodOffset(t, method), - methodNativeID(t, method), - methodName(t, method), - methodSpec(t, method), - methodAddendum(t, method), - methodClass(t, method), - methodCode(t, method), - reinterpret_cast(compiled)); - - methodTree(t) = treeInsert - (t, &(context.zone), methodTree(t), - reinterpret_cast(compiled), clone, methodTreeSentinal(t), - compareIpToMethodBounds); - - storeStoreMemoryBarrier(); - - methodCompiled(t, method) = reinterpret_cast(compiled); - - if (methodVirtual(t, method)) { - classVtable(t, methodClass(t, method), methodOffset(t, method)) - = compiled; - } - - treeUpdate(t, methodTree(t), reinterpret_cast(compiled), - method, methodTreeSentinal(t), compareIpToMethodBounds); } } + + ACQUIRE(t, t->m->classLock); + + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } + + finish(t, allocator, &context); + + if (DebugMethodTree) { + fprintf(stderr, "insert method at %p\n", + reinterpret_cast(methodCompiled(t, clone))); + } + + // We can't update the MethodCode field on the original method + // before it is placed into the method tree, since another thread + // might call the method, from which stack unwinding would fail + // (since there is not yet an entry in the method tree). However, + // we can't insert the original method into the tree before updating + // the MethodCode field on it since we rely on that field to + // determine its position in the tree. Therefore, we insert the + // clone in its place. Later, we'll replace the clone with the + // original to save memory. + + setRoot + (t, MethodTree, treeInsert + (t, &(context.zone), root(t, MethodTree), + methodCompiled(t, clone), clone, root(t, MethodTreeSentinal), + compareIpToMethodBounds)); + + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, methodCode(t, clone)); + + if (methodVirtual(t, method)) { + classVtable(t, methodClass(t, method), methodOffset(t, method)) + = reinterpret_cast(methodCompiled(t, clone)); + } + + // we've compiled the method and inserted it into the tree without + // error, so we ensure that the executable area not be deallocated + // when we dispose of the context: + context.executableAllocator = 0; + + treeUpdate(t, root(t, MethodTree), methodCompiled(t, clone), + method, root(t, MethodTreeSentinal), compareIpToMethodBounds); } object& -methodTree(MyThread* t) +root(Thread* t, Root root) { - return processor(t)->methodTree; + return arrayBody(t, processor(static_cast(t))->roots, root); } -object -methodTreeSentinal(MyThread* t) +void +setRoot(Thread* t, Root root, object value) { - return processor(t)->methodTreeSentinal; + set(t, processor(static_cast(t))->roots, + ArrayBody + (root * BytesPerWord), value); } FixedAllocator* diff --git a/src/compiler.cpp b/src/compiler.cpp index 44217336a2..18dc98e06f 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -982,9 +982,30 @@ valid(Read* r) return r and r->valid(); } -Read* -live(Value* v) +bool +hasBuddy(Context* c, Value* a, Value* b) { + if (a == b) { + return true; + } + + int i = 0; + for (Value* p = a->buddy; p != a; p = p->buddy) { + if (p == b) { + return true; + } + if (++i > 1000) { + abort(c); + } + } + return false; +} + +Read* +live(Context* c UNUSED, Value* v) +{ + assert(c, hasBuddy(c, v->buddy, v)); + Value* p = v; do { if (valid(p->reads)) { @@ -999,6 +1020,8 @@ live(Value* v) Read* liveNext(Context* c, Value* v) { + assert(c, hasBuddy(c, v->buddy, v)); + Read* r = v->reads->next(c); if (valid(r)) return r; @@ -1082,7 +1105,7 @@ popRead(Context* c, Event* e UNUSED, Value* v) } } - Read* r = live(v); + Read* r = live(c, v); if (r) { deadBuddy(c, v, r); } else { @@ -1493,7 +1516,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, Value* successor = read->successor(); if (successor) { - Read* r = live(successor); + Read* r = live(c, successor); if (r) { SiteMask intersection = mask; if (r->intersect(&intersection)) { @@ -2534,7 +2557,7 @@ steal(Context* c, Resource* r, Value* thief) { r->site->freeze(c, r->value); - maybeMove(c, live(r->value), false, true, StealRegisterReserveCount); + maybeMove(c, live(c, r->value), false, true, StealRegisterReserveCount); r->site->thaw(c, r->value); } @@ -3075,7 +3098,8 @@ codePromise(Context* c, Event* e) CodePromise* codePromise(Context* c, Promise* offset) { - return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset); + return new (c->zone->allocate(sizeof(CodePromise))) + CodePromise(c, offset); } void @@ -3123,12 +3147,25 @@ class CallEvent: public Event { assert(c, stackArgumentFootprint == 0); Stack* s = argumentStack; - unsigned frameIndex = 0; unsigned index = 0; + unsigned argumentIndex = 0; while (true) { + unsigned footprint; + if (argumentIndex + 1 < argumentCount + and s->value->nextWord == s->next->value) + { + footprint = 2; + } else { + footprint = 1; + } + + if (footprint > 1 and index & 1 and c->arch->argumentAlignment()) { + ++ index; + } + SiteMask targetMask; - if (index < c->arch->argumentRegisterCount()) { + if (index + footprint <= c->arch->argumentRegisterCount()) { int number = c->arch->argumentRegister(index); if (DebugReads) { @@ -3138,17 +3175,24 @@ class CallEvent: public Event { targetMask = fixedRegisterMask(number); registerMask &= ~(1 << number); } else { + if (index < c->arch->argumentRegisterCount()) { + index = c->arch->argumentRegisterCount(); + } + + unsigned frameIndex = index - c->arch->argumentRegisterCount(); + if (DebugReads) { fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); } targetMask = SiteMask(1 << MemoryOperand, 0, frameIndex); - ++ frameIndex; } addRead(c, this, s->value, targetMask); - if ((++ index) < argumentCount) { + ++ index; + + if ((++ argumentIndex) < argumentCount) { s = s->next; } else { break; @@ -3201,7 +3245,11 @@ class CallEvent: public Event { int base = frameBase(c); returnAddressIndex = base + c->arch->returnAddressOffset(); - framePointerIndex = base + c->arch->framePointerOffset(); + if (UseFramePointer) { + framePointerIndex = base + c->arch->framePointerOffset(); + } else { + framePointerIndex = -1; + } frameOffset = totalFrameSize(c) - c->arch->argumentFootprint(stackArgumentFootprint); @@ -3334,7 +3382,7 @@ class CallEvent: public Event { apply(c, op, BytesPerWord, address->source, address->source); if (traceHandler) { - traceHandler->handleTrace(codePromise(c, c->assembler->offset()), + traceHandler->handleTrace(codePromise(c, c->assembler->offset(true)), stackArgumentIndex); } @@ -3360,9 +3408,9 @@ class CallEvent: public Event { clean(c, this, stackBefore, localsBefore, reads, popIndex); - if (resultSize and live(result)) { + if (resultSize and live(c, result)) { addSite(c, result, registerSite(c, c->arch->returnLow())); - if (resultSize > BytesPerWord and live(result->nextWord)) { + if (resultSize > BytesPerWord and live(c, result->nextWord)) { addSite(c, result->nextWord, registerSite(c, c->arch->returnHigh())); } } @@ -3427,7 +3475,8 @@ class ReturnEvent: public Event { if (not unreachable(this)) { c->assembler->popFrameAndPopArgumentsAndReturn - (c->arch->argumentFootprint(c->parameterFootprint)); + (c->alignedFrameSize, + c->arch->argumentFootprint(c->parameterFootprint)); } } @@ -3446,7 +3495,7 @@ maybeMove(Context* c, BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst, const SiteMask& dstMask) { - Read* read = live(dst); + Read* read = live(c, dst); bool isStore = read == 0; Site* target; @@ -3607,8 +3656,8 @@ Site* pickSiteOrMove(Context* c, Value* src, Value* dst, Site* nextWord, unsigned index) { - if (live(dst)) { - Read* read = live(src); + if (live(c, dst)) { + Read* read = live(c, src); Site* s; if (nextWord) { s = pickMatchOrMove(c, read, nextWord, index, false); @@ -3727,7 +3776,7 @@ class MoveEvent: public Event { apply(c, Move, srcSelectSize, src->source, src->source, dstSize, dst->target, dst->target); - if (live(dst) == 0) { + if (live(c, dst) == 0) { removeSite(c, dst, dst->target); if (dstSize > BytesPerWord) { removeSite(c, dst->nextWord, dst->nextWord->target); @@ -3754,7 +3803,7 @@ class MoveEvent: public Event { assert(c, srcSize == BytesPerWord); assert(c, srcSelectSize == BytesPerWord); - if (dst->nextWord->target or live(dst->nextWord)) { + if (dst->nextWord->target or live(c, dst->nextWord)) { assert(c, dstLowMask.typeMask & (1 << RegisterOperand)); Site* low = freeRegisterSite(c, dstLowMask.registerMask); @@ -3945,12 +3994,12 @@ class CombineEvent: public Event { virtual void compile(Context* c) { assert(c, first->source->type(c) == first->nextWord->source->type(c)); - if (second->source->type(c) != second->nextWord->source->type(c)) { - fprintf(stderr, "%p %p %d : %p %p %d\n", - second, second->source, second->source->type(c), - second->nextWord, second->nextWord->source, - second->nextWord->source->type(c)); - } + // if (second->source->type(c) != second->nextWord->source->type(c)) { + // fprintf(stderr, "%p %p %d : %p %p %d\n", + // second, second->source, second->source->type(c), + // second->nextWord, second->nextWord->source, + // second->nextWord->source->type(c)); + // } assert(c, second->source->type(c) == second->nextWord->source->type(c)); @@ -4004,9 +4053,9 @@ class CombineEvent: public Event { high->thaw(c, second->nextWord); } - if (live(result)) { + if (live(c, result)) { addSite(c, result, low); - if (resultSize > lowSize and live(result->nextWord)) { + if (resultSize > lowSize and live(c, result->nextWord)) { addSite(c, result->nextWord, high); } } @@ -4043,11 +4092,11 @@ removeBuddy(Context* c, Value* v) assert(c, p->buddy); - if (not live(next)) { + if (not live(c, next)) { clearSites(c, next); } - if (not live(v)) { + if (not live(c, v)) { clearSites(c, v); } } @@ -4312,6 +4361,19 @@ loadLocal(Context* c, unsigned footprint, unsigned index) return c->locals[index].value; } +Value* +register_(Context* c, int number) +{ + assert(c, (1 << number) & (c->arch->generalRegisterMask() + | c->arch->floatRegisterMask())); + + Site* s = registerSite(c, number); + ValueType type = ((1 << number) & c->arch->floatRegisterMask()) + ? ValueFloat: ValueGeneral; + + return value(c, type, s, s); +} + void appendCombine(Context* c, TernaryOperation type, unsigned firstSize, Value* first, @@ -4325,25 +4387,34 @@ appendCombine(Context* c, TernaryOperation type, uint64_t secondRegisterMask; c->arch->planSource(type, firstSize, &firstTypeMask, &firstRegisterMask, - secondSize, &secondTypeMask, &secondRegisterMask, - resultSize, &thunk); + secondSize, &secondTypeMask, &secondRegisterMask, + resultSize, &thunk); if (thunk) { Stack* oldStack = c->stack; + bool threadParameter; + intptr_t handler = c->client->getThunk + (type, firstSize, resultSize, &threadParameter); + + unsigned stackSize = ceiling(secondSize, BytesPerWord) + + ceiling(firstSize, BytesPerWord); + local::push(c, ceiling(secondSize, BytesPerWord), second); local::push(c, ceiling(firstSize, BytesPerWord), first); + if (threadParameter) { + ++ stackSize; + + local::push(c, 1, register_(c, c->arch->thread())); + } + Stack* argumentStack = c->stack; c->stack = oldStack; appendCall - (c, value - (c, ValueGeneral, constantSite - (c, c->client->getThunk(type, firstSize, resultSize))), - 0, 0, result, resultSize, argumentStack, - ceiling(secondSize, BytesPerWord) + ceiling(firstSize, BytesPerWord), - 0); + (c, value(c, ValueGeneral, constantSite(c, handler)), 0, 0, result, + resultSize, argumentStack, stackSize, 0); } else { append (c, new (c->zone->allocate(sizeof(CombineEvent))) @@ -4420,9 +4491,9 @@ class TranslateEvent: public Event { high->thaw(c, value->nextWord); } - if (live(result)) { + if (live(c, result)) { addSite(c, result, low); - if (resultSize > lowSize and live(result->nextWord)) { + if (resultSize > lowSize and live(c, result->nextWord)) { addSite(c, result->nextWord, high); } } @@ -4717,15 +4788,31 @@ class BranchEvent: public Event { if (not unreachable(this)) { if (firstConstant and secondConstant) { - if (shouldJump(c, type, size, firstConstant->value->value(), - secondConstant->value->value())) - { + int64_t firstValue = firstConstant->value->value(); + int64_t secondValue = secondConstant->value->value(); + + if (size > BytesPerWord) { + firstValue |= findConstantSite + (c, first->nextWord)->value->value() << 32; + secondValue |= findConstantSite + (c, second->nextWord)->value->value() << 32; + } + + if (shouldJump(c, type, size, firstValue, secondValue)) { apply(c, Jump, BytesPerWord, address->source, address->source); } } else { + freezeSource(c, size, first); + freezeSource(c, size, second); + freezeSource(c, BytesPerWord, address); + apply(c, type, size, first->source, first->nextWord->source, size, second->source, second->nextWord->source, BytesPerWord, address->source, address->source); + + thawSource(c, BytesPerWord, address); + thawSource(c, size, second); + thawSource(c, size, first); } } @@ -4760,6 +4847,12 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, if (thunk) { Stack* oldStack = c->stack; + bool threadParameter; + intptr_t handler = c->client->getThunk + (type, size, size, &threadParameter); + + assert(c, not threadParameter); + local::push(c, ceiling(size, BytesPerWord), second); local::push(c, ceiling(size, BytesPerWord), first); @@ -4769,9 +4862,8 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, Value* result = value(c, ValueGeneral); appendCall (c, value - (c, ValueGeneral, constantSite(c, c->client->getThunk(type, size, 4))), - 0, 0, result, 4, argumentStack, - ceiling(size, BytesPerWord) * 2, 0); + (c, ValueGeneral, constantSite(c, handler)), 0, 0, result, 4, + argumentStack, ceiling(size, BytesPerWord) * 2, 0); appendBranch(c, thunkBranch(c, type), 4, value (c, ValueGeneral, constantSite(c, static_cast(0))), @@ -4865,12 +4957,13 @@ class BoundsCheckEvent: public Event { Assembler* a = c->assembler; ConstantSite* constant = findConstantSite(c, index); - CodePromise* nextPromise = codePromise - (c, static_cast(0)); CodePromise* outOfBoundsPromise = 0; if (constant) { - expect(c, constant->value->value() >= 0); + if (constant->value->value() < 0) { + Assembler::Constant handlerConstant(resolved(c, handler)); + a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); + } } else { outOfBoundsPromise = codePromise(c, static_cast(0)); @@ -4880,24 +4973,32 @@ class BoundsCheckEvent: public Event { BytesPerWord, &oob, &oob); } - assert(c, object->source->type(c) == RegisterOperand); - MemorySite length(static_cast(object->source)->number, - lengthOffset, NoRegister, 1); - length.acquired = true; + if (constant == 0 or constant->value->value() >= 0) { + assert(c, object->source->type(c) == RegisterOperand); + MemorySite length(static_cast(object->source)->number, + lengthOffset, NoRegister, 1); + length.acquired = true; - ConstantSite next(nextPromise); - apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length, - &length, BytesPerWord, &next, &next); + CodePromise* nextPromise = codePromise(c, static_cast(0)); - if (constant == 0) { - outOfBoundsPromise->offset = a->offset(); + freezeSource(c, BytesPerWord, index); + + ConstantSite next(nextPromise); + apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length, + &length, BytesPerWord, &next, &next); + + thawSource(c, BytesPerWord, index); + + if (constant == 0) { + outOfBoundsPromise->offset = a->offset(); + } + + Assembler::Constant handlerConstant(resolved(c, handler)); + a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); + + nextPromise->offset = a->offset(); } - Assembler::Constant handlerConstant(resolved(c, handler)); - a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); - - nextPromise->offset = a->offset(); - popRead(c, this, object); popRead(c, this, index); } @@ -4927,7 +5028,7 @@ class FrameSiteEvent: public Event { } virtual void compile(Context* c) { - if (live(value)) { + if (live(c, value)) { addSite(c, value, frameSite(c, index)); } } @@ -4965,7 +5066,7 @@ visit(Context* c, Link* link) Value* v = p->value; v->reads = p->read->nextTarget(); // fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read); - if (not live(v)) { + if (not live(c, v)) { clearSites(c, v); } } @@ -5228,7 +5329,7 @@ resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen, { FrameIterator::Element el = it.next(c); Value* v = el.value; - Read* r = v ? live(v) : 0; + Read* r = v ? live(c, v) : 0; Site* s = sites[el.localIndex]; if (r) { @@ -5272,7 +5373,7 @@ resolveSourceSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; - Read* r = live(v); + Read* r = live(c, v); if (r and sites[el.localIndex] == 0) { SiteMask mask((1 << RegisterOperand) | (1 << MemoryOperand), @@ -5306,7 +5407,7 @@ resolveTargetSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; - Read* r = live(v); + Read* r = live(c, v); if (r and sites[el.localIndex] == 0) { SiteMask mask((1 << RegisterOperand) | (1 << MemoryOperand), @@ -5405,7 +5506,7 @@ populateSiteTables(Context* c, Event* e, SiteRecordList* frozen) void setSites(Context* c, Value* v, Site* s) { - assert(c, live(v)); + assert(c, live(c, v)); for (; s; s = s->next) { addSite(c, v, s->copy(c)); @@ -5434,7 +5535,7 @@ setSites(Context* c, Event* e, Site** sites) for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) { FrameIterator::Element el = it.next(c); if (sites[el.localIndex]) { - if (live(el.value)) { + if (live(c, el.value)) { setSites(c, el.value, sites[el.localIndex]); } else if (DebugControl) { char buffer[256]; sitesToString(c, sites[el.localIndex], buffer, 256); @@ -5461,10 +5562,17 @@ void restore(Context* c, Event* e, Snapshot* snapshots) { for (Snapshot* s = snapshots; s; s = s->next) { - // char buffer[256]; sitesToString(c, s->sites, buffer, 256); - // fprintf(stderr, "restore %p buddy %p sites %s live %p\n", - // s->value, s->value->buddy, buffer, live(s->value)); + Value* v = s->value; + Value* next = v->buddy; + if (v != next) { + v->buddy = v; + Value* p = next; + while (p->buddy != v) p = p->buddy; + p->buddy = next; + } + } + for (Snapshot* s = snapshots; s; s = s->next) { assert(c, s->buddy); s->value->buddy = s->buddy; @@ -5473,11 +5581,15 @@ restore(Context* c, Event* e, Snapshot* snapshots) resetFrame(c, e); for (Snapshot* s = snapshots; s; s = s->next) { - if (live(s->value)) { - if (live(s->value) and s->sites and s->value->sites == 0) { + if (live(c, s->value)) { + if (live(c, s->value) and s->sites and s->value->sites == 0) { setSites(c, s->value, s->sites); } } + + // char buffer[256]; sitesToString(c, s->sites, buffer, 256); + // fprintf(stderr, "restore %p buddy %p sites %s live %p\n", + // s->value, s->value->buddy, buffer, live(c, s->value)); } } @@ -5544,7 +5656,7 @@ updateJunctionReads(Context* c, JunctionState* state) FrameIterator::Element e = it.next(c); StubReadPair* p = state->reads + e.localIndex; if (p->value and p->read->read == 0) { - Read* r = live(e.value); + Read* r = live(c, e.value); if (r) { if (DebugReads) { fprintf(stderr, "stub read %p for %p valid: %p\n", @@ -5596,7 +5708,7 @@ block(Context* c, Event* head) } unsigned -compile(Context* c) +compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) { if (c->logicalCode[c->logicalIp]->lastEvent == 0) { appendDummy(c); @@ -5607,6 +5719,10 @@ compile(Context* c) Block* firstBlock = block(c, c->firstEvent); Block* block = firstBlock; + if (stackOverflowHandler) { + a->checkStackOverflow(stackOverflowHandler, stackLimitOffset); + } + a->allocateFrame(c->alignedFrameSize); for (Event* e = c->firstEvent; e; e = e->next) { @@ -5694,6 +5810,8 @@ compile(Context* c) p->offset = a->offset(); } + a->endEvent(); + LogicalInstruction* nextInstruction = next(c, e->logicalInstruction); if (e->next == 0 or (e->next->logicalInstruction != e->logicalInstruction @@ -5731,7 +5849,7 @@ compile(Context* c) block = next; } - return block->assemblerBlock->resolve(block->start, 0) + a->scratchSize(); + return block->assemblerBlock->resolve(block->start, 0) + a->footerSize(); } unsigned @@ -5772,6 +5890,10 @@ addForkElement(Context* c, Value* v, ForkState* state, unsigned index) ForkState* saveState(Context* c) { + if (c->logicalCode[c->logicalIp]->lastEvent == 0) { + appendDummy(c); + } + unsigned elementCount = frameFootprint(c, c->stack) + count(c->saved); ForkState* state = new @@ -5940,7 +6062,8 @@ class MyCompiler: public Compiler { unsigned base = frameBase(&c); c.frameResources[base + c.arch->returnAddressOffset()].reserved = true; - c.frameResources[base + c.arch->framePointerOffset()].reserved = true; + c.frameResources[base + c.arch->framePointerOffset()].reserved + = UseFramePointer; // leave room for logical instruction -1 unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1); @@ -6100,14 +6223,7 @@ class MyCompiler: public Compiler { } virtual Operand* register_(int number) { - assert(&c, (1 << number) & (c.arch->generalRegisterMask() - | c.arch->floatRegisterMask())); - - Site* s = registerSite(&c, number); - ValueType type = ((1 << number) & c.arch->floatRegisterMask()) - ? ValueFloat: ValueGeneral; - - return value(&c, type, s, s); + return local::register_(&c, number); } Promise* machineIp() { @@ -6347,8 +6463,8 @@ class MyCompiler: public Compiler { virtual void checkBounds(Operand* object, unsigned lengthOffset, Operand* index, intptr_t handler) { - appendBoundsCheck(&c, static_cast(object), - lengthOffset, static_cast(index), handler); + appendBoundsCheck(&c, static_cast(object), lengthOffset, + static_cast(index), handler); } virtual void store(unsigned srcSize, Operand* src, unsigned dstSize, @@ -6768,8 +6884,11 @@ class MyCompiler: public Compiler { appendBarrier(&c, StoreLoadBarrier); } - virtual unsigned compile() { - return c.machineCodeSize = local::compile(&c); + virtual unsigned compile(uintptr_t stackOverflowHandler, + unsigned stackLimitOffset) + { + return c.machineCodeSize = local::compile + (&c, stackOverflowHandler, stackLimitOffset); } virtual unsigned poolSize() { diff --git a/src/compiler.h b/src/compiler.h index d4484c719e..282941b722 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -30,7 +30,7 @@ class Compiler { virtual intptr_t getThunk(BinaryOperation op, unsigned size, unsigned resultSize) = 0; virtual intptr_t getThunk(TernaryOperation op, unsigned size, - unsigned resultSize) = 0; + unsigned resultSize, bool* threadParameter) = 0; }; static const unsigned Aligned = 1 << 0; @@ -188,7 +188,8 @@ class Compiler { virtual void storeStoreBarrier() = 0; virtual void storeLoadBarrier() = 0; - virtual unsigned compile() = 0; + virtual unsigned compile(uintptr_t stackOverflowHandler, + unsigned stackLimitOffset) = 0; virtual unsigned poolSize() = 0; virtual void writeTo(uint8_t* dst) = 0; diff --git a/src/continuations-x86.S b/src/continuations-x86.S index c55679d0ba..af2b399ea0 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 2224 +#define THREAD_CONTINUATION 2240 #define THREAD_EXCEPTION 80 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232 -#define THREAD_EXCEPTION_OFFSET 2240 -#define THREAD_EXCEPTION_HANDLER 2248 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2248 +#define THREAD_EXCEPTION_OFFSET 2256 +#define THREAD_EXCEPTION_HANDLER 2264 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 @@ -59,11 +59,13 @@ LOCAL(vmInvoke_continuationTest): #endif movq %r10,(%rsp,%rdi,1) +#ifdef AVIAN_USE_FRAME_POINTER // save the current base pointer in the frame and update it movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi movq %rbp,(%rsp,%rdi,1) addq %rsp,%rdi movq %rdi,%rbp +#endif // consume the continuation movq CONTINUATION_NEXT(%rcx),%rdi @@ -89,11 +91,11 @@ LOCAL(vmInvoke_exit): #elif defined __i386__ -#define THREAD_CONTINUATION 2148 +#define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 -#define THREAD_EXCEPTION_OFFSET 2156 -#define THREAD_EXCEPTION_HANDLER 2160 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 +#define THREAD_EXCEPTION_OFFSET 2164 +#define THREAD_EXCEPTION_HANDLER 2168 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 @@ -151,11 +153,13 @@ LOCAL(vmInvoke_offset): #endif movl %esi,(%esp,%edi,1) +#ifdef AVIAN_USE_FRAME_POINTER // save the current base pointer in the frame and update it movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi movl %ebp,(%esp,%edi,1) addl %esp,%edi movl %edi,%ebp +#endif // consume the continuation movl CONTINUATION_NEXT(%ecx),%edi diff --git a/src/finder.cpp b/src/finder.cpp index ae784eb48c..b0e25ef82a 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,20 +10,22 @@ #include "zlib-custom.h" #include "system.h" +#include "tokenizer.h" #include "finder.h" using namespace vm; namespace { +const bool DebugFind = false; + const char* -append(System* s, const char* a, const char* b, - const char* c) +append(Allocator* allocator, const char* a, const char* b, const char* c) { unsigned al = strlen(a); unsigned bl = strlen(b); unsigned cl = strlen(c); - char* p = static_cast(allocate(s, (al + bl + cl) + 1)); + char* p = static_cast(allocator->allocate((al + bl + cl) + 1)); memcpy(p, a, al); memcpy(p + al, b, bl); memcpy(p + al + bl, c, cl + 1); @@ -31,10 +33,10 @@ append(System* s, const char* a, const char* b, } const char* -copy(System* s, const char* a) +copy(Allocator* allocator, const char* a) { unsigned al = strlen(a); - char* p = static_cast(allocate(s, al + 1)); + char* p = static_cast(allocator->allocate(al + 1)); memcpy(p, a, al + 1); return p; } @@ -61,7 +63,8 @@ class Element { virtual Iterator* iterator() = 0; virtual System::Region* find(const char* name) = 0; - virtual bool exists(const char* name) = 0; + virtual System::FileType stat(const char* name, unsigned* length, + bool tryDirectory) = 0; virtual void dispose() = 0; Element* next; @@ -71,8 +74,9 @@ class DirectoryElement: public Element { public: class Iterator: public Element::Iterator { public: - Iterator(System* s, const char* name, unsigned skip): - s(s), name(name), skip(skip), directory(0), last(0), it(0) + Iterator(System* s, Allocator* allocator, const char* name, unsigned skip): + s(s), allocator(allocator), name(name), skip(skip), directory(0), + last(0), it(0) { if (not s->success(s->open(&directory, name))) { directory = 0; @@ -91,15 +95,17 @@ class DirectoryElement: public Element { } if (last) { - s->free(last); + allocator->free(last, strlen(last) + 1); } if (directory) { for (const char* v = directory->next(); v; v = directory->next()) { if (v[0] != '.') { - last = append(s, name, "/", v); - if (s->identify(last) == System::TypeDirectory) { - it = new (allocate(s, sizeof(Iterator))) Iterator(s, last, skip); + last = append(allocator, name, "/", v); + unsigned length; + if (s->stat(last, &length) == System::TypeDirectory) { + it = new (allocator->allocate(sizeof(Iterator))) + Iterator(s, allocator, last, skip); it->name = last; } const char* result = last + skip; @@ -114,10 +120,11 @@ class DirectoryElement: public Element { virtual void dispose() { directory->dispose(); - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; const char* name; unsigned skip; System::Directory* directory; @@ -125,48 +132,57 @@ class DirectoryElement: public Element { Iterator* it; }; - DirectoryElement(System* s, const char* name): - s(s), name(name) + DirectoryElement(System* s, Allocator* allocator, const char* name): + s(s), allocator(allocator), name(name) { } virtual Element::Iterator* iterator() { - return new (allocate(s, sizeof(Iterator))) - Iterator(s, name, strlen(name) + 1); + return new (allocator->allocate(sizeof(Iterator))) + Iterator(s, allocator, name, strlen(name) + 1); } virtual System::Region* find(const char* name) { - const char* file = append(s, this->name, "/", name); + const char* file = append(allocator, this->name, "/", name); System::Region* region; System::Status status = s->map(®ion, file); - s->free(file); + allocator->free(file, strlen(file) + 1); if (s->success(status)) { + if (DebugFind) { + fprintf(stderr, "found %s in %s\n", name, this->name); + } return region; } else { + if (DebugFind) { + fprintf(stderr, "%s not found in %s\n", name, this->name); + } return 0; } } - virtual bool exists(const char* name) { - const char* file = append(s, this->name, "/", name); - System::FileType type = s->identify(file); - s->free(file); - return type != System::TypeDoesNotExist; + virtual System::FileType stat(const char* name, unsigned* length, bool) { + const char* file = append(allocator, this->name, "/", name); + System::FileType type = s->stat(file, length); + allocator->free(file, strlen(file) + 1); + return type; } virtual void dispose() { - s->free(name); - s->free(this); + allocator->free(name, strlen(name) + 1); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; const char* name; }; class PointerRegion: public System::Region { public: - PointerRegion(System* s, const uint8_t* start, size_t length): + PointerRegion(System* s, Allocator* allocator, const uint8_t* start, + size_t length): s(s), + allocator(allocator), start_(start), length_(length) { } @@ -180,18 +196,20 @@ class PointerRegion: public System::Region { } virtual void dispose() { - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; const uint8_t* start_; size_t length_; }; class DataRegion: public System::Region { public: - DataRegion(System* s, size_t length): + DataRegion(System* s, Allocator* allocator, size_t length): s(s), + allocator(allocator), length_(length) { } @@ -204,10 +222,11 @@ class DataRegion: public System::Region { } virtual void dispose() { - s->free(this); + allocator->free(this, sizeof(*this) + length_); } System* s; + Allocator* allocator; size_t length_; uint8_t data[0]; }; @@ -233,11 +252,12 @@ class JarIndex { Node* next; }; - JarIndex(System* s, unsigned capacity): + JarIndex(System* s, Allocator* allocator, unsigned capacity): s(s), + allocator(allocator), capacity(capacity), position(0), - nodes(static_cast(allocate(s, sizeof(Node) * capacity))) + nodes(static_cast(allocator->allocate(sizeof(Node) * capacity))) { memset(table, 0, sizeof(Node*) * capacity); } @@ -314,14 +334,16 @@ class JarIndex { commentFieldLength(p); } - static JarIndex* make(System* s, unsigned capacity) { + static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) { return new - (allocate(s, sizeof(JarIndex) + (sizeof(Node*) * capacity))) - JarIndex(s, capacity); + (allocator->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity))) + JarIndex(s, allocator, capacity); } - static JarIndex* open(System* s, System::Region* region) { - JarIndex* index = make(s, 32); + static JarIndex* open(System* s, Allocator* allocator, + System::Region* region) + { + JarIndex* index = make(s, allocator, 32); const uint8_t* start = region->start(); const uint8_t* end = start + region->length(); @@ -354,7 +376,7 @@ class JarIndex { table[i] = new (nodes + (position++)) Node(hash, entry, table[i]); return this; } else { - JarIndex* index = make(s, capacity * 2); + JarIndex* index = make(s, allocator, capacity * 2); for (unsigned i = 0; i < capacity; ++i) { index->add(nodes[i].hash, nodes[i].entry); } @@ -382,15 +404,15 @@ class JarIndex { const uint8_t* p = n->entry; switch (compressionMethod(p)) { case Stored: { - return new (allocate(s, sizeof(PointerRegion))) - PointerRegion(s, fileData(start + localHeaderOffset(p)), + return new (allocator->allocate(sizeof(PointerRegion))) + PointerRegion(s, allocator, fileData(start + localHeaderOffset(p)), compressedSize(p)); } break; case Deflated: { DataRegion* region = new - (allocate(s, sizeof(DataRegion) + uncompressedSize(p))) - DataRegion(s, uncompressedSize(p)); + (allocator->allocate(sizeof(DataRegion) + uncompressedSize(p))) + DataRegion(s, allocator, uncompressedSize(p)); z_stream zStream; memset(&zStream, 0, sizeof(z_stream)); @@ -420,16 +442,41 @@ class JarIndex { return 0; } - bool exists(const char* name) { - return findNode(name) != 0; + System::FileType stat(const char* name, unsigned* length, bool tryDirectory) + { + Node* node = findNode(name); + if (node) { + *length = uncompressedSize(node->entry); + return System::TypeFile; + } else if (tryDirectory) { + *length = 0; + + // try again with '/' appended + unsigned length = strlen(name); + RUNTIME_ARRAY(char, n, length + 2); + memcpy(RUNTIME_ARRAY_BODY(n), name, length); + RUNTIME_ARRAY_BODY(n)[length] = '/'; + RUNTIME_ARRAY_BODY(n)[length + 1] = 0; + + node = findNode(RUNTIME_ARRAY_BODY(n)); + if (node) { + return System::TypeDirectory; + } else { + return System::TypeDoesNotExist; + } + } else { + *length = 0; + return System::TypeDoesNotExist; + } } void dispose() { - s->free(nodes); - s->free(this); + allocator->free(nodes, sizeof(Node) * capacity); + allocator->free(this, sizeof(*this) + (sizeof(Node*) * capacity)); } System* s; + Allocator* allocator; unsigned capacity; unsigned position; @@ -441,7 +488,9 @@ class JarElement: public Element { public: class Iterator: public Element::Iterator { public: - Iterator(System* s, JarIndex* index): s(s), index(index), position(0) { } + Iterator(System* s, Allocator* allocator, JarIndex* index): + s(s), allocator(allocator), index(index), position(0) + { } virtual const char* next(unsigned* size) { if (position < index->position) { @@ -454,22 +503,34 @@ class JarElement: public Element { } virtual void dispose() { - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; JarIndex* index; unsigned position; }; - JarElement(System* s, const char* name): - s(s), name(name), region(0), index(0) + JarElement(System* s, Allocator* allocator, const char* name): + s(s), allocator(allocator), name(name), region(0), index(0) + { } + + JarElement(System* s, Allocator* allocator, const uint8_t* jarData, + unsigned jarLength): + s(s), + allocator(allocator), + name(0), + region(new (allocator->allocate(sizeof(PointerRegion))) + PointerRegion(s, allocator, jarData, jarLength)), + index(JarIndex::open(s, allocator, region)) { } virtual Element::Iterator* iterator() { init(); - return new (allocate(s, sizeof(Iterator))) Iterator(s, index); + return new (allocator->allocate(sizeof(Iterator))) + Iterator(s, allocator, index); } virtual void init() { @@ -477,7 +538,7 @@ class JarElement: public Element { System::Region* r; if (s->success(s->map(&r, name))) { region = r; - index = JarIndex::open(s, r); + index = JarIndex::open(s, allocator, r); } } } @@ -487,29 +548,45 @@ class JarElement: public Element { while (*name == '/') name++; - return (index ? index->find(name, region->start()) : 0); + System::Region* r = (index ? index->find(name, region->start()) : 0); + if (DebugFind) { + if (r) { + fprintf(stderr, "found %s in %s\n", name, this->name); + } else { + fprintf(stderr, "%s not found in %s\n", name, this->name); + } + } + return r; } - virtual bool exists(const char* name) { + virtual System::FileType stat(const char* name, unsigned* length, + bool tryDirectory) + { init(); while (*name == '/') name++; - return (index ? index->exists(name) : 0); + return (index ? index->stat(name, length, tryDirectory) + : System::TypeDoesNotExist); } virtual void dispose() { - s->free(name); + dispose(sizeof(*this)); + } + + virtual void dispose(unsigned size) { + allocator->free(name, strlen(name) + 1); if (index) { index->dispose(); } if (region) { region->dispose(); } - s->free(this); + allocator->free(this, size); } System* s; + Allocator* allocator; const char* name; System::Region* region; JarIndex* index; @@ -517,14 +594,15 @@ class JarElement: public Element { class BuiltinElement: public JarElement { public: - BuiltinElement(System* s, const char* name, const char* libraryName): - JarElement(s, name), - libraryName(libraryName ? copy(s, libraryName) : 0) + BuiltinElement(System* s, Allocator* allocator, const char* name, + const char* libraryName): + JarElement(s, allocator, name), + libraryName(libraryName ? copy(allocator, libraryName) : 0) { } virtual void init() { if (index == 0) { - if (s->success(s->load(&library, libraryName, false))) { + if (s->success(s->load(&library, libraryName))) { void* p = library->resolve(name); if (p) { uint8_t* (*function)(unsigned*); @@ -533,9 +611,9 @@ class BuiltinElement: public JarElement { unsigned size; uint8_t* data = function(&size); if (data) { - region = new (allocate(s, sizeof(PointerRegion))) - PointerRegion(s, data, size); - index = JarIndex::open(s, region); + region = new (allocator->allocate(sizeof(PointerRegion))) + PointerRegion(s, allocator, data, size); + index = JarIndex::open(s, allocator, region); } } } @@ -544,8 +622,10 @@ class BuiltinElement: public JarElement { virtual void dispose() { library->disposeAll(); - s->free(libraryName); - JarElement::dispose(); + if (libraryName) { + allocator->free(libraryName, strlen(libraryName) + 1); + } + JarElement::dispose(sizeof(*this)); } System::Library* library; @@ -553,35 +633,9 @@ class BuiltinElement: public JarElement { }; Element* -parsePath(System* s, const char* path, const char* bootLibrary) +parsePath(System* s, Allocator* allocator, const char* path, + const char* bootLibrary) { - class Tokenizer { - public: - class Token { - public: - Token(const char* s, unsigned length): s(s), length(length) { } - - const char* s; - unsigned length; - }; - - Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } - - bool hasMore() { - while (*s == delimiter) ++s; - return *s; - } - - Token next() { - const char* p = s; - while (*s and *s != delimiter) ++s; - return Token(p, s - p); - } - - const char* s; - char delimiter; - }; - Element* first = 0; Element* prev = 0; for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { @@ -589,34 +643,40 @@ parsePath(System* s, const char* path, const char* bootLibrary) Element* e; if (*token.s == '[' and token.s[token.length - 1] == ']') { - char* name = static_cast(allocate(s, token.length - 1)); + char* name = static_cast(allocator->allocate(token.length - 1)); memcpy(name, token.s + 1, token.length - 1); name[token.length - 2] = 0; - e = new (allocate(s, sizeof(BuiltinElement))) - BuiltinElement(s, name, bootLibrary); + e = new (allocator->allocate(sizeof(BuiltinElement))) + BuiltinElement(s, allocator, name, bootLibrary); } else { - char* name = static_cast(allocate(s, token.length + 1)); + char* name = static_cast(allocator->allocate(token.length + 1)); memcpy(name, token.s, token.length); name[token.length] = 0; - switch (s->identify(name)) { + unsigned length; + switch (s->stat(name, &length)) { case System::TypeFile: { - e = new (allocate(s, sizeof(JarElement))) JarElement(s, name); + e = new (allocator->allocate(sizeof(JarElement))) + JarElement(s, allocator, name); } break; case System::TypeDirectory: { - e = new (allocate(s, sizeof(DirectoryElement))) - DirectoryElement(s, name); + e = new (allocator->allocate(sizeof(DirectoryElement))) + DirectoryElement(s, allocator, name); } break; default: { - s->free(name); + allocator->free(name, strlen(name) + 1); e = 0; } break; } } + if (DebugFind) { + fprintf(stderr, "add element %.*s %p\n", token.length, token.s, e); + } + if (e) { if (prev) { prev->next = e; @@ -632,8 +692,9 @@ parsePath(System* s, const char* path, const char* bootLibrary) class MyIterator: public Finder::IteratorImp { public: - MyIterator(System* s, Element* path): - s(s), e(path ? path->next : 0), it(path ? path->iterator() : 0) + MyIterator(System* s, Allocator* allocator, Element* path): + s(s), allocator(allocator), e(path ? path->next : 0), + it(path ? path->iterator() : 0) { } virtual const char* next(unsigned* size) { @@ -656,25 +717,37 @@ class MyIterator: public Finder::IteratorImp { virtual void dispose() { if (it) it->dispose(); - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; Element* e; Element::Iterator* it; }; class MyFinder: public Finder { public: - MyFinder(System* system, const char* path, const char* bootLibrary): + MyFinder(System* system, Allocator* allocator, const char* path, + const char* bootLibrary): system(system), - path_(parsePath(system, path, bootLibrary)), - pathString(copy(system, path)) + allocator(allocator), + path_(parsePath(system, allocator, path, bootLibrary)), + pathString(copy(allocator, path)) + { } + + MyFinder(System* system, Allocator* allocator, const uint8_t* jarData, + unsigned jarLength): + system(system), + allocator(allocator), + path_(new (allocator->allocate(sizeof(JarElement))) + JarElement(system, allocator, jarData, jarLength)), + pathString(0) { } virtual IteratorImp* iterator() { - return new (allocate(system, sizeof(MyIterator))) - MyIterator(system, path_); + return new (allocator->allocate(sizeof(MyIterator))) + MyIterator(system, allocator, path_); } virtual System::Region* find(const char* name) { @@ -688,14 +761,17 @@ class MyFinder: public Finder { return 0; } - virtual bool exists(const char* name) { + virtual System::FileType stat(const char* name, unsigned* length, + bool tryDirectory) + { for (Element* e = path_; e; e = e->next) { - if (e->exists(name)) { - return true; + System::FileType type = e->stat(name, length, tryDirectory); + if (type != System::TypeDoesNotExist) { + return type; } } - return false; + return System::TypeDoesNotExist; } virtual const char* path() { @@ -708,11 +784,12 @@ class MyFinder: public Finder { e = e->next; t->dispose(); } - system->free(pathString); - system->free(this); + allocator->free(pathString, strlen(pathString) + 1); + allocator->free(this, sizeof(*this)); } System* system; + Allocator* allocator; Element* path_; const char* pathString; }; @@ -722,9 +799,16 @@ class MyFinder: public Finder { namespace vm { Finder* -makeFinder(System* s, const char* path, const char* bootLibrary) +makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary) { - return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path, bootLibrary); + return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary); +} + +Finder* +makeFinder(System* s, Allocator* a, const uint8_t* jarData, unsigned jarLength) +{ + return new (a->allocate(sizeof(MyFinder))) + MyFinder(s, a, jarData, jarLength); } } // namespace vm diff --git a/src/finder.h b/src/finder.h index 4cd1256baf..203abb49e3 100644 --- a/src/finder.h +++ b/src/finder.h @@ -60,13 +60,19 @@ class Finder { virtual IteratorImp* iterator() = 0; virtual System::Region* find(const char* name) = 0; - virtual bool exists(const char* name) = 0; + virtual System::FileType stat(const char* name, + unsigned* length, + bool tryDirectory = false) = 0; virtual const char* path() = 0; virtual void dispose() = 0; }; Finder* -makeFinder(System* s, const char* path, const char* bootLibrary); +makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary); + +Finder* +makeFinder(System* s, Allocator* a, const uint8_t* jarData, + unsigned jarLength); } // namespace vm diff --git a/src/gnu.cpp b/src/gnu.cpp deleted file mode 100644 index 84e7193ee6..0000000000 --- a/src/gnu.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* 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. */ - -#include "machine.h" -#include "constants.h" -#include "processor.h" -#include "util.h" - -using namespace vm; - -namespace { - -void -setProperty(Thread* t, object method, object properties, - const char* name, const void* value, const char* format = "%s") -{ - PROTECT(t, method); - PROTECT(t, properties); - - object n = makeString(t, "%s", name); - PROTECT(t, n); - - object v = makeString(t, format, value); - - t->m->processor->invoke(t, method, properties, n, v); -} - -} // namespace - -namespace vm { - -jobject JNICALL -NewDirectByteBuffer(Thread* t, void* address, jlong capacity) -{ - const char* pointerClassName; - const char* initSpec; - if (BytesPerWord == 8) { - pointerClassName = "gnu/classpath/Pointer64"; - initSpec = "(J)V"; - } else { - pointerClassName = "gnu/classpath/Pointer32"; - initSpec = "(I)V"; - } - - object pointerClass = resolveClass(t, t->m->loader, pointerClassName); - if (UNLIKELY(pointerClass == 0)) return 0; - PROTECT(t, pointerClass); - - object pointerConstructor = resolveMethod - (t, pointerClass, "", initSpec); - if (UNLIKELY(pointerConstructor == 0)) return 0; - - object pointer = make(t, pointerClass); - PROTECT(t, pointer); - - t->m->processor->invoke(t, pointerConstructor, pointer, address); - if (UNLIKELY(t->exception)) return 0; - - object bufferClass = resolveClass - (t, t->m->loader, "java/nio/DirectByteBufferImpl$ReadWrite"); - if (UNLIKELY(bufferClass == 0)) return 0; - PROTECT(t, bufferClass); - - object bufferConstructor = resolveMethod - (t, bufferClass, "", "(Lgnu/classpath/Pointer;int)V"); - if (UNLIKELY(bufferConstructor == 0)) return 0; - - object buffer = make(t, bufferClass); - PROTECT(t, buffer); - - t->m->processor->invoke - (t, bufferConstructor, buffer, &pointer, static_cast(capacity)); - if (UNLIKELY(t->exception)) return 0; - - return makeLocalReference(t, buffer); -} - -void* JNICALL -GetDirectBufferAddress(Thread* t, jobject buffer) -{ - object addressField = resolveField - (t, objectClass(t, *buffer), "address", "Lgnu/classpath/Pointer;"); - if (UNLIKELY(addressField == 0)) return 0; - - object address = cast(*buffer, fieldOffset(t, addressField)); - if (address == 0) return 0; - - const char* dataSpec; - if (BytesPerWord == 8) { - dataSpec = "J"; - } else { - dataSpec = "I"; - } - - object dataField = resolveField - (t, objectClass(t, address), "data", dataSpec); - if (UNLIKELY(dataField == 0)) return 0; - - return cast(address, fieldOffset(t, dataField)); -} - -jlong JNICALL -GetDirectBufferCapacity(Thread* t, jobject buffer) -{ - object capField = resolveField(t, objectClass(t, *buffer), "cap", "I"); - if (UNLIKELY(capField == 0)) return 0; - - return cast(*buffer, fieldOffset(t, capField)); -} - -} // namespace vm - -extern "C" JNIEXPORT void JNICALL -Avian_gnu_classpath_VMSystemProperties_preInit -(Thread* t, object, uintptr_t* arguments) -{ - object properties = reinterpret_cast(arguments[0]); - PROTECT(t, properties); - - object method = resolveMethod - (t, t->m->loader, "java/util/Properties", "setProperty", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); - - if (UNLIKELY(t->exception)) { - return; - } - - PROTECT(t, method); - - setProperty(t, method, properties, "java.version", "1.5"); - setProperty(t, method, properties, "java.specification.version", "1.5"); - - setProperty(t, method, properties, "java.vm.name", "Avian"); - - setProperty(t, method, properties, "java.protocol.handler.pkgs", "avian"); - - setProperty(t, method, properties, "file.encoding", "ASCII"); - - // specify a bogus library path so we can do our own search in - // VMRuntime.nativeLoad: -#define LIBRARY_PATH_SENTINAL "*" - setProperty(t, method, properties, "java.library.path", - LIBRARY_PATH_SENTINAL); - -#ifdef PLATFORM_WINDOWS -# define FILE_SEPARATOR "\\" - - setProperty(t, method, properties, "line.separator", "\r\n"); - setProperty(t, method, properties, "file.separator", FILE_SEPARATOR); - setProperty(t, method, properties, "path.separator", ";"); - setProperty(t, method, properties, "os.name", "Windows"); - - TCHAR buffer[MAX_PATH]; - GetTempPath(MAX_PATH, buffer); - setProperty(t, method, properties, "java.io.tmpdir", buffer); - setProperty(t, method, properties, "java.home", buffer); - - setProperty(t, method, properties, "user.home", - _wgetenv(L"USERPROFILE"), "%ls"); - - GetCurrentDirectory(MAX_PATH, buffer); - setProperty(t, method, properties, "user.dir", buffer); -#else -# define FILE_SEPARATOR "/" - - setProperty(t, method, properties, "line.separator", "\n"); - setProperty(t, method, properties, "file.separator", FILE_SEPARATOR); - setProperty(t, method, properties, "path.separator", ":"); -# ifdef __APPLE__ - setProperty(t, method, properties, "os.name", "Mac OS X"); -# else - setProperty(t, method, properties, "os.name", "Linux"); -# endif - setProperty(t, method, properties, "java.io.tmpdir", "/tmp"); - setProperty(t, method, properties, "java.home", "/tmp"); - setProperty(t, method, properties, "user.home", getenv("HOME")); - setProperty(t, method, properties, "user.dir", getenv("PWD")); -#endif - -#ifdef ARCH_x86_32 - setProperty(t, method, properties, "gnu.cpu.endian", "little"); - setProperty(t, method, properties, "os.arch", "x86"); -#elif defined ARCH_x86_64 - setProperty(t, method, properties, "gnu.cpu.endian", "little"); - setProperty(t, method, properties, "os.arch", "x86_64"); -#elif defined ARCH_powerpc - setProperty(t, method, properties, "gnu.cpu.endian", "big"); - setProperty(t, method, properties, "os.arch", "ppc"); -#elif defined ARCH_arm - setProperty(t, method, properties, "os.arch", "arm"); -#else - setProperty(t, method, properties, "os.arch", "unknown"); -#endif -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_gnu_classpath_VMStackWalker_getClassContext -(Thread* t, object, uintptr_t*) -{ - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t): - t(t), skipCount(1), trace(0), index(0), protector(t, &trace) - { } - - virtual bool visit(Processor::StackWalker* walker) { - if (skipCount == 0) { - if (trace == 0) { - trace = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), - walker->count()); - } - - assert(t, index < objectArrayLength(t, trace)); - - set(t, trace, ArrayBody + (index * BytesPerWord), - methodClass(t, walker->method())); - - ++ index; - return true; - } else { - -- skipCount; - return true; - } - } - - Thread* t; - unsigned skipCount; - object trace; - unsigned index; - Thread::SingleProtector protector; - } v(t); - - t->m->processor->walkStack(t, &v); - - if (v.trace == 0) { - v.trace = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), 0); - } - - return reinterpret_cast(v.trace); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_gnu_classpath_VMStackWalker_getClassLoader -(Thread* t, object, uintptr_t* arguments) -{ - return reinterpret_cast - (classLoader(t, reinterpret_cast(arguments[0]))); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMRuntime_mapLibraryName -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - PROTECT(t, name); - - const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1; - const unsigned nameLength = stringLength(t, name); - const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1; - const unsigned total = soPrefixLength + nameLength + soSuffixLength; - - object s = makeByteArray(t, total + 1); - char* p = reinterpret_cast(&byteArrayBody(t, s, 0)); - - memcpy(p, SO_PREFIX, soPrefixLength); - stringChars(t, name, p + soPrefixLength); - memcpy(p + soPrefixLength + nameLength, SO_SUFFIX, soSuffixLength); - p[total] = 0; - - return reinterpret_cast(makeString(t, s, 0, total, 0)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_System_arraycopy -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMSystem_arraycopy -(Thread* t, object, uintptr_t* arguments) -{ - Avian_java_lang_System_arraycopy(t, 0, arguments); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_load -(Thread* t, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMRuntime_nativeLoad -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - - // given that we set java.library.path to LIBRARY_PATH_SENTINAL, we - // can determine which names are filenames and which are library - // names by looking for the prefix LIBRARY_PATH_SENTINAL - // FILE_SEPARATOR - - unsigned length = stringLength(t, name); - char n[length + 1]; - stringChars(t, name, n); - - const unsigned pathPrefixLength - = sizeof(LIBRARY_PATH_SENTINAL) - 1 - + sizeof(FILE_SEPARATOR) - 1; - - bool mapName = (strncmp(n, LIBRARY_PATH_SENTINAL FILE_SEPARATOR, - pathPrefixLength) == 0); - if (mapName) { - // strip the path prefix, SO prefix, and SO suffix before passing - // the name to Runtime.load - - const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1; - const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1; - const unsigned newOffset - = stringOffset(t, name) + pathPrefixLength + soPrefixLength; - const unsigned newLength - = length - pathPrefixLength - soPrefixLength - soSuffixLength; - - name = makeString(t, stringData(t, name), newOffset, newLength, 0); - } - - uintptr_t args[] = { reinterpret_cast(name), mapName }; - - Avian_java_lang_Runtime_load(t, 0, args); - - if (t->exception) { - t->exception = 0; - return 0; - } else { - return 1; - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_primitiveClass -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_getPrimitiveClass -(Thread* t, object, uintptr_t* arguments) -{ - return Avian_java_lang_Class_primitiveClass(t, 0, arguments); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_defineClass -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_defineClass -(Thread* t, object, uintptr_t* arguments) -{ - uintptr_t args[] - = { arguments[0], arguments[2], arguments[3], arguments[4] }; - -// object name = reinterpret_cast(arguments[1]); -// char n[stringLength(t, name) + 1]; -// stringChars(t, name, n); -// fprintf(stderr, "define class %s in %p\n", n, -// reinterpret_cast(arguments[0])); - - return Avian_avian_SystemClassLoader_defineClass(t, 0, args); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_System_identityHashCode -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMSystem_identityHashCode -(Thread* t, object, uintptr_t* arguments) -{ - return Avian_java_lang_System_identityHashCode(t, 0, arguments); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_gc -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMRuntime_gc -(Thread* t, object, uintptr_t*) -{ - Avian_java_lang_Runtime_gc(t, 0, 0); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMRuntime_runFinalizationForExit -(Thread*, object, uintptr_t*) -{ - // ignore -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMRuntime_exit -(Thread*, object, uintptr_t* arguments) -{ - exit(arguments[0]); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_findClass -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_loadClass -(Thread* t, object, uintptr_t* arguments) -{ - uintptr_t args[] = { 0, arguments[0] }; - - // object name = reinterpret_cast(arguments[0]); - // char n[stringLength(t, name) + 1]; - // stringChars(t, name, n); - // fprintf(stderr, "load bootstrap class %s in %p\n", n, t->m->loader); - - int64_t result = Avian_avian_SystemClassLoader_findClass(t, 0, args); - - // fprintf(stderr, "result %p\n", reinterpret_cast(result)); - - return result; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMClassLoader_resolveClass -(Thread*, object, uintptr_t*) -{ - // ignore -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_findLoadedClass -(Thread* t, object, uintptr_t* arguments) -{ - object loader = reinterpret_cast(arguments[0]); - - object map = getClassLoaderMap(t, loader); - if (map) { - PROTECT(t, loader); - - object name = reinterpret_cast(arguments[1]); - PROTECT(t, name); - - object n = makeByteArray(t, stringLength(t, name) + 1); - char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); - stringChars(t, name, s); - - replace('.', '/', s); - - return reinterpret_cast - (hashMapFind - (t, getClassLoaderMap(t, loader), n, byteArrayHash, byteArrayEqual)); - } else { - return 0; - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_compareAndSwapInt -(Thread*, object, uintptr_t* arguments) -{ - object target = reinterpret_cast(arguments[1]); - int64_t offset; memcpy(&offset, arguments + 2, 8); - int32_t expect = arguments[4]; - int32_t update = arguments[5]; - - return __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_compareAndSwapLong -(Thread*, object, uintptr_t* arguments) -{ - object target = reinterpret_cast(arguments[1]); - int64_t offset; memcpy(&offset, arguments + 2, 8); - int64_t expect; memcpy(&expect, arguments + 4, 8); - int64_t update; memcpy(&update, arguments + 6, 8); - - return __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_objectFieldOffset -(Thread* t, object, uintptr_t* arguments) -{ - return fieldOffset(t, reinterpret_cast(arguments[1])); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8 -(Thread*, object, uintptr_t*) -{ - return 0; -} diff --git a/src/heap.cpp b/src/heap.cpp index 718d2885a0..02e0e99a19 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -68,6 +68,7 @@ void assert(Context*, bool); System* system(Context*); void* tryAllocate(Context* c, unsigned size); +void* allocate(Context* c, unsigned size); void free(Context* c, const void* p, unsigned size); #ifdef USE_ATOMIC_OPERATIONS @@ -359,7 +360,9 @@ class Segment { break; } } else { - abort(context); + data = static_cast + (local::allocate + (context, (footprint(capacity_)) * BytesPerWord)); } } } @@ -1708,7 +1711,8 @@ collect(Context* c) } } -void* tryAllocate(Context* c, unsigned size) +void* +allocate(Context* c, unsigned size, bool limit) { ACQUIRE(c->lock); @@ -1716,7 +1720,7 @@ void* tryAllocate(Context* c, unsigned size) size = pad(size) + 2 * BytesPerWord; } - if (size + c->count < c->limit) { + if ((not limit) or size + c->count < c->limit) { void* p = c->system->tryAllocate(size); if (p) { c->count += size; @@ -1733,7 +1737,21 @@ void* tryAllocate(Context* c, unsigned size) return 0; } -void free(Context* c, const void* p, unsigned size) { +void* +tryAllocate(Context* c, unsigned size) +{ + return allocate(c, size, true); +} + +void* +allocate(Context* c, unsigned size) +{ + return allocate(c, size, false); +} + +void +free(Context* c, const void* p, unsigned size) +{ ACQUIRE(c->lock); if (DebugAllocation) { @@ -1755,7 +1773,9 @@ void free(Context* c, const void* p, unsigned size) { c->count -= size; } -void free_(Context* c, const void* p, unsigned size) { +void +free_(Context* c, const void* p, unsigned size) +{ free(c, p, size); } @@ -1775,14 +1795,16 @@ class MyHeap: public Heap { c.immortalHeapEnd = start + sizeInWords; } + virtual bool limitExceeded() { + return c.count > c.limit; + } + virtual void* tryAllocate(unsigned size) { return local::tryAllocate(&c, size); } virtual void* allocate(unsigned size) { - void* p = local::tryAllocate(&c, size); - expect(c.system, p); - return p; + return local::allocate(&c, size); } virtual void free(const void* p, unsigned size) { diff --git a/src/heap.h b/src/heap.h index 769bc1ec4b..ecb60d2637 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -53,6 +53,7 @@ class Heap: public Allocator { virtual void setClient(Client* client) = 0; virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0; + virtual bool limitExceeded() = 0; virtual void collect(CollectionType type, unsigned footprint) = 0; virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask, unsigned* totalInBytes) = 0; diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 41730b0fb6..2f70e80c5f 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -76,8 +76,7 @@ dumpHeap(Thread* t, FILE* out) local::write1(out, local::Size); local::write4(out, local::objectSize(t, p)); - if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) - { + if (objectClass(t, p) == type(t, Machine::ClassType)) { object name = className(t, p); if (name) { local::write1(out, local::ClassName); diff --git a/src/interpret.cpp b/src/interpret.cpp index e63613cb54..3da5ca97d5 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -30,9 +30,6 @@ class ClassInitList; class Thread: public vm::Thread { public: - static const unsigned StackSizeInBytes = 64 * 1024; - static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; - Thread(Machine* m, object javaThread, vm::Thread* parent): vm::Thread(m, javaThread, parent), ip(0), @@ -78,7 +75,7 @@ pushObject(Thread* t, object o) fprintf(stderr, "push object %p at %d\n", o, t->sp); } - assert(t, t->sp + 1 < Thread::StackSizeInWords / 2); + assert(t, t->sp + 1 < StackSizeInWords / 2); t->stack[(t->sp * 2) ] = ObjectTag; t->stack[(t->sp * 2) + 1] = reinterpret_cast(o); ++ t->sp; @@ -91,7 +88,7 @@ pushInt(Thread* t, uint32_t v) fprintf(stderr, "push int %d at %d\n", v, t->sp); } - assert(t, t->sp + 1 < Thread::StackSizeInWords / 2); + assert(t, t->sp + 1 < StackSizeInWords / 2); t->stack[(t->sp * 2) ] = IntTag; t->stack[(t->sp * 2) + 1] = v; ++ t->sp; @@ -184,7 +181,7 @@ peekObject(Thread* t, unsigned index) index); } - assert(t, index < Thread::StackSizeInWords / 2); + assert(t, index < StackSizeInWords / 2); assert(t, t->stack[index * 2] == ObjectTag); return *reinterpret_cast(t->stack + (index * 2) + 1); } @@ -198,7 +195,7 @@ peekInt(Thread* t, unsigned index) index); } - assert(t, index < Thread::StackSizeInWords / 2); + assert(t, index < StackSizeInWords / 2); assert(t, t->stack[index * 2] == IntTag); return t->stack[(index * 2) + 1]; } @@ -254,7 +251,7 @@ inline object* pushReference(Thread* t, object o) { if (o) { - expect(t, t->sp + 1 < Thread::StackSizeInWords / 2); + expect(t, t->sp + 1 < StackSizeInWords / 2); pushObject(t, o); return reinterpret_cast(t->stack + ((t->sp - 1) * 2) + 1); } else { @@ -376,10 +373,9 @@ popFrame(Thread* t) } if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag) - and t->classInitList) + and t->classInitList + and t->classInitList->class_ == methodClass(t, method)) { - assert(t, t->classInitList->class_ == methodClass(t, method)); - t->classInitList->pop(); postInitClass(t, methodClass(t, method)); @@ -429,91 +425,6 @@ class MyStackWalker: public Processor::StackWalker { int frame; }; -object -makeNativeMethodData(Thread* t, object method, void* function) -{ - PROTECT(t, method); - - unsigned count = methodParameterCount(t, method) + 2; - - object data = makeNativeMethodData(t, - function, - 0, // argument table size - count); - - unsigned argumentTableSize = BytesPerWord * 2; - unsigned index = 0; - - nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE; - nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE; - - const char* s = reinterpret_cast - (&byteArrayBody(t, methodSpec(t, method), 0)); - ++ s; // skip '(' - while (*s and *s != ')') { - unsigned code = fieldCode(t, *s); - nativeMethodDataParameterTypes(t, data, index++) = fieldType(t, code); - - switch (*s) { - case 'L': - argumentTableSize += BytesPerWord; - while (*s and *s != ';') ++ s; - ++ s; - break; - - case '[': - argumentTableSize += BytesPerWord; - while (*s == '[') ++ s; - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - default: - ++ s; - break; - } - break; - - default: - argumentTableSize += pad(primitiveSize(t, code)); - ++ s; - break; - } - } - - nativeMethodDataArgumentTableSize(t, data) = argumentTableSize; - - return data; -} - -inline void -resolveNativeMethodData(Thread* t, object method) -{ - if (methodCode(t, method) == 0) { - void* p = resolveNativeMethod(t, method); - if (LIKELY(p)) { - PROTECT(t, method); - object data = makeNativeMethodData(t, method, p); - - // ensure other threads see updated methodVmFlags before - // methodCode, and that the native method data is initialized - // before it is visible to those threads: - storeStoreMemoryBarrier(); - - set(t, method, MethodCode, data); - } else { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = makeUnsatisfiedLinkError(t, message); - } - } -} - inline void checkStack(Thread* t, object method) { @@ -522,9 +433,9 @@ checkStack(Thread* t, object method) + codeMaxLocals(t, methodCode(t, method)) + FrameFootprint + codeMaxStack(t, methodCode(t, method)) - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + throwNew(t, Machine::StackOverflowErrorType); } } @@ -597,39 +508,47 @@ pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) } void -marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, - object data, bool indirect) +marshalArguments(Thread* t, uintptr_t* args, uint8_t* types, unsigned sp, + object method, bool fastCallingConvention) { - unsigned offset = 0; - unsigned sp = frameBase(t, t->frame); - for (; i < count; ++i) { - unsigned type = nativeMethodDataParameterTypes(t, data, i + 1); + MethodSpecIterator it + (t, reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0))); + + unsigned argOffset = 0; + unsigned typeOffset = 0; + + while (it.hasNext()) { + unsigned type = fieldType(t, fieldCode(t, *it.next())); + if (types) { + types[typeOffset++] = type; + } switch (type) { case INT8_TYPE: case INT16_TYPE: case INT32_TYPE: case FLOAT_TYPE: - args[offset++] = peekInt(t, sp++); + args[argOffset++] = peekInt(t, sp++); break; case DOUBLE_TYPE: case INT64_TYPE: { uint64_t v = peekLong(t, sp); - memcpy(args + offset, &v, 8); - offset += (8 / BytesPerWord); + memcpy(args + argOffset, &v, 8); + argOffset += fastCallingConvention ? 2 : (8 / BytesPerWord); sp += 2; } break; case POINTER_TYPE: { - if (indirect) { + if (fastCallingConvention) { + args[argOffset++] = reinterpret_cast(peekObject(t, sp++)); + } else { object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); if (*v == 0) { v = 0; } - args[offset++] = reinterpret_cast(v); - } else { - args[offset++] = reinterpret_cast(peekObject(t, sp++)); + args[argOffset++] = reinterpret_cast(v); } } break; @@ -639,39 +558,51 @@ marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, } unsigned -invokeNativeSlow(Thread* t, object method) +invokeNativeSlow(Thread* t, object method, void* function) { PROTECT(t, method); - object data = methodCode(t, method); - PROTECT(t, data); - pushFrame(t, method); - unsigned count = nativeMethodDataLength(t, data) - 1; - - unsigned size = nativeMethodDataArgumentTableSize(t, data); - uintptr_t args[size / BytesPerWord]; - unsigned offset = 0; - - args[offset++] = reinterpret_cast(t); - - unsigned i = 0; + unsigned footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { - ++ i; - args[offset++] = reinterpret_cast - (pushReference(t, methodClass(t, method))); + ++ footprint; } + unsigned count = methodParameterCount(t, method) + 2; - marshalArguments(t, args + offset, i, count, data, true); + THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); + unsigned argOffset = 0; + THREAD_RUNTIME_ARRAY(t, uint8_t, types, count); + unsigned typeOffset = 0; + + RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); + RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; + + object jclass = 0; + PROTECT(t, jclass); + + unsigned sp; + if (methodFlags(t, method) & ACC_STATIC) { + sp = frameBase(t, t->frame); + jclass = getJClass(t, methodClass(t, method)); + RUNTIME_ARRAY_BODY(args)[argOffset++] + = reinterpret_cast(&jclass); + } else { + sp = frameBase(t, t->frame); + object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); + if (*v == 0) { + v = 0; + } + RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(v); + } + RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; + + marshalArguments + (t, RUNTIME_ARRAY_BODY(args) + argOffset, + RUNTIME_ARRAY_BODY(types) + typeOffset, sp, method, false); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); - void* function = nativeMethodDataFunction(t, data); - uint8_t types[nativeMethodDataLength(t, data)]; - memcpy(&types, - &nativeMethodDataParameterTypes(t, data, 0), - nativeMethodDataLength(t, data)); uint64_t result; if (DebugRun) { @@ -679,25 +610,19 @@ invokeNativeSlow(Thread* t, object method) &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0)); } - -// if (strcmp(reinterpret_cast -// (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), -// "org/eclipse/swt/internal/C") == 0 -// and strcmp(reinterpret_cast -// (&byteArrayBody(t, methodName(t, method), 0)), -// "memmove") == 0) -// { -// asm("int3"); -// } - + { ENTER(t, Thread::IdleState); + bool noThrow = t->checkpoint->noThrow; + t->checkpoint->noThrow = true; + THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow); + result = t->m->system->call (function, - args, - types, - count + 1, - size, + RUNTIME_ARRAY_BODY(args), + RUNTIME_ARRAY_BODY(types), + count, + footprint * BytesPerWord, returnType); } @@ -712,7 +637,9 @@ invokeNativeSlow(Thread* t, object method) popFrame(t); if (UNLIKELY(t->exception)) { - return VoidField; + object exception = t->exception; + t->exception = 0; + throw_(t, exception); } pushResult(t, returnCode, result, true); @@ -725,36 +652,36 @@ invokeNative(Thread* t, object method) { PROTECT(t, method); - resolveNativeMethodData(t, method); + resolveNative(t, method); - if (UNLIKELY(t->exception)) { - return VoidField; - } - - if (methodVmFlags(t, method) & FastNative) { + object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); + if (nativeFast(t, native)) { pushFrame(t, method); - object data = methodCode(t, method); - uintptr_t arguments[methodParameterFootprint(t, method)]; - marshalArguments - (t, arguments, (methodFlags(t, method) & ACC_STATIC) ? 1 : 0, - nativeMethodDataLength(t, data) - 1, data, false); + uint64_t result; + { THREAD_RESOURCE0(t, popFrame(static_cast(t))); - uint64_t result = reinterpret_cast - (nativeMethodDataFunction(t, methodCode(t, method))) - (t, method, arguments); - - popFrame(t); + unsigned footprint = methodParameterFootprint(t, method); + RUNTIME_ARRAY(uintptr_t, args, footprint); + unsigned sp = frameBase(t, t->frame); + unsigned argOffset = 0; + if ((methodFlags(t, method) & ACC_STATIC) == 0) { + RUNTIME_ARRAY_BODY(args)[argOffset++] + = reinterpret_cast(peekObject(t, sp++)); + } - if (UNLIKELY(t->exception)) { - return VoidField; + marshalArguments + (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, true); + + result = reinterpret_cast + (nativeFunction(t, native))(t, method, RUNTIME_ARRAY_BODY(args)); } pushResult(t, methodReturnCode(t, method), result, false); return methodReturnCode(t, method); } else { - return invokeNativeSlow(t, method); + return invokeNativeSlow(t, method, nativeFunction(t, native)); } } @@ -875,10 +802,8 @@ pushField(Thread* t, object target, object field) } object -interpret(Thread* t) +interpret3(Thread* t, const int base) { - const int base = t->frame; - unsigned instruction = nop; unsigned& ip = t->ip; unsigned& sp = t->sp; @@ -931,13 +856,13 @@ interpret(Thread* t) { pushObject(t, objectArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - objectArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, objectArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -953,13 +878,13 @@ interpret(Thread* t) { set(t, array, ArrayBody + (index * BytesPerWord), value); } else { - object message = makeString(t, "%d not in [0,%d)", index, - objectArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, objectArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -995,14 +920,11 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; - pushObject(t, makeObjectArray - (t, classLoader(t, methodClass(t, frameMethod(t, frame))), - class_, count)); + pushObject(t, makeObjectArray(t, class_, count)); } else { - object message = makeString(t, "%d", count); - exception = makeNegativeArraySizeException(t, message); + exception = makeThrowable + (t, Machine::NegativeArraySizeExceptionType, "%d", count); goto throw_; } } goto loop; @@ -1023,7 +945,7 @@ interpret(Thread* t) if (LIKELY(array)) { pushInt(t, cast(array, BytesPerWord)); } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1051,7 +973,7 @@ interpret(Thread* t) case athrow: { exception = popObject(t); if (UNLIKELY(exception == 0)) { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } goto throw_; @@ -1060,18 +982,16 @@ interpret(Thread* t) object array = popObject(t); if (LIKELY(array)) { - if (objectClass(t, array) - == arrayBody(t, t->m->types, Machine::BooleanArrayType)) - { + if (objectClass(t, array) == type(t, Machine::BooleanArrayType)) { if (LIKELY(index >= 0 and static_cast(index) < booleanArrayLength(t, array))) { pushInt(t, booleanArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - booleanArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, booleanArrayLength(t, array)); goto throw_; } } else { @@ -1081,14 +1001,14 @@ interpret(Thread* t) { pushInt(t, byteArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - byteArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, byteArrayLength(t, array)); goto throw_; } } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1099,18 +1019,16 @@ interpret(Thread* t) object array = popObject(t); if (LIKELY(array)) { - if (objectClass(t, array) - == arrayBody(t, t->m->types, Machine::BooleanArrayType)) - { + if (objectClass(t, array) == type(t, Machine::BooleanArrayType)) { if (LIKELY(index >= 0 and static_cast(index) < booleanArrayLength(t, array))) { booleanArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - booleanArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, booleanArrayLength(t, array)); goto throw_; } } else { @@ -1119,14 +1037,14 @@ interpret(Thread* t) { byteArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - byteArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, byteArrayLength(t, array)); goto throw_; } } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1145,13 +1063,13 @@ interpret(Thread* t) { pushInt(t, charArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - charArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, charArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1167,13 +1085,13 @@ interpret(Thread* t) { charArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - charArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, charArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1186,12 +1104,11 @@ interpret(Thread* t) if (UNLIKELY(exception)) goto throw_; if (not instanceOf(t, class_, peekObject(t, sp - 1))) { - object message = makeString - (t, "%s as %s", + exception = makeThrowable + (t, Machine::ClassCastExceptionType, "%s as %s", &byteArrayBody (t, className(t, objectClass(t, peekObject(t, sp - 1))), 0), &byteArrayBody(t, className(t, class_), 0)); - exception = makeClassCastException(t, message); goto throw_; } } @@ -1226,13 +1143,13 @@ interpret(Thread* t) { pushLong(t, doubleArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - doubleArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, doubleArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1248,13 +1165,13 @@ interpret(Thread* t) { memcpy(&doubleArrayBody(t, array, index), &value, sizeof(uint64_t)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - doubleArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, doubleArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1426,13 +1343,13 @@ interpret(Thread* t) { pushInt(t, floatArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - floatArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, floatArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1448,13 +1365,13 @@ interpret(Thread* t) { memcpy(&floatArrayBody(t, array, index), &value, sizeof(uint32_t)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - floatArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, floatArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1540,7 +1457,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); @@ -1566,7 +1482,7 @@ interpret(Thread* t) } } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1575,7 +1491,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, fieldFlags(t, field) & ACC_STATIC); @@ -1656,13 +1571,13 @@ interpret(Thread* t) { pushInt(t, intArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - intArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, intArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1685,13 +1600,13 @@ interpret(Thread* t) { intArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - intArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, intArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1727,6 +1642,11 @@ interpret(Thread* t) case idiv: { int32_t b = popInt(t); int32_t a = popInt(t); + + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } pushInt(t, a / b); } goto loop; @@ -1931,7 +1851,6 @@ interpret(Thread* t) if (peekObject(t, sp - 1)) { object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; if (instanceOf(t, class_, popObject(t))) { pushInt(t, 1); @@ -1950,7 +1869,6 @@ interpret(Thread* t) ip += 2; object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { @@ -1958,7 +1876,7 @@ interpret(Thread* t) (t, method, objectClass(t, peekObject(t, sp - parameterFootprint))); goto invoke; } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1967,7 +1885,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { @@ -1983,7 +1900,7 @@ interpret(Thread* t) goto invoke; } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1992,7 +1909,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; PROTECT(t, method); if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke; @@ -2004,7 +1920,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { @@ -2014,7 +1929,7 @@ interpret(Thread* t) code = findVirtualMethod(t, method, class_); goto invoke; } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2030,6 +1945,11 @@ interpret(Thread* t) int32_t b = popInt(t); int32_t a = popInt(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushInt(t, a % b); } goto loop; @@ -2148,13 +2068,13 @@ interpret(Thread* t) { pushLong(t, longArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - longArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, longArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2177,13 +2097,13 @@ interpret(Thread* t) { longArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - longArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, longArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2217,14 +2137,13 @@ interpret(Thread* t) if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); - if (objectClass(t, v) - == arrayBody(t, t->m->types, Machine::ReferenceType)) - { + if (objectClass(t, v) == type(t, Machine::ReferenceType)) { object class_ = resolveClassInPool (t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; - pushObject(t, class_); + pushObject(t, getJClass(t, class_)); + } else if (objectClass(t, v) == type(t, Machine::ClassType)) { + pushObject(t, getJClass(t, v)); } else { pushObject(t, v); } @@ -2247,6 +2166,11 @@ interpret(Thread* t) int64_t b = popLong(t); int64_t a = popLong(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushLong(t, a / b); } goto loop; @@ -2329,6 +2253,11 @@ interpret(Thread* t) int64_t b = popLong(t); int64_t a = popLong(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushLong(t, a % b); } goto loop; @@ -2409,7 +2338,7 @@ interpret(Thread* t) if (LIKELY(o)) { acquire(t, o); } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2419,7 +2348,7 @@ interpret(Thread* t) if (LIKELY(o)) { release(t, o); } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2429,15 +2358,14 @@ interpret(Thread* t) uint8_t dimensions = codeBody(t, code, ip++); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; PROTECT(t, class_); int32_t counts[dimensions]; for (int i = dimensions - 1; i >= 0; --i) { counts[i] = popInt(t); if (UNLIKELY(counts[i] < 0)) { - object message = makeString(t, "%d", counts[i]); - exception = makeNegativeArraySizeException(t, message); + exception = makeThrowable + (t, Machine::NegativeArraySizeExceptionType, "%d", counts[i]); goto throw_; } } @@ -2455,7 +2383,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; PROTECT(t, class_); if (UNLIKELY(classInit(t, class_, 3))) goto invoke; @@ -2509,8 +2436,8 @@ interpret(Thread* t) pushObject(t, array); } else { - object message = makeString(t, "%d", count); - exception = makeNegativeArraySizeException(t, message); + exception = makeThrowable + (t, Machine::NegativeArraySizeExceptionType, "%d", count); goto throw_; } } goto loop; @@ -2529,7 +2456,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); PROTECT(t, field); @@ -2572,7 +2498,7 @@ interpret(Thread* t) break; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; @@ -2583,7 +2509,7 @@ interpret(Thread* t) if (LIKELY(o)) { cast(o, fieldOffset(t, field)) = value; } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; @@ -2593,7 +2519,7 @@ interpret(Thread* t) if (LIKELY(o)) { set(t, o, fieldOffset(t, field), value); } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; @@ -2620,7 +2546,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, fieldFlags(t, field) & ACC_STATIC); @@ -2721,13 +2646,13 @@ interpret(Thread* t) { pushInt(t, shortArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - shortArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, shortArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2743,13 +2668,13 @@ interpret(Thread* t) { shortArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - shortArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, shortArrayLength(t, array)); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2807,7 +2732,6 @@ interpret(Thread* t) resolveClass(t, classLoader(t, methodClass(t, frameMethod(t, frame))), className(t, class_)); - if (UNLIKELY(exception)) goto throw_; ip -= 3; } goto loop; @@ -2827,7 +2751,7 @@ interpret(Thread* t) case iinc: { uint16_t index = codeReadInt16(t, code, ip); - uint16_t count = codeReadInt16(t, code, ip); + int16_t count = codeReadInt16(t, code, ip); setLocalInt(t, index, localInt(t, index) + count); } goto loop; @@ -2858,11 +2782,8 @@ interpret(Thread* t) invoke: { if (methodFlags(t, code) & ACC_NATIVE) { invokeNative(t, code); - if (UNLIKELY(exception)) goto throw_; } else { checkStack(t, code); - if (UNLIKELY(exception)) goto throw_; - pushFrame(t, code); } } goto loop; @@ -2887,6 +2808,39 @@ interpret(Thread* t) return 0; } +uint64_t +interpret2(vm::Thread* t, uintptr_t* arguments) +{ + int base = arguments[0]; + bool* success = reinterpret_cast(arguments[1]); + + object r = interpret3(static_cast(t), base); + *success = true; + return reinterpret_cast(r); +} + +object +interpret(Thread* t) +{ + const int base = t->frame; + + while (true) { + bool success = false; + uintptr_t arguments[] = { base, reinterpret_cast(&success) }; + + uint64_t r = run(t, interpret2, arguments); + if (success) { + if (t->exception) { + object exception = t->exception; + t->exception = 0; + throw_(t, exception); + } else { + return reinterpret_cast(r); + } + } + } +} + void pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects, va_list a) @@ -2974,7 +2928,7 @@ invoke(Thread* t, object method) class_ = objectClass(t, peekObject(t, t->sp - parameterFootprint)); if (classVmFlags(t, class_) & BootstrapFlag) { - resolveClass(t, t->m->loader, className(t, class_)); + resolveClass(t, root(t, Machine::BootLoader), className(t, class_)); } if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { @@ -2993,47 +2947,45 @@ invoke(Thread* t, object method) if (methodFlags(t, method) & ACC_NATIVE) { unsigned returnCode = invokeNative(t, method); - if (LIKELY(t->exception == 0)) { - switch (returnCode) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: - result = makeInt(t, popInt(t)); - break; + switch (returnCode) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: + result = makeInt(t, popInt(t)); + break; - case LongField: - case DoubleField: - result = makeLong(t, popLong(t)); - break; + case LongField: + case DoubleField: + result = makeLong(t, popLong(t)); + break; - case ObjectField: - result = popObject(t); - break; + case ObjectField: + result = popObject(t); + break; - case VoidField: - result = 0; - break; + case VoidField: + result = 0; + break; - default: - abort(t); - }; - } + default: + abort(t); + }; } else { checkStack(t, method); - if (LIKELY(t->exception == 0)) { - pushFrame(t, method); - result = interpret(t); - if (LIKELY(t->exception == 0)) { - popFrame(t); - } - } - } + pushFrame(t, method); - if (UNLIKELY(t->exception)) { - return 0; + result = interpret(t); + + if (LIKELY(t->exception == 0)) { + popFrame(t); + } else { + object exception = t->exception; + t->exception = 0; + throw_(t, exception); + } } return result; @@ -3070,7 +3022,7 @@ class MyProcessor: public Processor { { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code, 0); + offset, 0, 0, name, spec, addendum, class_, code); } virtual object @@ -3094,7 +3046,7 @@ class MyProcessor: public Processor { unsigned vtableLength UNUSED) { return vm::makeClass - (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, + (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, fieldTable, methodTable, addendum, staticTable, loader, 0); } @@ -3189,10 +3141,9 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast @@ -3214,10 +3165,9 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast @@ -3238,10 +3188,9 @@ class MyProcessor: public Processor { or t->state == Thread::ExclusiveState); if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } pushArguments(t, this_, methodSpec, false, arguments); @@ -3249,18 +3198,14 @@ class MyProcessor: public Processor { object method = resolveMethod (t, loader, className, methodName, methodSpec); - if (LIKELY(t->exception == 0)) { - assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); + assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); - return ::invoke(t, method); - } else { - return 0; - } + return ::invoke(t, method); } - virtual object getStackTrace(vm::Thread*, vm::Thread*) { + virtual object getStackTrace(vm::Thread* t, vm::Thread*) { // not implemented - return 0; + return makeObjectArray(t, 0); } virtual void initialize(BootImage*, uint8_t*, unsigned) { @@ -3273,7 +3218,7 @@ class MyProcessor: public Processor { abort(s); } - virtual void visitRoots(HeapWalker*) { + virtual void visitRoots(vm::Thread*, HeapWalker*) { abort(s); } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 1886301027..eebbf2ad6d 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -31,26 +31,17 @@ AttachCurrentThread(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { - *t = m->processor->makeThread(m, 0, m->rootThread); - m->system->attach(&((*t)->runnable)); - - enter(*t, Thread::ActiveState); - enter(*t, Thread::IdleState); - - m->localThread->set(*t); + *t = attachThread(m, false); } return 0; } jint JNICALL -AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void* parameters) +AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { - AttachCurrentThread(m, t, parameters); - - ENTER(*t, Thread::ActiveState); - setDaemon(*t, (*t)->javaThread, true); + *t = attachThread(m, true); } return 0; } @@ -80,11 +71,9 @@ DetachCurrentThread(Machine* m) } } -jint JNICALL -DestroyJavaVM(Machine* m) +uint64_t +destroyJavaVM(Thread* t, uintptr_t*) { - Thread* t; AttachCurrentThread(m, &t, 0); - // wait for other non-daemon threads to exit { ACQUIRE(t, t->m->stateLock); while (t->m->liveCount - t->m->daemonCount > 1) { @@ -92,16 +81,22 @@ DestroyJavaVM(Machine* m) } } - { ENTER(t, Thread::ActiveState); + shutDown(t); - shutDown(t); + return 1; +} + +jint JNICALL +DestroyJavaVM(Machine* m) +{ + Thread* t; AttachCurrentThread(m, &t, 0); + + if (runRaw(t, destroyJavaVM, 0)) { + t->exit(); + return 0; + } else { + return -1; } - - int exitCode = (t->exception ? -1 : 0); - - t->exit(); - - return exitCode; } jint JNICALL @@ -156,6 +151,45 @@ ReleaseStringChars(Thread* t, jstring s, const jchar* chars) t->m->heap->free(chars, (stringLength(t, *s) + 1) * sizeof(jchar)); } +void JNICALL +GetStringRegion(Thread* t, jstring s, jsize start, jsize length, jchar* dst) +{ + ENTER(t, Thread::ActiveState); + + stringChars(t, *s, start, length, dst); +} + +const jchar* JNICALL +GetStringCritical(Thread* t, jstring s, jboolean* isCopy) +{ + if ((t->criticalLevel ++) == 0) { + enter(t, Thread::ActiveState); + } + + if (isCopy) { + *isCopy = true; + } + + object data = stringData(t, *s); + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { + return GetStringChars(t, s, isCopy); + } else { + return &charArrayBody(t, data, stringOffset(t, *s)); + } +} + +void JNICALL +ReleaseStringCritical(Thread* t, jstring s, const jchar* chars) +{ + if (objectClass(t, stringData(t, *s)) == type(t, Machine::ByteArrayType)) { + ReleaseStringChars(t, s, chars); + } + + if ((-- t->criticalLevel) == 0) { + enter(t, Thread::IdleState); + } +} + jsize JNICALL GetStringUTFLength(Thread* t, jstring s) { @@ -186,6 +220,15 @@ ReleaseStringUTFChars(Thread* t, jstring s, const char* chars) t->m->heap->free(chars, stringLength(t, *s) + 1); } +void JNICALL +GetStringUTFRegion(Thread* t, jstring s, jsize start, jsize length, char* dst) +{ + ENTER(t, Thread::ActiveState); + + stringUTFChars + (t, *s, start, length, dst, stringUTFLength(t, *s, start, length)); +} + jsize JNICALL GetArrayLength(Thread* t, jarray array) { @@ -194,21 +237,43 @@ GetArrayLength(Thread* t, jarray array) return cast(*array, BytesPerWord); } -jstring JNICALL -NewString(Thread* t, const jchar* chars, jsize size) +uint64_t +newString(Thread* t, uintptr_t* arguments) { - if (chars == 0) return 0; - - ENTER(t, Thread::ActiveState); + const jchar* chars = reinterpret_cast(arguments[0]); + jsize size = arguments[1]; object a = 0; if (size) { a = makeCharArray(t, size); memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar)); } - object s = makeString(t, a, 0, size, 0); - return makeLocalReference(t, s); + return reinterpret_cast + (makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size))); +} + +jstring JNICALL +NewString(Thread* t, const jchar* chars, jsize size) +{ + if (chars == 0) return 0; + + uintptr_t arguments[] = { reinterpret_cast(chars), size }; + + return reinterpret_cast(run(t, newString, arguments)); +} + +uint64_t +newStringUTF(Thread* t, uintptr_t* arguments) +{ + const char* chars = reinterpret_cast(arguments[0]); + + object array = parseUtf8(t, chars, strlen(chars)); + + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1))); } jstring JNICALL @@ -216,17 +281,9 @@ NewStringUTF(Thread* t, const char* chars) { if (chars == 0) return 0; - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(chars) }; - object a = 0; - unsigned size = strlen(chars); - if (size) { - a = makeByteArray(t, size); - memcpy(&byteArrayBody(t, a, 0), chars, size); - } - object s = makeString(t, a, 0, size, 0); - - return makeLocalReference(t, s); + return reinterpret_cast(run(t, newStringUTF, arguments)); } void @@ -240,26 +297,63 @@ replace(int a, int b, const char* in, int8_t* out) *out = 0; } -jclass JNICALL -FindClass(Thread* t, const char* name) +uint64_t +defineClass(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject loader = reinterpret_cast(arguments[0]); + const uint8_t* buffer = reinterpret_cast(arguments[1]); + jsize length = arguments[2]; + + return reinterpret_cast + (makeLocalReference + (t, getJClass + (t, defineClass + (t, loader ? *loader : root(t, Machine::BootLoader), buffer, length)))); +} + +jclass JNICALL +DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, + jsize length) +{ + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(buffer), + length }; + + return reinterpret_cast(run(t, defineClass, arguments)); +} + +uint64_t +findClass(Thread* t, uintptr_t* arguments) +{ + const char* name = reinterpret_cast(arguments[0]); object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); - return makeLocalReference(t, resolveClass(t, t->m->loader, n)); + object caller = getCaller(t, 0); + + return reinterpret_cast + (makeLocalReference + (t, getJClass + (t, resolveClass + (t, caller ? classLoader(t, methodClass(t, caller)) + : root(t, Machine::AppLoader), n)))); } -jint JNICALL -ThrowNew(Thread* t, jclass c, const char* message) +jclass JNICALL +FindClass(Thread* t, const char* name) { - if (t->exception) { - return -1; - } + uintptr_t arguments[] = { reinterpret_cast(name) }; + + return reinterpret_cast(run(t, findClass, arguments)); +} + +uint64_t +throwNew(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* message = reinterpret_cast(arguments[1]); - ENTER(t, Thread::ActiveState); - object m = 0; PROTECT(t, m); @@ -270,10 +364,37 @@ ThrowNew(Thread* t, jclass c, const char* message) object trace = makeTrace(t); PROTECT(t, trace); - t->exception = make(t, *c); + t->exception = make(t, jclassVmClass(t, *c)); set(t, t->exception, ThrowableMessage, m); set(t, t->exception, ThrowableTrace, trace); + return 1; +} + +jint JNICALL +ThrowNew(Thread* t, jclass c, const char* message) +{ + if (t->exception) { + return -1; + } + + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(message) }; + + return run(t, throwNew, arguments) ? 0 : -1; +} + +jint JNICALL +Throw(Thread* t, jthrowable throwable) +{ + if (t->exception) { + return -1; + } + + ENTER(t, Thread::ActiveState); + + t->exception = *throwable; + return 0; } @@ -291,7 +412,6 @@ ExceptionCheck(Thread* t) return t->exception != 0; } -#ifndef AVIAN_GNU jobject JNICALL NewDirectByteBuffer(Thread*, void*, jlong) { @@ -309,14 +429,13 @@ GetDirectBufferCapacity(Thread*, jobject) { return -1; } -#endif// not AVIAN_GNU jclass JNICALL GetObjectClass(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); - return makeLocalReference(t, objectClass(t, *o)); + return makeLocalReference(t, getJClass(t, objectClass(t, *o))); } jboolean JNICALL @@ -324,7 +443,15 @@ IsInstanceOf(Thread* t, jobject o, jclass c) { ENTER(t, Thread::ActiveState); - return instanceOf(t, *c, *o); + return instanceOf(t, jclassVmClass(t, *c), *o); +} + +jboolean JNICALL +IsAssignableFrom(Thread* t, jclass b, jclass a) +{ + ENTER(t, Thread::ActiveState); + + return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b)); } object @@ -334,7 +461,7 @@ findMethod(Thread* t, jclass c, const char* name, const char* spec) PROTECT(t, n); object s = makeByteArray(t, "%s", spec); - return vm::findMethod(t, *c, n, s); + return vm::findMethod(t, jclassVmClass(t, *c), n, s); } jint @@ -346,23 +473,50 @@ methodID(Thread* t, object method) ACQUIRE(t, t->m->referenceLock); if (methodNativeID(t, method) == 0) { - t->m->jniMethodTable = vectorAppend(t, t->m->jniMethodTable, method); - methodNativeID(t, method) = vectorSize(t, t->m->jniMethodTable); + setRoot(t, Machine::JNIMethodTable, vectorAppend + (t, root(t, Machine::JNIMethodTable), method)); + methodNativeID(t, method) = vectorSize + (t, root(t, Machine::JNIMethodTable)); } } return methodNativeID(t, method); } +uint64_t +getMethodID(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* name = reinterpret_cast(arguments[1]); + const char* spec = reinterpret_cast(arguments[2]); + + object method = findMethod(t, c, name, spec); + + assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); + + return methodID(t, method); +} + jmethodID JNICALL GetMethodID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; + + return run(t, getMethodID, arguments); +} + +uint64_t +getStaticMethodID(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* name = reinterpret_cast(arguments[1]); + const char* spec = reinterpret_cast(arguments[2]); object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) return 0; - assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); + assert(t, methodFlags(t, method) & ACC_STATIC); return methodID(t, method); } @@ -370,37 +524,46 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec) jmethodID JNICALL GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; - object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) return 0; - - assert(t, methodFlags(t, method) & ACC_STATIC); - - return methodID(t, method); + return run(t, getStaticMethodID, arguments); } inline object getMethod(Thread* t, jmethodID m) { - object method = vectorBody(t, t->m->jniMethodTable, m - 1); + object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); return method; } +uint64_t +newObjectV(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object o = make(t, jclassVmClass(t, *c)); + PROTECT(t, o); + + t->m->processor->invokeList(t, getMethod(t, m), o, true, *a); + + return reinterpret_cast(makeLocalReference(t, o)); +} + jobject JNICALL NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + m, + reinterpret_cast(VA_LIST(a)) }; - object o = make(t, *c); - PROTECT(t, o); - - t->m->processor->invokeList(t, getMethod(t, m), o, true, a); - - return makeLocalReference(t, o); + return reinterpret_cast(run(t, newObjectV, arguments)); } jobject JNICALL @@ -416,14 +579,27 @@ NewObject(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callObjectMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + return reinterpret_cast + (makeLocalReference + (t, t->m->processor->invokeList(t, method, *o, true, *a))); +} + jobject JNICALL CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - return makeLocalReference - (t, t->m->processor->invokeList(t, method, *o, true, a)); + return reinterpret_cast(run(t, callObjectMethodV, arguments)); } jobject JNICALL @@ -439,14 +615,25 @@ CallObjectMethod(Thread* t, jobject o, jmethodID m, ...) return r; } +uint64_t +callIntMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + return intValue(t, t->m->processor->invokeList(t, method, *o, true, *a)); +} + jboolean JNICALL CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? (intValue(t, r) != 0) : false); + return run(t, callIntMethodV, arguments) != 0; } jboolean JNICALL @@ -465,11 +652,11 @@ CallBooleanMethod(Thread* t, jobject o, jmethodID m, ...) jbyte JNICALL CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jbyte JNICALL @@ -488,11 +675,11 @@ CallByteMethod(Thread* t, jobject o, jmethodID m, ...) jchar JNICALL CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jchar JNICALL @@ -511,11 +698,11 @@ CallCharMethod(Thread* t, jobject o, jmethodID m, ...) jshort JNICALL CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jshort JNICALL @@ -534,11 +721,11 @@ CallShortMethod(Thread* t, jobject o, jmethodID m, ...) jint JNICALL CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jint JNICALL @@ -554,14 +741,25 @@ CallIntMethod(Thread* t, jobject o, jmethodID m, ...) return r; } +uint64_t +callLongMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + return longValue(t, t->m->processor->invokeList(t, method, *o, true, *a)); +} + jlong JNICALL CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? longValue(t, r) : 0); + return run(t, callLongMethodV, arguments); } jlong JNICALL @@ -580,11 +778,11 @@ CallLongMethod(Thread* t, jobject o, jmethodID m, ...) jfloat JNICALL CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? bitsToFloat(intValue(t, r)) : 0); + return bitsToFloat(run(t, callIntMethodV, arguments)); } jfloat JNICALL @@ -603,11 +801,11 @@ CallFloatMethod(Thread* t, jobject o, jmethodID m, ...) jdouble JNICALL CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? bitsToDouble(longValue(t, r)) : 0); + return bitsToDouble(run(t, callLongMethodV, arguments)); } jdouble JNICALL @@ -623,13 +821,27 @@ CallDoubleMethod(Thread* t, jobject o, jmethodID m, ...) return r; } +uint64_t +callVoidMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + t->m->processor->invokeList(t, method, *o, true, *a); + + return 0; +} + void JNICALL CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(VA_LIST(a)) }; - object method = getMethod(t, m); - t->m->processor->invokeList(t, method, *o, true, a); + run(t, callVoidMethodV, arguments); } void JNICALL @@ -646,20 +858,30 @@ CallVoidMethod(Thread* t, jobject o, jmethodID m, ...) inline object getStaticMethod(Thread* t, jmethodID m) { - object method = vectorBody(t, t->m->jniMethodTable, m - 1); + object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, methodFlags(t, method) & ACC_STATIC); return method; } +uint64_t +callStaticObjectMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + return reinterpret_cast + (makeLocalReference + (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a))); +} + jobject JNICALL CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - return makeLocalReference(t, t->m->processor->invokeList - (t, getStaticMethod(t, m), 0, true, a)); + return reinterpret_cast(run(t, callStaticObjectMethodV, arguments)); } jobject JNICALL @@ -675,13 +897,22 @@ CallStaticObjectMethod(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callStaticIntMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + return intValue + (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); +} + jboolean JNICALL CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? (intValue(t, r) != 0) : false); + return run(t, callStaticIntMethodV, arguments) != 0; } jboolean JNICALL @@ -700,10 +931,9 @@ CallStaticBooleanMethod(Thread* t, jclass c, jmethodID m, ...) jbyte JNICALL CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jbyte JNICALL @@ -722,10 +952,9 @@ CallStaticByteMethod(Thread* t, jclass c, jmethodID m, ...) jchar JNICALL CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jchar JNICALL @@ -744,10 +973,9 @@ CallStaticCharMethod(Thread* t, jclass c, jmethodID m, ...) jshort JNICALL CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jshort JNICALL @@ -766,10 +994,9 @@ CallStaticShortMethod(Thread* t, jclass c, jmethodID m, ...) jint JNICALL CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jint JNICALL @@ -785,13 +1012,22 @@ CallStaticIntMethod(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callStaticLongMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + return longValue + (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); +} + jlong JNICALL CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? longValue(t, r) : 0); + return run(t, callStaticLongMethodV, arguments); } jlong JNICALL @@ -810,10 +1046,9 @@ CallStaticLongMethod(Thread* t, jclass c, jmethodID m, ...) jfloat JNICALL CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? bitsToFloat(intValue(t, r)) : 0); + return bitsToFloat(run(t, callStaticIntMethodV, arguments)); } jfloat JNICALL @@ -832,10 +1067,9 @@ CallStaticFloatMethod(Thread* t, jclass c, jmethodID m, ...) jdouble JNICALL CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? bitsToDouble(longValue(t, r)) : 0); + return bitsToDouble(run(t, callStaticLongMethodV, arguments)); } jdouble JNICALL @@ -851,12 +1085,23 @@ CallStaticDoubleMethod(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callStaticVoidMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a); + + return 0; +} + void JNICALL CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; - t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); + run(t, callStaticVoidMethodV, arguments); } void JNICALL @@ -870,26 +1115,34 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...) va_end(a); } +uint64_t +getFieldID(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* name = reinterpret_cast(arguments[1]); + const char* spec = reinterpret_cast(arguments[2]); + + return fieldOffset(t, resolveField(t, jclassVmClass(t, *c), name, spec)); +} + jfieldID JNICALL GetFieldID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; - object field = resolveField(t, *c, name, spec); - if (UNLIKELY(t->exception)) return 0; - - return fieldOffset(t, field); + return run(t, getFieldID, arguments); } jfieldID JNICALL GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; - object field = resolveField(t, *c, name, spec); - if (UNLIKELY(t->exception)) return 0; - - return fieldOffset(t, field); + return run(t, getFieldID, arguments); } jobject JNICALL @@ -1041,7 +1294,8 @@ GetStaticObjectField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return makeLocalReference(t, cast(classStaticTable(t, *c), field)); + return makeLocalReference + (t, cast(classStaticTable(t, jclassVmClass(t, *c)), field)); } jboolean JNICALL @@ -1049,7 +1303,7 @@ GetStaticBooleanField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jbyte JNICALL @@ -1057,7 +1311,7 @@ GetStaticByteField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jchar JNICALL @@ -1065,7 +1319,7 @@ GetStaticCharField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jshort JNICALL @@ -1073,7 +1327,7 @@ GetStaticShortField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jint JNICALL @@ -1081,7 +1335,7 @@ GetStaticIntField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jlong JNICALL @@ -1089,7 +1343,7 @@ GetStaticLongField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jfloat JNICALL @@ -1097,7 +1351,7 @@ GetStaticFloatField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jdouble JNICALL @@ -1105,7 +1359,7 @@ GetStaticDoubleField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } void JNICALL @@ -1113,7 +1367,7 @@ SetStaticObjectField(Thread* t, jclass c, jfieldID field, jobject v) { ENTER(t, Thread::ActiveState); - set(t, classStaticTable(t, *c), field, (v ? *v : 0)); + set(t, classStaticTable(t, jclassVmClass(t, *c)), field, (v ? *v : 0)); } void JNICALL @@ -1121,7 +1375,7 @@ SetStaticBooleanField(Thread* t, jclass c, jfieldID field, jboolean v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1129,7 +1383,7 @@ SetStaticByteField(Thread* t, jclass c, jfieldID field, jbyte v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1137,7 +1391,7 @@ SetStaticCharField(Thread* t, jclass c, jfieldID field, jchar v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1145,7 +1399,7 @@ SetStaticShortField(Thread* t, jclass c, jfieldID field, jshort v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1153,7 +1407,7 @@ SetStaticIntField(Thread* t, jclass c, jfieldID field, jint v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1161,7 +1415,7 @@ SetStaticLongField(Thread* t, jclass c, jfieldID field, jlong v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1169,7 +1423,7 @@ SetStaticFloatField(Thread* t, jclass c, jfieldID field, jfloat v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1177,7 +1431,7 @@ SetStaticDoubleField(Thread* t, jclass c, jfieldID field, jdouble v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } jobject JNICALL @@ -1219,6 +1473,12 @@ DeleteGlobalRef(Thread* t, jobject r) } } +jint JNICALL +EnsureLocalCapacity(Thread*, jint) +{ + return 0; +} + jthrowable JNICALL ExceptionOccurred(Thread* t) { @@ -1243,17 +1503,29 @@ ExceptionClear(Thread* t) t->exception = 0; } -jobjectArray JNICALL -NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) +uint64_t +newObjectArray(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jsize length = arguments[0]; + jclass class_ = reinterpret_cast(arguments[1]); + jobject init = reinterpret_cast(arguments[2]); - object a = makeObjectArray(t, classLoader(t, *class_), *class_, length); + object a = makeObjectArray(t, jclassVmClass(t, *class_), length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); } - return makeLocalReference(t, a); + return reinterpret_cast(makeLocalReference(t, a)); +} + +jobjectArray JNICALL +NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) +{ + uintptr_t arguments[] = { length, + reinterpret_cast(class_), + reinterpret_cast(init) }; + + return reinterpret_cast(run(t, newObjectArray, arguments)); } jobject JNICALL @@ -1273,68 +1545,102 @@ SetObjectArrayElement(Thread* t, jobjectArray array, jsize index, set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); } +uint64_t +newArray(Thread* t, uintptr_t* arguments) +{ + object (*constructor)(Thread*, unsigned) + = reinterpret_cast(arguments[0]); + + jsize length = arguments[1]; + + return reinterpret_cast + (makeLocalReference(t, constructor(t, length))); +} + jbooleanArray JNICALL NewBooleanArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeBooleanArray)), + length }; - return makeLocalReference(t, makeBooleanArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); +} + +object +makeByteArray0(Thread* t, unsigned length) +{ + return makeByteArray(t, length); } jbyteArray JNICALL NewByteArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeByteArray0)), + length }; - return makeLocalReference(t, makeByteArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jcharArray JNICALL NewCharArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeCharArray)), + length }; - return makeLocalReference(t, makeCharArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jshortArray JNICALL NewShortArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeShortArray)), + length }; - return makeLocalReference(t, makeShortArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jintArray JNICALL NewIntArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeIntArray)), + length }; - return makeLocalReference(t, makeIntArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jlongArray JNICALL NewLongArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeLongArray)), + length }; - return makeLocalReference(t, makeLongArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jfloatArray JNICALL NewFloatArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeFloatArray)), + length }; - return makeLocalReference(t, makeFloatArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jdoubleArray JNICALL NewDoubleArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeDoubleArray)), + length }; - return makeLocalReference(t, makeDoubleArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jboolean* JNICALL @@ -1827,24 +2133,96 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint) } } +uint64_t +registerNatives(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const JNINativeMethod* methods + = reinterpret_cast(arguments[1]); + jint methodCount = arguments[2]; + + for (int i = 0; i < methodCount; ++i) { + if (methods[i].function) { + object method = findMethodOrNull + (t, jclassVmClass(t, *c), methods[i].name, methods[i].signature); + + if (method == 0 or (methodFlags(t, method) & ACC_NATIVE) == 0) { + // The JNI spec says we must throw a NoSuchMethodError in this + // case, but that would prevent using a code shrinker like + // ProGuard effectively. Instead, we just ignore it. + } else { + registerNative(t, method, methods[i].function); + } + } + } + + return 1; +} + jint JNICALL -MonitorEnter(Thread* t, jobject o) +RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, + jint methodCount) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(methods), + methodCount }; + + return run(t, registerNatives, arguments) ? 0 : -1; +} + +jint JNICALL +UnregisterNatives(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); - acquire(t, *o); + unregisterNatives(t, *c); return 0; } +uint64_t +monitorOp(Thread* t, uintptr_t* arguments) +{ + void (*op)(Thread*, object) + = reinterpret_cast(arguments[0]); + + jobject o = reinterpret_cast(arguments[1]); + + op(t, *o); + + return 1; +} + +void +acquire0(Thread* t, object o) +{ + return acquire(t, o); +} + +jint JNICALL +MonitorEnter(Thread* t, jobject o) +{ + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(acquire0)), + reinterpret_cast(o) }; + + return run(t, monitorOp, arguments) ? 0 : -1; +} + +void +release0(Thread* t, object o) +{ + return release(t, o); +} + jint JNICALL MonitorExit(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(release0)), + reinterpret_cast(o) }; - release(t, *o); - - return 0; + return run(t, monitorOp, arguments) ? 0 : -1; } jint JNICALL @@ -1888,11 +2266,11 @@ parseSize(const char* s) return 0; } else if (s[length - 1] == 'k') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); - RUNTIME_ARRAY_BODY(buffer)[length] = 0; + RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024; } else if (s[length - 1] == 'm') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); - RUNTIME_ARRAY_BODY(buffer)[length] = 0; + RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024; } else { return atoi(s); @@ -1909,23 +2287,40 @@ append(char** p, const char* value, unsigned length, char tail) } } +void +boot(Thread* t) +{ + enter(t, Thread::ActiveState); + + t->javaThread = t->m->classpath->makeThread(t, 0); + + setRoot(t, Machine::NullPointerException, makeThrowable + (t, Machine::NullPointerExceptionType)); + + setRoot(t, Machine::ArithmeticException, + makeThrowable(t, Machine::ArithmeticExceptionType)); + + setRoot(t, Machine::ArrayIndexOutOfBoundsException, + makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); + + setRoot(t, Machine::OutOfMemoryError, + makeThrowable(t, Machine::OutOfMemoryErrorType)); + + setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t)); + + threadDaemon(t, root(t, Machine::FinalizerThread)) = true; + + t->m->classpath->boot(t); + + enter(t, Thread::IdleState); +} + } // namespace local } // namespace namespace vm { -#ifdef AVIAN_GNU -jobject JNICALL -NewDirectByteBuffer(Thread*, void*, jlong); - -void* JNICALL -GetDirectBufferAddress(Thread*, jobject); - -jlong JNICALL -GetDirectBufferCapacity(Thread*, jobject); -#endif//AVIAN_GNU - void populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) { @@ -1943,14 +2338,20 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->GetStringLength = local::GetStringLength; envTable->GetStringChars = local::GetStringChars; envTable->ReleaseStringChars = local::ReleaseStringChars; + envTable->GetStringRegion = local::GetStringRegion; + envTable->GetStringCritical = local::GetStringCritical; + envTable->ReleaseStringCritical = local::ReleaseStringCritical; envTable->GetStringUTFLength = local::GetStringUTFLength; envTable->GetStringUTFChars = local::GetStringUTFChars; envTable->ReleaseStringUTFChars = local::ReleaseStringUTFChars; + envTable->GetStringUTFRegion = local::GetStringUTFRegion; envTable->GetArrayLength = local::GetArrayLength; envTable->NewString = local::NewString; envTable->NewStringUTF = local::NewStringUTF; + envTable->DefineClass = local::DefineClass; envTable->FindClass = local::FindClass; envTable->ThrowNew = local::ThrowNew; + envTable->Throw = local::Throw; envTable->ExceptionCheck = local::ExceptionCheck; envTable->NewDirectByteBuffer = local::NewDirectByteBuffer; envTable->GetDirectBufferAddress = local::GetDirectBufferAddress; @@ -1958,6 +2359,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->DeleteLocalRef = local::DeleteLocalRef; envTable->GetObjectClass = local::GetObjectClass; envTable->IsInstanceOf = local::IsInstanceOf; + envTable->IsAssignableFrom = local::IsAssignableFrom; envTable->GetFieldID = local::GetFieldID; envTable->GetMethodID = local::GetMethodID; envTable->GetStaticMethodID = local::GetStaticMethodID; @@ -2043,6 +2445,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->NewGlobalRef = local::NewGlobalRef; envTable->NewWeakGlobalRef = local::NewGlobalRef; envTable->DeleteGlobalRef = local::DeleteGlobalRef; + envTable->EnsureLocalCapacity = local::EnsureLocalCapacity; envTable->ExceptionOccurred = local::ExceptionOccurred; envTable->ExceptionDescribe = local::ExceptionDescribe; envTable->ExceptionClear = local::ExceptionClear; @@ -2092,6 +2495,8 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->GetPrimitiveArrayCritical = local::GetPrimitiveArrayCritical; envTable->ReleasePrimitiveArrayCritical = local::ReleasePrimitiveArrayCritical; + envTable->RegisterNatives = local::RegisterNatives; + envTable->UnregisterNatives = local::UnregisterNatives; envTable->MonitorEnter = local::MonitorEnter; envTable->MonitorExit = local::MonitorExit; envTable->GetJavaVM = local::GetJavaVM; @@ -2102,7 +2507,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) #define BOOTSTRAP_PROPERTY "avian.bootstrap" #define CRASHDIR_PROPERTY "avian.crash.dir" +#define EMBED_PREFIX_PROPERTY "avian.embed.prefix" #define CLASSPATH_PROPERTY "java.class.path" +#define JAVA_HOME_PROPERTY "java.home" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" #define BOOTCLASSPATH_OPTION "bootclasspath" #define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" @@ -2122,8 +2529,10 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) unsigned heapLimit = 0; const char* bootLibrary = 0; const char* classpath = 0; + const char* javaHome = AVIAN_JAVA_HOME; + const char* embedPrefix = AVIAN_EMBED_PREFIX; const char* bootClasspathPrepend = ""; - const char* bootClasspath = ""; + const char* bootClasspath = 0; const char* bootClasspathAppend = ""; const char* crashDumpDirectory = 0; @@ -2161,6 +2570,14 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) sizeof(CLASSPATH_PROPERTY)) == 0) { classpath = p + sizeof(CLASSPATH_PROPERTY); + } else if (strncmp(p, JAVA_HOME_PROPERTY "=", + sizeof(JAVA_HOME_PROPERTY)) == 0) + { + javaHome = p + sizeof(JAVA_HOME_PROPERTY); + } else if (strncmp(p, EMBED_PREFIX_PROPERTY "=", + sizeof(EMBED_PREFIX_PROPERTY)) == 0) + { + embedPrefix = p + sizeof(EMBED_PREFIX_PROPERTY); } ++ propertyCount; @@ -2171,24 +2588,30 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) if (classpath == 0) classpath = "."; + System* s = makeSystem(crashDumpDirectory); + Heap* h = makeHeap(s, heapLimit); + Classpath* c = makeClasspath(s, h, javaHome, embedPrefix); + + if (bootClasspath == 0) { + bootClasspath = c->bootClasspath(); + } + unsigned bcppl = strlen(bootClasspathPrepend); unsigned bcpl = strlen(bootClasspath); unsigned bcpal = strlen(bootClasspathAppend); - unsigned cpl = strlen(classpath); - unsigned classpathBufferSize = bcppl + bcpl + bcpal + cpl + 4; - RUNTIME_ARRAY(char, classpathBuffer, classpathBufferSize); - char* classpathPointer = RUNTIME_ARRAY_BODY(classpathBuffer); + unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; + RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); + char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); + local::append(&bootClasspathPointer, bootClasspathPrepend, bcppl, + bcpl + bcpal ? PATH_SEPARATOR : 0); + local::append(&bootClasspathPointer, bootClasspath, bcpl, + bcpal ? PATH_SEPARATOR : 0); + local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); - local::append - (&classpathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); - local::append(&classpathPointer, bootClasspath, bcpl, PATH_SEPARATOR); - local::append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR); - local::append(&classpathPointer, classpath, cpl, 0); - - System* s = makeSystem(crashDumpDirectory); - Heap* h = makeHeap(s, heapLimit); - Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary); + Finder* bf = makeFinder + (s, h, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); + Finder* af = makeFinder(s, h, classpath, bootLibrary); Processor* p = makeProcessor(s, h, true); const char** properties = static_cast @@ -2201,12 +2624,11 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } *m = new (h->allocate(sizeof(Machine))) - Machine(s, h, f, p, properties, propertyCount); + Machine(s, h, bf, af, p, c, properties, propertyCount); *t = p->makeThread(*m, 0, 0); - enter(*t, Thread::ActiveState); - enter(*t, Thread::IdleState); + local::boot(*t); return 0; } diff --git a/src/machine.cpp b/src/machine.cpp index 01b766de93..c174f4aafd 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -45,7 +45,10 @@ void join(Thread* t, Thread* o) { if (t != o) { - o->systemThread->join(); + if (acquireSystem(t, o)) { + o->systemThread->join(); + releaseSystem(t, o); + } o->state = Thread::JoinedState; } } @@ -80,7 +83,7 @@ dispose(Thread* t, Thread* o, bool remove) expect(t, find(t->m->rootThread, o)); unsigned c = count(t->m->rootThread, o); - RUNTIME_ARRAY(Thread*, threads, c); + THREAD_RUNTIME_ARRAY(t, Thread*, threads, c); fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads)); #endif @@ -167,28 +170,49 @@ turnOffTheLights(Thread* t) enter(t, Thread::ExitState); - for (object* p = &(t->m->finalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + { object p = 0; + PROTECT(t, p); - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, f)); + for (p = t->m->finalizers; p;) { + object f = p; + p = finalizerNext(t, p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + if (function) { + function(t, finalizerTarget(t, f)); + } + } + + for (p = t->m->tenuredFinalizers; p;) { + object f = p; + p = finalizerNext(t, p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + if (function) { + function(t, finalizerTarget(t, f)); + } } } - for (object* p = &(t->m->tenuredFinalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); - - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, f)); + if (root(t, Machine::VirtualFiles)) { + for (unsigned i = 0; i < arrayLength(t, root(t, Machine::VirtualFiles)); + ++i) + { + object region = arrayBody(t, root(t, Machine::VirtualFiles), i); + if (region) { + static_cast(regionRegion(t, region))->dispose(); + } } } + for (object p = root(t, Machine::VirtualFileFinders); + p; p = finderNext(t, p)) + { + static_cast(finderFinder(t, p))->dispose(); + } + Machine* m = t->m; disposeAll(t, t->m->rootThread); @@ -196,13 +220,17 @@ turnOffTheLights(Thread* t) System* s = m->system; Heap* h = m->heap; Processor* p = m->processor; - Finder* f = m->finder; + Classpath* c = m->classpath; + Finder* bf = m->bootFinder; + Finder* af = m->appFinder; + c->dispose(); m->dispose(); h->disposeFixies(); p->dispose(); + bf->dispose(); + af->dispose(); h->dispose(); - f->dispose(); s->dispose(); } @@ -227,23 +255,6 @@ killZombies(Thread* t, Thread* o) } } -object -makeJavaThread(Thread* t, Thread* parent) -{ - object group; - if (parent) { - group = threadGroup(t, parent->javaThread); - } else { - group = makeThreadGroup(t, 0, 0, 0); - } - - const unsigned NewState = 0; - const unsigned NormalPriority = 5; - - return makeThread - (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, group); -} - unsigned footprint(Thread* t) { @@ -377,13 +388,12 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) object q = jreferenceQueue(t, *p); - set(t, *p, JreferenceJNext, *p); if (referenceQueueFront(t, q)) { - set(t, referenceQueueRear(t, q), JreferenceJNext, *p); + set(t, *p, JreferenceJNext, referenceQueueFront(t, q)); } else { - set(t, q, ReferenceQueueFront, *p); + set(t, *p, JreferenceJNext, *p); } - set(t, q, ReferenceQueueRear, *p); + set(t, q, ReferenceQueueFront, *p); jreferenceQueue(t, *p) = 0; } @@ -568,12 +578,19 @@ postCollect(Thread* t) } t->heapOffset = 0; - t->heapIndex = 0; - if (t->useBackupHeap) { + if (t->m->heap->limitExceeded()) { + // if we're out of memory, pretend the thread-local heap is + // already full so we don't make things worse: + t->heapIndex = ThreadHeapSizeInWords; + } else { + t->heapIndex = 0; + } + + if (t->flags & Thread::UseBackupHeapFlag) { memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes); - t->useBackupHeap = false; + t->flags &= ~Thread::UseBackupHeapFlag; t->backupHeapIndex = 0; } @@ -582,6 +599,17 @@ postCollect(Thread* t) } } +uint64_t +invoke(Thread* t, uintptr_t* arguments) +{ + object m = reinterpret_cast(arguments[0]); + object o = reinterpret_cast(arguments[1]); + + t->m->processor->invoke(t, m, o); + + return 1; +} + void finalizeObject(Thread* t, object o) { @@ -594,7 +622,11 @@ finalizeObject(Thread* t, object o) and vm::strcmp(reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, m), 0)) == 0) { - t->m->processor->invoke(t, m, o); + uintptr_t arguments[] = { reinterpret_cast(m), + reinterpret_cast(o) }; + + run(t, invoke, arguments); + t->exception = 0; return; } @@ -603,21 +635,6 @@ finalizeObject(Thread* t, object o) abort(t); } -object -makeByteArray(Thread* t, const char* format, va_list a) -{ - const int Size = 256; - char buffer[Size]; - - int r = vm::vsnprintf(buffer, Size - 1, format, a); - expect(t, r >= 0 and r < Size - 1); - - object s = makeByteArray(t, strlen(buffer) + 1); - memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s)); - - return s; -} - unsigned readByte(Stream& s, unsigned* value) { @@ -727,7 +744,8 @@ parseUtf8(Thread* t, Stream& s, unsigned length) void removeByteArray(Thread* t, object o) { - hashMapRemove(t, t->m->byteArrayMap, o, byteArrayHash, objectEqual); + hashMapRemove + (t, root(t, Machine::ByteArrayMap), o, byteArrayHash, objectEqual); } object @@ -735,12 +753,14 @@ internByteArray(Thread* t, object array) { PROTECT(t, array); + ACQUIRE(t, t->m->referenceLock); + object n = hashMapFindNode - (t, t->m->byteArrayMap, array, byteArrayHash, byteArrayEqual); + (t, root(t, Machine::ByteArrayMap), array, byteArrayHash, byteArrayEqual); if (n) { return jreferenceTarget(t, tripleFirst(t, n)); } else { - hashMapInsert(t, t->m->byteArrayMap, array, 0, byteArrayHash); + hashMapInsert(t, root(t, Machine::ByteArrayMap), array, 0, byteArrayHash); addFinalizer(t, array, removeByteArray); return array; } @@ -768,9 +788,7 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) case CONSTANT_Utf8: { if (singletonObject(t, pool, i) == 0) { object value = parseUtf8(t, s, s.read2()); - if (objectClass(t, value) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, value) == type(t, Machine::ByteArrayType)) { value = internByteArray(t, value); } set(t, pool, SingletonBody + (i * BytesPerWord), value); @@ -793,8 +811,8 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) parsePoolEntry(t, s, index, pool, si); object value = singletonObject(t, pool, si); - value = makeString - (t, value, 0, cast(value, BytesPerWord) - 1, 0); + value = t->m->classpath->makeString + (t, value, 0, cast(value, BytesPerWord) - 1); value = intern(t, value); set(t, pool, SingletonBody + (i * BytesPerWord), value); } @@ -847,6 +865,9 @@ parsePool(Thread* t, Stream& s) if (count) { uint32_t* index = static_cast(t->m->heap->allocate(count * 4)); + THREAD_RESOURCE2(t, uint32_t*, index, unsigned, count, + t->m->heap->free(index, count * 4)); + for (unsigned i = 0; i < count; ++i) { index[i] = s.position(); @@ -878,6 +899,7 @@ parsePool(Thread* t, Stream& s) s.skip(8); ++ i; break; + case CONSTANT_Double: singletonSetBit(t, pool, count, i); singletonSetBit(t, pool, count, i + 1); @@ -900,8 +922,6 @@ parsePool(Thread* t, Stream& s) i += parsePoolEntry(t, s, index, pool, i); } - t->m->heap->free(index, count * 4); - s.setPosition(end); } @@ -949,7 +969,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) PROTECT(t, name); object interface = resolveClass(t, classLoader(t, class_), name); - if (UNLIKELY(t->exception)) return; PROTECT(t, interface); @@ -969,9 +988,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) unsigned i = 0; for (HashMapIterator it(t, map); it.hasMore();) { - object interface = resolveClass - (t, classLoader(t, class_), tripleFirst(t, it.next())); - if (UNLIKELY(t->exception)) return; + object interface = tripleSecond(t, it.next()); set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface); ++ i; @@ -1018,7 +1035,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) object addendum = 0; PROTECT(t, addendum); - RUNTIME_ARRAY(uint8_t, staticTypes, count); + THREAD_RUNTIME_ARRAY(t, uint8_t, staticTypes, count); for (unsigned i = 0; i < count; ++i) { unsigned flags = s.read2(); @@ -1046,7 +1063,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - addendum = makeAddendum(t, pool, body); + addendum = makeFieldAddendum(t, pool, body); } else { s.skip(length); } @@ -1082,9 +1099,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) classVmFlags(t, class_) |= HasFinalMemberFlag; } - unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord; - if (excess) { - memberOffset += BytesPerWord - excess; + while (memberOffset % fieldSize(t, code)) { + ++ memberOffset; } fieldOffset(t, field) = memberOffset; @@ -1211,7 +1227,7 @@ parseCode(Thread* t, Stream& s, object pool) unsigned maxLocals = s.read2(); unsigned length = s.read4(); - object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length); + object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); @@ -1305,11 +1321,11 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap, methodFlags(t, method), (*virtualCount)++, 0, + 0, methodName(t, method), methodSpec(t, method), 0, class_, - 0, 0); hashMapInsert(t, virtualMap, method, method, methodHash); @@ -1392,14 +1408,29 @@ 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("Exceptions"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeMethodAddendum(t, pool, 0, 0); + } + unsigned exceptionCount = s.read2(); + object body = makeShortArray(t, exceptionCount); + for (unsigned i = 0; i < exceptionCount; ++i) { + shortArrayBody(t, body, i) = s.read2(); + } + set(t, addendum, MethodAddendumExceptionTable, body); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { + if (addendum == 0) { + addendum = makeMethodAddendum(t, pool, 0, 0); + } object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - addendum = makeAddendum(t, pool, body); + set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); } @@ -1491,6 +1522,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) bool populateInterfaceVtables = false; if (declaredVirtualCount == 0 + and abstractVirtuals == 0 and (classFlags(t, class_) & ACC_INTERFACE) == 0) { if (classSuper(t, class_)) { @@ -1549,7 +1581,6 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) if (abstractVirtuals) { PROTECT(t, vtable); - PROTECT(t, abstractVirtuals); unsigned oldLength = arrayLength(t, classMethodTable(t, class_)); object newMethodTable = makeArray @@ -1627,7 +1658,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - object addendum = makeClassAddendum(t, pool, body, 0); + object addendum = makeClassAddendum(t, pool, body); set(t, class_, ClassAddendum, addendum); } else { @@ -1673,8 +1704,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) // verify that the classes have the same layout expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); - expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType) - or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); + expect(t, classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0); @@ -1702,8 +1732,22 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, object elementClass) { // todo: arrays should implement Cloneable and Serializable - object vtable = classVirtualTable - (t, arrayBody(t, t->m->types, Machine::JobjectType)); + + if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) { + PROTECT(t, loader); + PROTECT(t, spec); + PROTECT(t, elementClass); + + // Load java.lang.Object if present so we can use its vtable, but + // don't throw an exception if we can't find it. This way, we + // avoid infinite recursion due to trying to create an array to + // make a stack trace for a ClassNotFoundException. + resolveSystemClass + (t, root(t, Machine::BootLoader), + className(t, type(t, Machine::JobjectType)), false); + } + + object vtable = classVirtualTable(t, type(t, Machine::JobjectType)); object c = t->m->processor->makeClass (t, @@ -1712,10 +1756,10 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, 2 * BytesPerWord, BytesPerWord, dimensions, - classObjectMask(t, arrayBody(t, t->m->types, Machine::ArrayType)), + classObjectMask(t, type(t, Machine::ArrayType)), spec, 0, - arrayBody(t, t->m->types, Machine::JobjectType), + type(t, Machine::JobjectType), 0, vtable, 0, @@ -1731,7 +1775,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, } object -makeArrayClass(Thread* t, object loader, object spec) +makeArrayClass(Thread* t, object loader, object spec, bool throw_) { PROTECT(t, loader); PROTECT(t, spec); @@ -1769,47 +1813,58 @@ makeArrayClass(Thread* t, object loader, object spec) } object elementClass = hashMapFind - (t, t->m->bootstrapClassMap, elementSpec, byteArrayHash, byteArrayEqual); - + (t, root(t, Machine::BootstrapClassMap), elementSpec, byteArrayHash, + byteArrayEqual); + if (elementClass == 0) { - elementClass = resolveClass(t, loader, elementSpec); - if (UNLIKELY(t->exception)) return 0; + elementClass = resolveClass(t, loader, elementSpec, throw_); + if (elementClass == 0) return 0; } - return makeArrayClass(t, loader, dimensions, spec, elementClass); + PROTECT(t, elementClass); + + object class_ = findLoadedClass(t, classLoader(t, elementClass), spec); + + return class_ ? class_ : makeArrayClass + (t, classLoader(t, elementClass), dimensions, spec, elementClass); } object -resolveArrayClass(Thread* t, object loader, object spec) +resolveArrayClass(Thread* t, object loader, object spec, bool throw_) { object c = hashMapFind - (t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, + byteArrayEqual); if (c) { set(t, c, ClassVirtualTable, - classVirtualTable - (t, arrayBody(t, t->m->types, Machine::JobjectType))); + classVirtualTable(t, type(t, Machine::JobjectType))); return c; } else { - return makeArrayClass(t, loader, spec); + PROTECT(t, loader); + PROTECT(t, spec); + + c = findLoadedClass(t, root(t, Machine::BootLoader), spec); + + if (c) { + return c; + } else { + return makeArrayClass(t, loader, spec, throw_); + } } } void removeMonitor(Thread* t, object o) { - expect(t, t->state == Thread::ExclusiveState - or t->state == Thread::ExitState); - unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); } - object m = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); - - expect(t, m); + object m = hashMapRemove + (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); if (DebugMonitors) { fprintf(stderr, "dispose monitor %p for object %x\n", m, hash); @@ -1819,14 +1874,15 @@ removeMonitor(Thread* t, object o) void removeString(Thread* t, object o) { - hashMapRemove(t, t->m->stringMap, o, stringHash, objectEqual); + hashMapRemove(t, root(t, Machine::StringMap), o, stringHash, objectEqual); } void bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength) { - object super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0); + object super = (superType >= 0 + ? vm::type(t, static_cast(superType)) : 0); object mask; if (objectMask) { @@ -1835,7 +1891,8 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, and intArrayBody(t, classObjectMask(t, super), 0) == static_cast(objectMask)) { - mask = classObjectMask(t, arrayBody(t, t->m->types, superType)); + mask = classObjectMask + (t, vm::type(t, static_cast(superType))); } else { mask = makeIntArray(t, 1); intArrayBody(t, mask, 0) = objectMask; @@ -1844,14 +1901,15 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, mask = 0; } - super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0); + super = (superType >= 0 + ? vm::type(t, static_cast(superType)) : 0); object class_ = t->m->processor->makeClass (t, 0, BootstrapFlag, fixedSize, arrayElementSize, arrayElementSize ? 1 : 0, mask, 0, 0, super, 0, 0, 0, 0, 0, 0, - t->m->loader, vtableLength); + root(t, Machine::BootLoader), vtableLength); - set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_); + setType(t, type, class_); } void @@ -1861,27 +1919,37 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, PROTECT(t, bootMethod); object n = makeByteArray(t, name); - object class_ = arrayBody(t, t->m->types, type); + PROTECT(t, n); + + object class_ = vm::type(t, type); + PROTECT(t, class_); set(t, class_, ClassName, n); object vtable; if (vtableLength >= 0) { - PROTECT(t, class_); - vtable = makeArray(t, vtableLength); for (int i = 0; i < vtableLength; ++ i) { arrayBody(t, vtable, i) = bootMethod; } } else { - vtable = classVirtualTable(t, arrayBody(t, t->m->types, superType)); + vtable = classVirtualTable + (t, vm::type(t, static_cast(superType))); } set(t, class_, ClassVirtualTable, vtable); t->m->processor->initVtable(t, class_); - hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash); + hashMapInsert + (t, root(t, Machine::BootstrapClassMap), n, class_, byteArrayHash); +} + +void +nameClass(Thread* t, Machine::Type type, const char* name) +{ + object n = makeByteArray(t, name); + set(t, arrayBody(t, t->m->types, type), ClassName, n); } void @@ -1891,101 +1959,123 @@ boot(Thread* t) m->unsafe = true; - m->loader = allocate(t, FixedSizeOfSystemClassLoader, true); + m->roots = allocate(t, pad((Machine::RootCount + 2) * BytesPerWord), true); + arrayLength(t, m->roots) = Machine::RootCount; + + setRoot(t, Machine::BootLoader, + allocate(t, FixedSizeOfSystemClassLoader, true)); + + setRoot(t, Machine::AppLoader, + allocate(t, FixedSizeOfSystemClassLoader, true)); m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true); arrayLength(t, m->types) = TypeCount; #include "type-initializations.cpp" - object arrayClass = arrayBody(t, m->types, Machine::ArrayType); + object arrayClass = type(t, Machine::ArrayType); set(t, m->types, 0, arrayClass); + set(t, m->roots, 0, arrayClass); - object loaderClass = arrayBody - (t, m->types, Machine::SystemClassLoaderType); - set(t, m->loader, 0, loaderClass); + object loaderClass = type(t, Machine::SystemClassLoaderType); + set(t, root(t, Machine::BootLoader), 0, loaderClass); + set(t, root(t, Machine::AppLoader), 0, loaderClass); -#ifdef AVIAN_GNU - classLoaderInitialized(t, m->loader) = true; -#endif + object objectClass = type(t, Machine::JobjectType); - object objectClass = arrayBody(t, m->types, Machine::JobjectType); - - object classClass = arrayBody(t, m->types, Machine::ClassType); + object classClass = type(t, Machine::ClassType); set(t, classClass, 0, classClass); set(t, classClass, ClassSuper, objectClass); - object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType); + object intArrayClass = type(t, Machine::IntArrayType); set(t, intArrayClass, 0, classClass); set(t, intArrayClass, ClassSuper, objectClass); m->unsafe = false; - classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType)) + classVmFlags(t, type(t, Machine::SingletonType)) |= SingletonFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::ContinuationType)) + classVmFlags(t, type(t, Machine::ContinuationType)) |= ContinuationFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType)) + classVmFlags(t, type(t, Machine::JreferenceType)) |= ReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType)) + classVmFlags(t, type(t, Machine::WeakReferenceType)) |= ReferenceFlag | WeakReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::SoftReferenceType)) + classVmFlags(t, type(t, Machine::SoftReferenceType)) |= ReferenceFlag | WeakReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType)) + classVmFlags(t, type(t, Machine::PhantomReferenceType)) |= ReferenceFlag | WeakReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType)) + classVmFlags(t, type(t, Machine::JbooleanType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType)) + classVmFlags(t, type(t, Machine::JbyteType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JcharType)) + classVmFlags(t, type(t, Machine::JcharType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JshortType)) + classVmFlags(t, type(t, Machine::JshortType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JintType)) + classVmFlags(t, type(t, Machine::JintType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JlongType)) + classVmFlags(t, type(t, Machine::JlongType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType)) + classVmFlags(t, type(t, Machine::JfloatType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType)) + classVmFlags(t, type(t, Machine::JdoubleType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType)) + classVmFlags(t, type(t, Machine::JvoidType)) |= PrimitiveFlag; - set(t, arrayBody(t, m->types, Machine::BooleanArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JbooleanType)); - set(t, arrayBody(t, m->types, Machine::ByteArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JbyteType)); - set(t, arrayBody(t, m->types, Machine::CharArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JcharType)); - set(t, arrayBody(t, m->types, Machine::ShortArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JshortType)); - set(t, arrayBody(t, m->types, Machine::IntArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JintType)); - set(t, arrayBody(t, m->types, Machine::LongArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JlongType)); - set(t, arrayBody(t, m->types, Machine::FloatArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JfloatType)); - set(t, arrayBody(t, m->types, Machine::DoubleArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JdoubleType)); + set(t, type(t, Machine::BooleanArrayType), ClassStaticTable, + type(t, Machine::JbooleanType)); + set(t, type(t, Machine::ByteArrayType), ClassStaticTable, + type(t, Machine::JbyteType)); + set(t, type(t, Machine::CharArrayType), ClassStaticTable, + type(t, Machine::JcharType)); + set(t, type(t, Machine::ShortArrayType), ClassStaticTable, + type(t, Machine::JshortType)); + set(t, type(t, Machine::IntArrayType), ClassStaticTable, + type(t, Machine::JintType)); + set(t, type(t, Machine::LongArrayType), ClassStaticTable, + type(t, Machine::JlongType)); + set(t, type(t, Machine::FloatArrayType), ClassStaticTable, + type(t, Machine::JfloatType)); + set(t, type(t, Machine::DoubleArrayType), ClassStaticTable, + type(t, Machine::JdoubleType)); - m->classMap = makeHashMap(t, 0, 0); + { object map = makeHashMap(t, 0, 0); + set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); + } - m->bootstrapClassMap = makeHashMap(t, 0, 0); + systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = m->bootFinder; + + { object map = makeHashMap(t, 0, 0); + set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); + } + + systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = m->appFinder; + + set(t, root(t, Machine::AppLoader), ClassLoaderParent, + root(t, Machine::BootLoader)); + + setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); + + setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); - m->stringMap = makeWeakHashMap(t, 0, 0); m->processor->boot(t, 0); - { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1); + { object bootCode = makeCode(t, 0, 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, 0, bootCode, 0); + (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); PROTECT(t, bootMethod); #include "type-java-initializations.cpp" + +#ifdef AVIAN_HEAPDUMP +# include "type-name-initializations.cpp" +#endif } } @@ -2055,8 +2145,8 @@ class HeapClient: public Heap::Client { memcpy(dst, src, n * BytesPerWord); if (hashTaken(t, src)) { - cast(dst, 0) &= PointerMask; - cast(dst, 0) |= ExtendedMark; + alias(dst, 0) &= PointerMask; + alias(dst, 0) |= ExtendedMark; extendedWord(t, dst, base) = takeHash(t, src); } } @@ -2074,20 +2164,83 @@ class HeapClient: public Heap::Client { Machine* m; }; +void +doCollect(Thread* t, Heap::CollectionType type) +{ +#ifdef VM_STRESS + bool stress = (t->flags |= Thread::StressFlag); + if (not stress) atomicOr(&(t->flags), Thread::StressFlag); +#endif + + Machine* m = t->m; + + m->unsafe = true; + m->heap->collect(type, footprint(m->rootThread)); + m->unsafe = false; + + postCollect(m->rootThread); + + killZombies(t, m->rootThread); + + for (unsigned i = 0; i < m->heapPoolIndex; ++i) { + m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes); + } + m->heapPoolIndex = 0; + + if (m->heap->limitExceeded()) { + // if we're out of memory, disallow further allocations of fixed + // objects: + m->fixedFootprint = FixedFootprintThresholdInBytes; + } else { + m->fixedFootprint = 0; + } + +#ifdef VM_STRESS + if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); +#endif + + object f = t->m->finalizeQueue; + t->m->finalizeQueue = 0; + for (; f; f = finalizerNext(t, f)) { + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + if (function) { + function(t, finalizerTarget(t, f)); + } else { + setRoot(t, Machine::ObjectsToFinalize, makePair + (t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize))); + } + } + + if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { + m->finalizeThread = m->processor->makeThread + (m, root(t, Machine::FinalizerThread), m->rootThread); + + addThread(t, m->finalizeThread); + + if (not startThread(t, m->finalizeThread)) { + removeThread(t, m->finalizeThread); + m->finalizeThread = 0; + } + } +} + } // namespace namespace vm { -Machine::Machine(System* system, Heap* heap, Finder* finder, - Processor* processor, const char** properties, - unsigned propertyCount): +Machine::Machine(System* system, Heap* heap, Finder* bootFinder, + Finder* appFinder, Processor* processor, Classpath* classpath, + const char** properties, unsigned propertyCount): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient))) HeapClient(this)), heap(heap), - finder(finder), + bootFinder(bootFinder), + appFinder(appFinder), processor(processor), + classpath(classpath), rootThread(0), exclusive(0), finalizeThread(0), @@ -2105,26 +2258,16 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, referenceLock(0), shutdownLock(0), libraries(0), - loader(0), - classMap(0), - loadClassMethod(0), - bootstrapClassMap(0), - monitorMap(0), - stringMap(0), - byteArrayMap(0), types(0), - jniMethodTable(0), + roots(0), finalizers(0), tenuredFinalizers(0), finalizeQueue(0), weakReferences(0), tenuredWeakReferences(0), - shutdownHooks(0), - objectsToFinalize(0), - nullPointerException(0), - arrayIndexOutOfBoundsException(0), unsafe(false), triedBuiltinOnLoad(false), + dumpedHeapOnOOM(false), heapPoolIndex(0) { heap->setClient(heapClient); @@ -2138,7 +2281,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, not system->success(system->make(&referenceLock)) or not system->success(system->make(&shutdownLock)) or not system->success - (system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) + (system->load(&libraries, findProperty(this, "avian.bootstrap")))) { system->abort(); } @@ -2179,7 +2322,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): vtable(&(m->jniEnvVTable)), m(m), parent(parent), - peer((parent ? parent->child : 0)), + peer(0), child(0), waitNext(0), state(NoState), @@ -2197,12 +2340,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): (m->heap->allocate(ThreadHeapSizeInBytes))), heap(defaultHeap), backupHeapIndex(0), - useBackupHeap(false), - waiting(false), - tracing(false) -#ifdef VM_STRESS - , stress(false) -#endif // VM_STRESS + flags(ActiveFlag) { } void @@ -2237,35 +2375,29 @@ Thread::init() m->unsafe = false; + enter(this, ActiveState); + if (image) { m->processor->boot(this, image); } else { boot(this); } - m->byteArrayMap = makeWeakHashMap(this, 0, 0); - m->monitorMap = makeWeakHashMap(this, 0, 0); + setRoot(this, Machine::ByteArrayMap, makeWeakHashMap(this, 0, 0)); + setRoot(this, Machine::MonitorMap, makeWeakHashMap(this, 0, 0)); - m->jniMethodTable = makeVector(this, 0, 0); - - m->nullPointerException = makeNullPointerException(this); - - m->arrayIndexOutOfBoundsException - = makeArrayIndexOutOfBoundsException(this, 0); + setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0)); + setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0)); + setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); m->localThread->set(this); - } else { - peer = parent->child; - parent->child = this; + + javaThread = m->classpath->makeThread(this, 0); + + threadPeer(this, javaThread) = reinterpret_cast(this); } expect(this, m->system->success(m->system->make(&lock))); - - if (javaThread == 0) { - this->javaThread = makeJavaThread(this, parent); - } - - threadPeer(this, javaThread) = reinterpret_cast(this); } void @@ -2280,7 +2412,21 @@ Thread::exit() turnOffTheLights(this); } else { threadPeer(this, javaThread) = 0; - enter(this, Thread::ZombieState); + + { ACQUIRE_RAW(this, m->stateLock); + + while (flags & SystemFlag) { + m->stateLock->wait(systemThread, 0); + } + + enter(this, Thread::ZombieState); + } + + lock->dispose(); + lock = 0; + + systemThread->dispose(); + systemThread = 0; } } } @@ -2288,7 +2434,9 @@ Thread::exit() void Thread::dispose() { - lock->dispose(); + if (lock) { + lock->dispose(); + } if (systemThread) { systemThread->dispose(); @@ -2304,10 +2452,10 @@ shutDown(Thread* t) { ACQUIRE(t, t->m->shutdownLock); - object hooks = t->m->shutdownHooks; + object hooks = root(t, Machine::ShutdownHooks); PROTECT(t, hooks); - t->m->shutdownHooks = 0; + setRoot(t, Machine::ShutdownHooks, 0); object h = hooks; PROTECT(t, h); @@ -2408,7 +2556,7 @@ enter(Thread* t, Thread::State s) } break; case Thread::IdleState: - if (t->state == Thread::ActiveState) { + if (LIKELY(t->state == Thread::ActiveState)) { // fast path assert(t, t->m->activeCount > 0); INCREMENT(&(t->m->activeCount), -1); @@ -2420,6 +2568,7 @@ enter(Thread* t, Thread::State s) t->m->stateLock->notifyAll(t->systemThread); } + break; } else { // fall through to slow path @@ -2446,17 +2595,18 @@ enter(Thread* t, Thread::State s) assert(t, t->m->liveCount > 0); -- t->m->liveCount; - if (threadDaemon(t, t->javaThread)) { + if (t->flags & Thread::DaemonFlag) { -- t->m->daemonCount; } } + t->state = s; t->m->stateLock->notifyAll(t->systemThread); } break; case Thread::ActiveState: - if (t->state == Thread::IdleState and t->m->exclusive == 0) { + if (LIKELY(t->state == Thread::IdleState and t->m->exclusive == 0)) { // fast path INCREMENT(&(t->m->activeCount), 1); @@ -2544,7 +2694,7 @@ object allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, unsigned sizeInBytes, bool objectMask) { - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord) <= ThreadBackupHeapSizeInWords); @@ -2552,7 +2702,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord); cast(o, 0) = 0; return o; - } else if (UNLIKELY(t->tracing)) { + } else if (UNLIKELY(t->flags & Thread::TracingFlag)) { expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord) <= ThreadHeapSizeInWords); return allocateSmall(t, sizeInBytes); @@ -2577,7 +2727,9 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, > ThreadHeapSizeInWords) { t->heap = 0; - if (t->m->heapPoolIndex < ThreadHeapPoolSize) { + if ((not t->m->heap->limitExceeded()) + and t->m->heapPoolIndex < ThreadHeapPoolSize) + { t->heap = static_cast (t->m->heap->tryAllocate(ThreadHeapSizeInBytes)); @@ -2608,6 +2760,10 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, // vmPrintTrace(t); collect(t, Heap::MinorCollection); } + + if (t->m->heap->limitExceeded()) { + throw_(t, root(t, Machine::OutOfMemoryError)); + } } while (type == Machine::MovableAllocation and t->heapIndex + ceiling(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords); @@ -2625,7 +2781,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, memset(o, 0, sizeInBytes); - cast(o, 0) = FixedMark; + alias(o, 0) = FixedMark; t->m->fixedFootprint += total; @@ -2640,7 +2796,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, memset(o, 0, sizeInBytes); - cast(o, 0) = FixedMark; + alias(o, 0) = FixedMark; return o; } @@ -2673,12 +2829,39 @@ makeNewGeneral(Thread* t, object class_) return instance; } +void +popResources(Thread* t) +{ + while (t->resource != t->checkpoint->resource) { + Thread::Resource* r = t->resource; + t->resource = r->next; + r->release(); + } + + t->protector = t->checkpoint->protector; +} + +object +makeByteArray(Thread* t, const char* format, va_list a) +{ + const int Size = 256; + char buffer[Size]; + + int r = vm::vsnprintf(buffer, Size - 1, format, a); + expect(t, r >= 0 and r < Size - 1); + + object s = makeByteArray(t, strlen(buffer) + 1); + memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s)); + + return s; +} + object makeByteArray(Thread* t, const char* format, ...) { va_list a; va_start(a, format); - object s = ::makeByteArray(t, format, a); + object s = makeByteArray(t, format, a); va_end(a); return s; @@ -2689,94 +2872,93 @@ makeString(Thread* t, const char* format, ...) { va_list a; va_start(a, format); - object s = ::makeByteArray(t, format, a); + object s = makeByteArray(t, format, a); va_end(a); - return makeString(t, s, 0, byteArrayLength(t, s) - 1, 0); + return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1); } - int -stringUTFLength(Thread* t, object string) { - int length = 0; +stringUTFLength(Thread* t, object string, unsigned start, unsigned length) +{ + unsigned result = 0; - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) { - length = stringLength(t, string); + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { + result = length; } else { - for (unsigned i = 0; i < stringLength(t, string); ++i) { - uint16_t c = charArrayBody(t, data, stringOffset(t, string) + i); - if (!c) length += 1; // null char (was 2 bytes in Java) - else if (c < 0x80) length += 1; // ASCII char - else if (c < 0x800) length += 2; // two-byte char - else length += 3; // three-byte char + for (unsigned i = 0; i < length; ++i) { + uint16_t c = charArrayBody + (t, data, stringOffset(t, string) + start + i); + if (c == 0) result += 1; // null char (was 2 bytes in Java) + else if (c < 0x80) result += 1; // ASCII char + else if (c < 0x800) result += 2; // two-byte char + else result += 3; // three-byte char } } } - return length; + return result; } void -stringChars(Thread* t, object string, char* chars) +stringChars(Thread* t, object string, unsigned start, unsigned length, + char* chars) { - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { memcpy(chars, - &byteArrayBody(t, data, stringOffset(t, string)), - stringLength(t, string)); + &byteArrayBody(t, data, stringOffset(t, string) + start), + length); } else { - for (unsigned i = 0; i < stringLength(t, string); ++i) { - chars[i] = charArrayBody(t, data, stringOffset(t, string) + i); + for (unsigned i = 0; i < length; ++i) { + chars[i] = charArrayBody(t, data, stringOffset(t, string) + start + i); } } } - chars[stringLength(t, string)] = 0; + chars[length] = 0; } void -stringChars(Thread* t, object string, uint16_t* chars) +stringChars(Thread* t, object string, unsigned start, unsigned length, + uint16_t* chars) { - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { - for (unsigned i = 0; i < stringLength(t, string); ++i) { - chars[i] = byteArrayBody(t, data, stringOffset(t, string) + i); + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { + for (unsigned i = 0; i < length; ++i) { + chars[i] = byteArrayBody(t, data, stringOffset(t, string) + start + i); } } else { memcpy(chars, - &charArrayBody(t, data, stringOffset(t, string)), - stringLength(t, string) * sizeof(uint16_t)); + &charArrayBody(t, data, stringOffset(t, string) + start), + length * sizeof(uint16_t)); } } - chars[stringLength(t, string)] = 0; + chars[length] = 0; } void -stringUTFChars(Thread* t, object string, char* chars, unsigned length UNUSED) +stringUTFChars(Thread* t, object string, unsigned start, unsigned length, + char* chars, unsigned charsLength UNUSED) { - assert(t, static_cast(stringUTFLength(t, string)) == length); + assert(t, static_cast + (stringUTFLength(t, string, start, length)) == charsLength); - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { memcpy(chars, - &byteArrayBody(t, data, stringOffset(t, string)), - stringLength(t, string)); - chars[stringLength(t, string)] = 0; + &byteArrayBody(t, data, stringOffset(t, string) + start), + length); + chars[length] = 0; } else { int j = 0; - for (unsigned i = 0; i < stringLength(t, string); ++i) { - uint16_t c = charArrayBody(t, data, stringOffset(t, string) + i); + for (unsigned i = 0; i < length; ++i) { + uint16_t c = charArrayBody + (t, data, stringOffset(t, string) + start + i); if(!c) { // null char chars[j++] = 0; } else if (c < 0x80) { // ASCII char @@ -2795,15 +2977,29 @@ stringUTFChars(Thread* t, object string, char* chars, unsigned length UNUSED) } } +uint64_t +resolveBootstrap(Thread* t, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + + resolveSystemClass(t, root(t, Machine::BootLoader), name); + + return 1; +} + bool isAssignableFrom(Thread* t, object a, object b) { + assert(t, a); + assert(t, b); + if (a == b) return true; if (classFlags(t, a) & ACC_INTERFACE) { if (classVmFlags(t, b) & BootstrapFlag) { - resolveSystemClass(t, className(t, b)); - if (UNLIKELY(t->exception)) { + uintptr_t arguments[] = { reinterpret_cast(className(t, b)) }; + + if (run(t, resolveBootstrap, arguments) == 0) { t->exception = 0; return false; } @@ -2940,15 +3136,6 @@ primitiveSize(Thread* t, unsigned code) } } -object -findLoadedSystemClass(Thread* t, object spec) -{ - PROTECT(t, spec); - ACQUIRE(t, t->m->classLock); - - return hashMapFind(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual); -} - object parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) { @@ -2985,6 +3172,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) 0, // fixed size 0, // array size 0, // array dimensions + 0, // runtime data index 0, // object mask referenceName (t, singletonObject(t, pool, name - 1)), @@ -3004,7 +3192,6 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) if (super) { object sc = resolveClass (t, loader, referenceName(t, singletonObject(t, pool, super - 1))); - if (UNLIKELY(t->exception)) return 0; set(t, class_, ClassSuper, sc); @@ -3014,16 +3201,12 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) } parseInterfaceTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; parseFieldTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; parseMethodTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; parseAttributeTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; object vtable = classVirtualTable(t, class_); unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0); @@ -3058,20 +3241,29 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) } object -resolveSystemClass(Thread* t, object spec) +resolveSystemClass(Thread* t, object loader, object spec, bool throw_) { + PROTECT(t, loader); PROTECT(t, spec); ACQUIRE(t, t->m->classLock); object class_ = hashMapFind - (t, t->m->classMap, spec, byteArrayHash, byteArrayEqual); + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { + if (classLoaderParent(t, loader)) { + class_ = resolveSystemClass + (t, classLoaderParent(t, loader), spec, false); + if (class_) { + return class_; + } + } + if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, t->m->loader, spec); + class_ = resolveArrayClass(t, loader, spec, throw_); } else { - RUNTIME_ARRAY(char, file, byteArrayLength(t, spec) + 6); + THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6); memcpy(RUNTIME_ARRAY_BODY(file), &byteArrayBody(t, spec, 0), byteArrayLength(t, spec) - 1); @@ -3079,35 +3271,36 @@ resolveSystemClass(Thread* t, object spec) ".class", 7); - System::Region* region = t->m->finder->find(RUNTIME_ARRAY_BODY(file)); + System::Region* region = static_cast + (systemClassLoaderFinder(t, loader))->find + (RUNTIME_ARRAY_BODY(file)); if (region) { if (Verbose) { fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0)); } - // parse class file - class_ = parseClass - (t, t->m->loader, region->start(), region->length()); - region->dispose(); + { THREAD_RESOURCE(t, System::Region*, region, region->dispose()); - if (LIKELY(t->exception == 0)) { - if (Verbose) { - fprintf(stderr, "done parsing %s: %p\n", - &byteArrayBody(t, spec, 0), - class_); - } + // parse class file + class_ = parseClass(t, loader, region->start(), region->length()); + } - object bootstrapClass = hashMapFind - (t, t->m->bootstrapClassMap, spec, byteArrayHash, - byteArrayEqual); + if (Verbose) { + fprintf(stderr, "done parsing %s: %p\n", + &byteArrayBody(t, spec, 0), + class_); + } - if (bootstrapClass) { - PROTECT(t, bootstrapClass); - - updateBootstrapClass(t, bootstrapClass, class_); - class_ = bootstrapClass; - } + object bootstrapClass = hashMapFind + (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, + byteArrayEqual); + + if (bootstrapClass) { + PROTECT(t, bootstrapClass); + + updateBootstrapClass(t, bootstrapClass, class_); + class_ = bootstrapClass; } } } @@ -3115,10 +3308,10 @@ resolveSystemClass(Thread* t, object spec) if (class_) { PROTECT(t, class_); - hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash); - } else if (t->exception == 0) { - object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeClassNotFoundException(t, message); + hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); + } else if (throw_) { + throwNew(t, Machine::ClassNotFoundExceptionType, "%s", + &byteArrayBody(t, spec, 0)); } } @@ -3126,75 +3319,89 @@ resolveSystemClass(Thread* t, object spec) } object -resolveClass(Thread* t, object loader, object spec) +findLoadedClass(Thread* t, object loader, object spec) { - if (loader == t->m->loader) { - return resolveSystemClass(t, spec); + PROTECT(t, loader); + PROTECT(t, spec); + + ACQUIRE(t, t->m->classLock); + + return classLoaderMap(t, loader) ? hashMapFind + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual) : 0; +} + +object +resolveClass(Thread* t, object loader, object spec, bool throw_) +{ + if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) { + return resolveSystemClass(t, loader, spec, throw_); } else { + expect(t, throw_); + PROTECT(t, loader); PROTECT(t, spec); - ACQUIRE(t, t->m->classLock); - - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); + object c = findLoadedClass(t, loader, spec); + if (c) { + return c; } - object class_ = hashMapFind - (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + if (byteArrayBody(t, spec, 0) == '[') { + c = resolveArrayClass(t, loader, spec, throw_); + } else { + if (root(t, Machine::LoadClassMethod) == 0) { + object m = resolveMethod + (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", + "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - if (class_ == 0) { - if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, loader, spec); - } else { - if (t->m->loadClassMethod == 0) { - object m = resolveMethod - (t, t->m->loader, "java/lang/ClassLoader", "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); + if (m) { + setRoot(t, Machine::LoadClassMethod, m); - if (m) { - t->m->loadClassMethod = m; - - object classLoaderClass = arrayBody - (t, t->m->types, Machine::ClassLoaderType); + object classLoaderClass = type(t, Machine::ClassLoaderType); - if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { - resolveSystemClass(t, vm::className(t, classLoaderClass)); - } - } - } - - if (LIKELY(t->exception == 0)) { - object method = findVirtualMethod - (t, t->m->loadClassMethod, objectClass(t, loader)); - - if (LIKELY(t->exception == 0)) { - PROTECT(t, method); - - object specString = makeString - (t, "%s", &byteArrayBody(t, spec, 0)); - - replace('/', '.', reinterpret_cast - (&byteArrayBody(t, stringData(t, specString), 0))); - - class_ = t->m->processor->invoke(t, method, loader, specString); + if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { + resolveSystemClass + (t, root(t, Machine::BootLoader), + vm::className(t, classLoaderClass)); } - } + } + } + + object method = findVirtualMethod + (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); + + PROTECT(t, method); + + THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, spec)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast + (&byteArrayBody(t, spec, 0))); + + object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); + + object jc = t->m->processor->invoke(t, method, loader, specString); + if (LIKELY(jc)) { + c = jclassVmClass(t, jc); } } - if (class_) { - PROTECT(t, class_); + if (LIKELY(c)) { + PROTECT(t, c); - hashMapInsert(t, classLoaderMap(t, loader), spec, class_, - byteArrayHash); - } else if (t->exception == 0) { - object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeClassNotFoundException(t, message); + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + hashMapInsert + (t, classLoaderMap(t, loader), spec, c, byteArrayHash); + + return c; + } else { + throwNew(t, Machine::ClassNotFoundExceptionType, "%s", + &byteArrayBody(t, spec, 0)); } - - return class_; } } @@ -3211,13 +3418,10 @@ resolveMethod(Thread* t, object class_, const char* methodName, object method = findMethodInClass(t, class_, name, spec); - if (t->exception == 0 and method == 0) { - object message = makeString - (t, "%s %s not found in %s", methodName, methodSpec, - &byteArrayBody(t, className(t, class_), 0)); - - t->exception = makeNoSuchMethodError(t, message); - return 0; + if (method == 0) { + throwNew(t, Machine::NoSuchMethodErrorType, "%s %s not found in %s", + methodName, methodSpec, &byteArrayBody + (t, className(t, class_), 0)); } else { return method; } @@ -3237,49 +3441,21 @@ resolveField(Thread* t, object class_, const char* fieldName, object field = findInInterfaces(t, class_, name, spec, findFieldInClass); - for (; class_ != 0 and field == 0; class_ = classSuper(t, class_)) { - field = findFieldInClass(t, class_, name, spec); + object c = class_; + PROTECT(t, c); + + for (; c != 0 and field == 0; c = classSuper(t, c)) { + field = findFieldInClass(t, c, name, spec); } - if (t->exception == 0 and field == 0) { - object message = makeString - (t, "%s %s not found in %s", fieldName, fieldSpec, - &byteArrayBody(t, className(t, class_), 0)); - - t->exception = makeNoSuchFieldError(t, message); - return 0; + if (field == 0) { + throwNew(t, Machine::NoSuchFieldErrorType, "%s %s not found in %s", + fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0)); } else { return field; } } -object -resolveObjectArrayClass(Thread* t, object loader, object elementSpec) -{ - PROTECT(t, loader); - PROTECT(t, elementSpec); - - object spec; - if (byteArrayBody(t, elementSpec, 0) == '[') { - spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); - byteArrayBody(t, spec, 0) = '['; - memcpy(&byteArrayBody(t, spec, 1), - &byteArrayBody(t, elementSpec, 0), - byteArrayLength(t, elementSpec)); - } else { - spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); - byteArrayBody(t, spec, 0) = '['; - byteArrayBody(t, spec, 1) = 'L'; - memcpy(&byteArrayBody(t, spec, 2), - &byteArrayBody(t, elementSpec, 0), - byteArrayLength(t, elementSpec) - 1); - byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; - byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; - } - - return resolveClass(t, loader, spec); -} - bool classNeedsInit(Thread* t, object c) { @@ -3307,6 +3483,7 @@ preInitClass(Thread* t, object c) if (classVmFlags(t, c) & NeedInitFlag) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); + if (classVmFlags(t, c) & NeedInitFlag) { if (classVmFlags(t, c) & InitFlag) { // If the class is currently being initialized and this the thread @@ -3322,9 +3499,8 @@ preInitClass(Thread* t, object c) t->m->classLock->wait(t->systemThread, 0); } } else if (classVmFlags(t, c) & InitErrorFlag) { - object message = makeString - (t, "%s", &byteArrayBody(t, className(t, c), 0)); - t->exception = makeNoClassDefFoundError(t, message); + throwNew(t, Machine::NoClassDefFoundErrorType, "%s", + &byteArrayBody(t, className(t, c), 0)); } else { classVmFlags(t, c) |= InitFlag; return true; @@ -3338,12 +3514,17 @@ void postInitClass(Thread* t, object c) { PROTECT(t, c); - ACQUIRE(t, t->m->classLock); + if (t->exception) { - t->exception = makeExceptionInInitializerError(t, t->exception); classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; + + object exception = t->exception; + t->exception = 0; + + throwNew(t, Machine::ExceptionInInitializerErrorType, + static_cast(0), 0, exception); } else { classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag); } @@ -3356,19 +3537,62 @@ initClass(Thread* t, object c) PROTECT(t, c); if (preInitClass(t, c)) { + OBJECT_RESOURCE(t, c, postInitClass(t, c)); + Thread::ClassInitStack stack(t, c); t->m->processor->invoke(t, classInitializer(t, c), 0); - - postInitClass(t, c); } } object -makeObjectArray(Thread* t, object loader, object elementClass, unsigned count) +resolveObjectArrayClass(Thread* t, object loader, object elementClass) +{ + { object arrayClass = classRuntimeDataArrayClass + (t, getClassRuntimeData(t, elementClass)); + if (arrayClass) { + return arrayClass; + } + } + + PROTECT(t, loader); + PROTECT(t, elementClass); + + object elementSpec = className(t, elementClass); + PROTECT(t, elementSpec); + + object spec; + if (byteArrayBody(t, elementSpec, 0) == '[') { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); + byteArrayBody(t, spec, 0) = '['; + memcpy(&byteArrayBody(t, spec, 1), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec)); + } else { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); + byteArrayBody(t, spec, 0) = '['; + byteArrayBody(t, spec, 1) = 'L'; + memcpy(&byteArrayBody(t, spec, 2), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec) - 1); + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; + } + + object arrayClass = resolveClass(t, loader, spec); + + set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, + arrayClass); + + return arrayClass; +} + +object +makeObjectArray(Thread* t, object elementClass, unsigned count) { object arrayClass = resolveObjectArrayClass - (t, loader, className(t, elementClass)); + (t, classLoader(t, elementClass), elementClass); + PROTECT(t, arrayClass); object array = makeArray(t, count); @@ -3410,9 +3634,8 @@ findInTable(Thread* t, object table, object name, object spec, } object -findInHierarchy(Thread* t, object class_, object name, object spec, - object (*find)(Thread*, object, object, object), - object (*makeError)(Thread*, object)) +findInHierarchyOrNull(Thread* t, object class_, object name, object spec, + object (*find)(Thread*, object, object, object)) { object originalClass = class_; @@ -3434,15 +3657,6 @@ findInHierarchy(Thread* t, object class_, object name, object spec, } } - if (o == 0) { - object message = makeString - (t, "%s %s not found in %s", - &byteArrayBody(t, name, 0), - &byteArrayBody(t, spec, 0), - &byteArrayBody(t, className(t, originalClass), 0)); - t->exception = makeError(t, message); - } - return o; } @@ -3490,7 +3704,8 @@ objectMonitor(Thread* t, object o, bool createNew) { assert(t, t->state == Thread::ActiveState); - object m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapFind + (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); if (m) { if (DebugMonitors) { @@ -3504,7 +3719,9 @@ objectMonitor(Thread* t, object o, bool createNew) { ENTER(t, Thread::ExclusiveState); - m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + m = hashMapFind + (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); + if (m) { if (DebugMonitors) { fprintf(stderr, "found monitor %p for object %x\n", @@ -3522,7 +3739,7 @@ objectMonitor(Thread* t, object o, bool createNew) objectHash(t, o)); } - hashMapInsert(t, t->m->monitorMap, o, m, objectHash); + hashMapInsert(t, root(t, Machine::MonitorMap), o, m, objectHash); addFinalizer(t, o, removeMonitor); } @@ -3540,11 +3757,13 @@ intern(Thread* t, object s) ACQUIRE(t, t->m->referenceLock); - object n = hashMapFindNode(t, t->m->stringMap, s, stringHash, stringEqual); + object n = hashMapFindNode + (t, root(t, Machine::StringMap), s, stringHash, stringEqual); + if (n) { return jreferenceTarget(t, tripleFirst(t, n)); } else { - hashMapInsert(t, t->m->stringMap, s, 0, stringHash); + hashMapInsert(t, root(t, Machine::StringMap), s, 0, stringHash); addFinalizer(t, s, removeString); return s; } @@ -3555,56 +3774,31 @@ collect(Thread* t, Heap::CollectionType type) { ENTER(t, Thread::ExclusiveState); -#ifdef VM_STRESS - bool stress = t->stress; - if (not stress) t->stress = true; -#endif - - Machine* m = t->m; - - m->unsafe = true; - m->heap->collect(type, footprint(m->rootThread)); - m->unsafe = false; - - postCollect(m->rootThread); - - killZombies(t, m->rootThread); - - for (unsigned i = 0; i < m->heapPoolIndex; ++i) { - m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes); + if (t->m->heap->limitExceeded()) { + type = Heap::MajorCollection; } - m->heapPoolIndex = 0; - m->fixedFootprint = 0; + doCollect(t, type); -#ifdef VM_STRESS - if (not stress) t->stress = false; -#endif + if (t->m->heap->limitExceeded()) { + // try once more, giving the heap a chance to squeeze everything + // into the smallest possible space: + doCollect(t, Heap::MajorCollection); + } - object f = m->finalizeQueue; - m->finalizeQueue = 0; - for (; f; f = finalizerNext(t, f)) { - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, f)); - } else { - m->objectsToFinalize = makePair - (t, finalizerTarget(t, f), m->objectsToFinalize); - } - } - - if (m->objectsToFinalize and m->finalizeThread == 0) { - m->finalizeThread = m->processor->makeThread - (m, makeJavaThread(t, m->rootThread), m->rootThread); - - if (not t->m->system->success - (m->system->start(&(m->finalizeThread->runnable)))) - { - m->finalizeThread->exit(); - m->finalizeThread = 0; +#ifdef AVIAN_HEAPDUMP + if ((not t->m->dumpedHeapOnOOM) and t->m->heap->limitExceeded()) { + t->m->dumpedHeapOnOOM = true; + const char* path = findProperty(t, "avian.heap.dump"); + if (path) { + FILE* out = vm::fopen(path, "wb"); + if (out) { + dumpHeap(t, out); + fclose(out); + } } } +#endif//AVIAN_HEAPDUMP } void @@ -3623,7 +3817,7 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start) = (arrayElementSize ? cast(o, fixedSize - BytesPerWord) : 0); - RUNTIME_ARRAY(uint32_t, mask, intArrayLength(t, objectMask)); + THREAD_RUNTIME_ARRAY(t, uint32_t, mask, intArrayLength(t, objectMask)); memcpy(RUNTIME_ARRAY_BODY(mask), &intArrayBody(t, objectMask, 0), intArrayLength(t, objectMask) * 4); @@ -3668,19 +3862,8 @@ walkNext(Thread* t, object o, int previous) void visitRoots(Machine* m, Heap::Visitor* v) { - v->visit(&(m->loader)); - v->visit(&(m->classMap)); - v->visit(&(m->loadClassMethod)); - v->visit(&(m->bootstrapClassMap)); - v->visit(&(m->monitorMap)); - v->visit(&(m->stringMap)); - v->visit(&(m->byteArrayMap)); v->visit(&(m->types)); - v->visit(&(m->jniMethodTable)); - v->visit(&(m->shutdownHooks)); - v->visit(&(m->objectsToFinalize)); - v->visit(&(m->nullPointerException)); - v->visit(&(m->arrayIndexOutOfBoundsException)); + v->visit(&(m->roots)); for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); @@ -3695,7 +3878,7 @@ void printTrace(Thread* t, object exception) { if (exception == 0) { - exception = makeNullPointerException(t, 0, makeTrace(t), 0); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } for (object e = exception; e; e = throwableCause(t, e)) { @@ -3708,7 +3891,7 @@ printTrace(Thread* t, object exception) if (throwableMessage(t, e)) { object m = throwableMessage(t, e); - RUNTIME_ARRAY(char, message, stringLength(t, m) + 1); + THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1); stringChars(t, m, RUNTIME_ARRAY_BODY(message)); fprintf(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message)); } else { @@ -3716,8 +3899,8 @@ printTrace(Thread* t, object exception) } object trace = throwableTrace(t, e); - for (unsigned i = 0; i < arrayLength(t, trace); ++i) { - object e = arrayBody(t, trace, i); + for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { + object e = objectArrayBody(t, trace, i); const int8_t* class_ = &byteArrayBody (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); const int8_t* method = &byteArrayBody @@ -3738,7 +3921,13 @@ printTrace(Thread* t, object exception) fprintf(stderr, "(line %d)\n", line); } } + + if (e == throwableCause(t, e)) { + break; + } } + + fflush(stderr); } object @@ -3750,11 +3939,12 @@ makeTrace(Thread* t, Processor::StackWalker* walker) virtual bool visit(Processor::StackWalker* walker) { if (trace == 0) { - trace = makeArray(t, walker->count()); + trace = makeObjectArray(t, walker->count()); + vm_assert(t, trace); } object e = makeTraceElement(t, walker->method(), walker->ip()); - vm_assert(t, index < arrayLength(t, trace)); + vm_assert(t, index < objectArrayLength(t, trace)); set(t, trace, ArrayBody + (index * BytesPerWord), e); ++ index; return true; @@ -3768,7 +3958,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker) walker->walk(&v); - return v.trace ? v.trace : makeArray(t, 0); + return v.trace ? v.trace : makeObjectArray(t, 0); } object @@ -3789,32 +3979,21 @@ makeTrace(Thread* t, Thread* target) t->m->processor->walkStack(target, &v); - return v.trace ? v.trace : makeArray(t, 0); -} - -void -runJavaThread(Thread* t) -{ - object method = resolveMethod - (t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); - - if (t->exception == 0) { - t->m->processor->invoke(t, method, 0, t->javaThread); - } + return v.trace ? v.trace : makeObjectArray(t, 0); } void runFinalizeThread(Thread* t) { - setDaemon(t, t->javaThread, true); - object list = 0; PROTECT(t, list); while (true) { { ACQUIRE(t, t->m->stateLock); - while (t->m->finalizeThread and t->m->objectsToFinalize == 0) { + while (t->m->finalizeThread + and root(t, Machine::ObjectsToFinalize) == 0) + { ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); } @@ -3822,8 +4001,8 @@ runFinalizeThread(Thread* t) if (t->m->finalizeThread == 0) { return; } else { - list = t->m->objectsToFinalize; - t->m->objectsToFinalize = 0; + list = root(t, Machine::ObjectsToFinalize); + setRoot(t, Machine::ObjectsToFinalize, 0); } } @@ -3833,6 +4012,79 @@ runFinalizeThread(Thread* t) } } +object +parseUtf8(Thread* t, const char* data, unsigned length) +{ + class Client: public Stream::Client { + public: + Client(Thread* t): t(t) { } + + virtual void NO_RETURN handleError() { + vm::abort(t); + } + + private: + Thread* t; + } client(t); + + Stream s(&client, reinterpret_cast(data), length); + + return ::parseUtf8(t, s, length); +} + +object +getCaller(Thread* t, unsigned target) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t, unsigned target): + t(t), method(0), count(0), target(target) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (count == target) { + method = walker->method(); + return false; + } else { + ++ count; + return true; + } + } + + Thread* t; + object method; + unsigned count; + unsigned target; + } v(t, target); + + t->m->processor->walkStack(t, &v); + + return v.method; +} + +object +defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) +{ + PROTECT(t, loader); + + object c = parseClass(t, loader, buffer, length); + + if (c) { + PROTECT(t, c); + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + hashMapInsert + (t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash); + } + + return c; +} + void noop() { } @@ -3876,31 +4128,35 @@ vmPrintTrace(Thread* t) Thread* t; } v(t); + fprintf(stderr, "debug trace for thread %p\n", t); + t->m->processor->walkStack(t, &v); + + fflush(stderr); } // also for debugging void* vmAddressFromLine(Thread* t, object m, unsigned line) { - object code = methodCode(t, m); - printf("code: %p\n", code); - object lnt = codeLineNumberTable(t, code); - printf("lnt: %p\n", lnt); + object code = methodCode(t, m); + printf("code: %p\n", code); + object lnt = codeLineNumberTable(t, code); + printf("lnt: %p\n", lnt); - if (lnt) { - unsigned last = 0; - unsigned bottom = 0; - unsigned top = lineNumberTableLength(t, lnt); - for(unsigned i = bottom; i < top; i++) - { - LineNumber* ln = lineNumberTableBody(t, lnt, i); - if(lineNumberLine(ln) == line) - return reinterpret_cast(lineNumberIp(ln)); - else if(lineNumberLine(ln) > line) - return reinterpret_cast(last); - last = lineNumberIp(ln); - } - } - return 0; + if (lnt) { + unsigned last = 0; + unsigned bottom = 0; + unsigned top = lineNumberTableLength(t, lnt); + for(unsigned i = bottom; i < top; i++) + { + LineNumber* ln = lineNumberTableBody(t, lnt, i); + if(lineNumberLine(ln) == line) + return reinterpret_cast(lineNumberIp(ln)); + else if(lineNumberLine(ln) > line) + return reinterpret_cast(last); + last = lineNumberIp(ln); + } + } + return 0; } diff --git a/src/machine.h b/src/machine.h index 4bdfccfc24..c342b9f695 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -30,10 +30,63 @@ #define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x) +#define ACQUIRE_OBJECT(t, x) \ + ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x) + #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) +#define THREAD_RESOURCE0(t, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t): Resource(t) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + } MAKE_NAME(resource_)(t); + +#define OBJECT_RESOURCE(t, name, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t, object name): \ + Resource(t), name(name), protector(t, &(this->name)) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + \ + private: \ + object name; \ + Thread::SingleProtector protector; \ + } MAKE_NAME(resource_)(t, name); + +#define THREAD_RESOURCE(t, type, name, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t, type name): \ + Resource(t), name(name) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + \ + private: \ + type name; \ + } MAKE_NAME(resource_)(t, name); + +#define THREAD_RESOURCE2(t, type1, name1, type2, name2, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t, type1 name1, type2 name2): \ + Resource(t), name1(name1), name2(name2) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + \ + private: \ + type1 name1; \ + type2 name2; \ + } MAKE_NAME(resource_)(t, name1, name2); + namespace vm { const bool Verbose = false; @@ -53,6 +106,9 @@ const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024; const unsigned ThreadBackupHeapSizeInWords = ThreadBackupHeapSizeInBytes / BytesPerWord; +const unsigned StackSizeInBytes = 128 * 1024; +const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; + const unsigned ThreadHeapPoolSize = 64; const unsigned FixedFootprintThresholdInBytes @@ -97,7 +153,6 @@ const unsigned ContinuationFlag = 1 << 11; const unsigned ClassInitFlag = 1 << 0; const unsigned CompiledFlag = 1 << 1; const unsigned ConstructorFlag = 1 << 2; -const unsigned FastNative = 1 << 3; #ifndef JNI_VERSION_1_6 #define JNI_VERSION_1_6 0x00010006 @@ -1121,6 +1176,24 @@ struct JNIEnvVTable { #endif }; +inline void +atomicOr(uint32_t* p, int v) +{ + for (uint32_t old = *p; + not atomicCompareAndSwap32(p, old, old | v); + old = *p) + { } +} + +inline void +atomicAnd(uint32_t* p, int v) +{ + for (uint32_t old = *p; + not atomicCompareAndSwap32(p, old, old & v); + old = *p) + { } +} + inline int strcmp(const int8_t* a, const int8_t* b) { @@ -1151,6 +1224,8 @@ class Reference { unsigned count; }; +class Classpath; + class Machine { public: enum Type { @@ -1163,8 +1238,34 @@ class Machine { ImmortalAllocation }; - Machine(System* system, Heap* heap, Finder* finder, Processor* processor, - const char** properties, unsigned propertyCount); + enum Root { + BootLoader, + AppLoader, + BootstrapClassMap, + FindLoadedClassMethod, + LoadClassMethod, + MonitorMap, + StringMap, + ByteArrayMap, + ClassRuntimeDataTable, + MethodRuntimeDataTable, + JNIMethodTable, + ShutdownHooks, + FinalizerThread, + ObjectsToFinalize, + NullPointerException, + ArithmeticException, + ArrayIndexOutOfBoundsException, + OutOfMemoryError, + VirtualFileFinders, + VirtualFiles + }; + + static const unsigned RootCount = VirtualFiles + 1; + + Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, + Processor* processor, Classpath* classpath, const char** properties, + unsigned propertyCount); ~Machine() { dispose(); @@ -1176,8 +1277,10 @@ class Machine { System* system; Heap::Client* heapClient; Heap* heap; - Finder* finder; + Finder* bootFinder; + Finder* appFinder; Processor* processor; + Classpath* classpath; Thread* rootThread; Thread* exclusive; Thread* finalizeThread; @@ -1195,26 +1298,16 @@ class Machine { System::Monitor* referenceLock; System::Monitor* shutdownLock; System::Library* libraries; - object loader; - object classMap; - object loadClassMethod; - object bootstrapClassMap; - object monitorMap; - object stringMap; - object byteArrayMap; object types; - object jniMethodTable; + object roots; object finalizers; object tenuredFinalizers; object finalizeQueue; object weakReferences; object tenuredWeakReferences; - object shutdownHooks; - object objectsToFinalize; - object nullPointerException; - object arrayIndexOutOfBoundsException; bool unsafe; bool triedBuiltinOnLoad; + bool dumpedHeapOnOOM; JavaVMVTable javaVMVTable; JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; @@ -1240,11 +1333,22 @@ inline void stress(Thread* t); #endif // not VM_STRESS -void -runJavaThread(Thread* t); +uint64_t +runThread(Thread*, uintptr_t*); + +uint64_t +run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), + uintptr_t* arguments); void -runFinalizeThread(Thread* t); +checkDaemon(Thread* t); + +extern "C" uint64_t +vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments, + void* checkpoint); + +extern "C" void +vmRun_returnAddress(); class Thread { public: @@ -1258,6 +1362,14 @@ class Thread { ExitState }; + static const unsigned UseBackupHeapFlag = 1 << 0; + static const unsigned WaitingFlag = 1 << 1; + static const unsigned TracingFlag = 1 << 2; + static const unsigned DaemonFlag = 1 << 3; + static const unsigned StressFlag = 1 << 4; + static const unsigned ActiveFlag = 1 << 5; + static const unsigned SystemFlag = 1 << 6; + class Protector { public: Protector(Thread* t): t(t), next(t->protector) { @@ -1285,9 +1397,26 @@ class Thread { object* p; }; - class ClassInitStack { + class Resource { + public: + Resource(Thread* t): t(t), next(t->resource) { + t->resource = this; + } + + ~Resource() { + t->resource = next; + } + + virtual void release() = 0; + + Thread* t; + Resource* next; + }; + + class ClassInitStack: public Resource { public: ClassInitStack(Thread* t, object class_): + Resource(t), next(t->classInitStack), class_(class_), protector(t, &(this->class_)) @@ -1296,7 +1425,11 @@ class Thread { } ~ClassInitStack() { - protector.t->classInitStack = next; + t->classInitStack = next; + } + + virtual void release() { + this->ClassInitStack::~ClassInitStack(); } ClassInitStack* next; @@ -1304,6 +1437,48 @@ class Thread { SingleProtector protector; }; + class Checkpoint { + public: + Checkpoint(Thread* t): + t(t), + next(t->checkpoint), + resource(t->resource), + protector(t->protector), + noThrow(false) + { + t->checkpoint = this; + } + + ~Checkpoint() { + t->checkpoint = next; + } + + virtual void NO_RETURN unwind() = 0; + + Thread* t; + Checkpoint* next; + Resource* resource; + Protector* protector; + bool noThrow; + }; + + class RunCheckpoint: public Checkpoint { + public: + RunCheckpoint(Thread* t): + Checkpoint(t), + stack(0) + { } + + virtual void unwind() { + void* stack = this->stack; + this->stack = 0; + expect(t->m->system, stack); + vmJump(voidPointer(vmRun_returnAddress), 0, stack, t, 0, 0); + } + + void* stack; + }; + class Runnable: public System::Runnable { public: Runnable(Thread* t): t(t) { } @@ -1315,23 +1490,17 @@ class Thread { virtual void run() { enterActiveState(t); - t->m->localThread->set(t); + vm::run(t, runThread, 0); - if (t == t->m->finalizeThread) { - runFinalizeThread(t); - } else if (t->javaThread) { - runJavaThread(t); - - if (t->exception) { - printTrace(t, t->exception); - } + if (t->exception) { + printTrace(t, t->exception); } t->exit(); } virtual bool interrupted() { - return threadInterrupted(t, t->javaThread); + return t->javaThread and threadInterrupted(t, t->javaThread); } virtual void setInterrupted(bool v) { @@ -1363,19 +1532,76 @@ class Thread { unsigned heapOffset; Protector* protector; ClassInitStack* classInitStack; + Resource* resource; + Checkpoint* checkpoint; Runnable runnable; uintptr_t* defaultHeap; uintptr_t* heap; uintptr_t backupHeap[ThreadBackupHeapSizeInWords]; unsigned backupHeapIndex; - bool useBackupHeap; - bool waiting; - bool tracing; -#ifdef VM_STRESS - bool stress; -#endif // VM_STRESS + unsigned flags; }; +class Classpath { + public: + virtual object + makeJclass(Thread* t, object class_) = 0; + + virtual object + makeString(Thread* t, object array, int32_t offset, int32_t length) = 0; + + virtual object + makeThread(Thread* t, Thread* parent) = 0; + + virtual void + runThread(Thread* t) = 0; + + virtual void + boot(Thread* t) = 0; + + virtual const char* + bootClasspath() = 0; + + virtual void + dispose() = 0; +}; + +#ifdef _MSC_VER + +template +class ThreadRuntimeArray: public Thread::Resource { + public: + ThreadRuntimeArray(Thread* t, unsigned size): + Resource(t), + body(static_cast(t->m->heap->allocate(size * sizeof(T)))), + size(size) + { } + + ~ThreadRuntimeArray() { + t->m->heap->free(body, size * sizeof(T)); + } + + virtual void release() { + ThreadRuntimeArray::~ThreadRuntimeArray(); + } + + T* body; + unsigned size; +}; + +# define THREAD_RUNTIME_ARRAY(thread, type, name, size) \ + ThreadRuntimeArray name(thread, size); + +#else // not _MSC_VER + +# define THREAD_RUNTIME_ARRAY(thread, type, name, size) type name[size]; + +#endif // not _MSC_VER + +Classpath* +makeClasspath(System* system, Allocator* allocator, const char* javaHome, + const char* embedPrefix); + typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); inline object @@ -1393,16 +1619,21 @@ enterActiveState(Thread* t) enter(t, Thread::ActiveState); } -class StateResource { +class StateResource: public Thread::Resource { public: - StateResource(Thread* t, Thread::State state): t(t), oldState(t->state) { + StateResource(Thread* t, Thread::State state): + Resource(t), oldState(t->state) + { enter(t, state); } ~StateResource() { enter(t, oldState); } + virtual void release() { + this->StateResource::~StateResource(); + } + private: - Thread* t; Thread::State oldState; }; @@ -1441,20 +1672,20 @@ shutDown(Thread* t); inline void stress(Thread* t) { - if ((not t->stress) - and (not t->tracing) + if ((not t->m->unsafe) + and (t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 and t->state != Thread::NoState and t->state != Thread::IdleState) { - t->stress = true; + atomicOr(&(t->flags), Thread::StressFlag); # ifdef VM_STRESS_MAJOR - collect(t, Heap::MajorCollection); + collect(t, Heap::MajorCollection); # else // not VM_STRESS_MAJOR - collect(t, Heap::MinorCollection); + collect(t, Heap::MinorCollection); # endif // not VM_STRESS_MAJOR - t->stress = false; + atomicAnd(&(t->flags), ~Thread::StressFlag); } } @@ -1477,33 +1708,43 @@ release(Thread* t, System::Monitor* m) m->release(t->systemThread); } -class MonitorResource { +class MonitorResource: public Thread::Resource { public: - MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) { + MonitorResource(Thread* t, System::Monitor* m): + Resource(t), m(m) + { acquire(t, m); } ~MonitorResource() { - release(t, m); + vm::release(t, m); + } + + virtual void release() { + this->MonitorResource::~MonitorResource(); } private: - Thread* t; System::Monitor* m; }; -class RawMonitorResource { +class RawMonitorResource: public Thread::Resource { public: - RawMonitorResource(Thread* t, System::Monitor* m): t(t), m(m) { + RawMonitorResource(Thread* t, System::Monitor* m): + Resource(t), m(m) + { m->acquire(t->systemThread); } ~RawMonitorResource() { - release(t, m); + vm::release(t, m); + } + + virtual void release() { + this->RawMonitorResource::~RawMonitorResource(); } private: - Thread* t; System::Monitor* m; }; @@ -1546,8 +1787,12 @@ class FixedAllocator: public Allocator { return p; } - virtual void free(const void*, unsigned) { - abort(s); + virtual void free(const void* p, unsigned size) { + if (p >= base and static_cast(p) + size == base + offset) { + offset -= size; + } else { + abort(s); + } } System* s; @@ -1563,9 +1808,9 @@ ensure(Thread* t, unsigned sizeInBytes) > ThreadHeapSizeInWords) { if (sizeInBytes <= ThreadBackupHeapSizeInBytes) { - expect(t, not t->useBackupHeap); + expect(t, (t->flags & Thread::UseBackupHeapFlag) == 0); - t->useBackupHeap = true; + atomicOr(&(t->flags), Thread::UseBackupHeapFlag); return true; } else { @@ -1591,7 +1836,6 @@ allocateSmall(Thread* t, unsigned sizeInBytes) object o = reinterpret_cast(t->heap + t->heapIndex); t->heapIndex += ceiling(sizeInBytes, BytesPerWord); - cast(o, 0) = 0; return o; } @@ -1634,21 +1878,9 @@ setObjectClass(Thread*, object o, object value) { cast(o, 0) = reinterpret_cast - (reinterpret_cast(value) - | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); -} - -inline Thread* -startThread(Thread* t, object javaThread) -{ - Thread* p = t->m->processor->makeThread(t->m, javaThread, t); - - if (t->m->system->success(t->m->system->start(&(p->runnable)))) { - return p; - } else { - p->exit(); - return 0; - } + (reinterpret_cast(value) + | (reinterpret_cast + (cast(o, 0)) & (~PointerMask))); } inline const char* @@ -1682,32 +1914,204 @@ instanceOf(Thread* t, object class_, object o); #include "type-declarations.cpp" -inline object -getClassLoaderMap(Thread* t, object loader) +inline uint64_t +runRaw(Thread* t, + uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) { - if (loader == t->m->loader) { - return t->m->classMap; - } else { - return classLoaderMap(t, loader); + Thread::RunCheckpoint checkpoint(t); + return vmRun(function, arguments, &checkpoint); +} + +inline uint64_t +run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) +{ + ENTER(t, Thread::ActiveState); + return runRaw(t, function, arguments); +} + +inline void +runJavaThread(Thread* t) +{ + t->m->classpath->runThread(t); +} + +void +runFinalizeThread(Thread* t); + +inline uint64_t +runThread(Thread* t, uintptr_t*) +{ + t->m->localThread->set(t); + + checkDaemon(t); + + if (t == t->m->finalizeThread) { + runFinalizeThread(t); + } else if (t->javaThread) { + runJavaThread(t); } + + return 1; +} + +inline bool +startThread(Thread* t, Thread* p) +{ + return t->m->system->success(t->m->system->start(&(p->runnable))); +} + +inline void +addThread(Thread* t, Thread* p) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, p->state == Thread::NoState); + + p->state = Thread::IdleState; + ++ t->m->liveCount; + + p->peer = p->parent->child; + p->parent->child = p; + + if (p->javaThread) { + threadPeer(t, p->javaThread) = reinterpret_cast(p); + } +} + +inline void +removeThread(Thread* t, Thread* p) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, p->state == Thread::IdleState); + + -- t->m->liveCount; + + t->m->stateLock->notifyAll(t->systemThread); + + p->parent->child = p->peer; + + if (p->javaThread) { + threadPeer(t, p->javaThread) = 0; + } +} + +inline Thread* +startThread(Thread* t, object javaThread) +{ + Thread* p = t->m->processor->makeThread(t->m, javaThread, t); + + addThread(t, p); + + if (startThread(t, p)) { + return p; + } else { + removeThread(t, p); + return 0; + } +} + +inline void +registerDaemon(Thread* t) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + atomicOr(&(t->flags), Thread::DaemonFlag); + + ++ t->m->daemonCount; + + t->m->stateLock->notifyAll(t->systemThread); +} + +inline void +checkDaemon(Thread* t) +{ + if (threadDaemon(t, t->javaThread)) { + registerDaemon(t); + } +} + +inline uint64_t +initAttachedThread(Thread* t, uintptr_t* arguments) +{ + bool daemon = arguments[0]; + + t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread); + + threadPeer(t, t->javaThread) = reinterpret_cast(t); + + if (daemon) { + threadDaemon(t, t->javaThread) = true; + + registerDaemon(t); + } + + t->m->localThread->set(t); + + return 1; +} + +inline Thread* +attachThread(Machine* m, bool daemon) +{ + Thread* t = m->processor->makeThread(m, 0, m->rootThread); + m->system->attach(&(t->runnable)); + + addThread(t, t); + + enter(t, Thread::ActiveState); + + uintptr_t arguments[] = { daemon }; + + if (run(t, initAttachedThread, arguments)) { + enter(t, Thread::IdleState); + return t; + } else { + t->exit(); + return 0; + } +} + +inline object& +root(Thread* t, Machine::Root root) +{ + return arrayBody(t, t->m->roots, root); +} + +inline void +setRoot(Thread* t, Machine::Root root, object value) +{ + set(t, t->m->roots, ArrayBody + (root * BytesPerWord), value); +} + +inline object +type(Thread* t, Machine::Type type) +{ + return arrayBody(t, t->m->types, type); +} + +inline void +setType(Thread* t, Machine::Type type, object value) +{ + set(t, t->m->types, ArrayBody + (type * BytesPerWord), value); } inline bool objectFixed(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == FixedMark; + return (alias(o, 0) & (~PointerMask)) == FixedMark; } inline bool objectExtended(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == ExtendedMark; + return (alias(o, 0) & (~PointerMask)) == ExtendedMark; } inline bool hashTaken(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == HashTakenMark; + return (alias(o, 0) & (~PointerMask)) == HashTakenMark; } inline unsigned @@ -1731,160 +2135,10 @@ makeTrace(Thread* t) return makeTrace(t, t); } -inline object -makeRuntimeException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeRuntimeException(t, message, trace, 0); -} - -inline object -makeIllegalStateException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeIllegalStateException(t, message, trace, 0); -} - -inline object -makeIllegalArgumentException(Thread* t) -{ - return makeIllegalArgumentException(t, 0, makeTrace(t), 0); -} - -inline object -makeIllegalMonitorStateException(Thread* t) -{ - return makeIllegalMonitorStateException(t, 0, makeTrace(t), 0); -} - -inline object -makeIndexOutOfBoundsException(Thread* t) -{ - return makeIndexOutOfBoundsException(t, 0, makeTrace(t), 0); -} - -inline object -makeArrayIndexOutOfBoundsException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeArrayIndexOutOfBoundsException(t, message, trace, 0); -} - -inline object -makeArrayStoreException(Thread* t) -{ - return makeArrayStoreException(t, 0, makeTrace(t), 0); -} - -inline object -makeNegativeArraySizeException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNegativeArraySizeException(t, message, trace, 0); -} - -inline object -makeClassCastException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeClassCastException(t, message, trace, 0); -} - -inline object -makeClassNotFoundException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeClassNotFoundException(t, message, trace, 0, 0); -} - -inline object -makeNullPointerException(Thread* t) -{ - return makeNullPointerException(t, 0, makeTrace(t), 0); -} - -inline object -makeInvocationTargetException(Thread* t, object targetException) -{ - PROTECT(t, targetException); - object trace = makeTrace(t); - return makeRuntimeException(t, 0, trace, targetException); -} - -inline object -makeInterruptedException(Thread* t) -{ - return makeInterruptedException(t, 0, makeTrace(t), 0); -} - -inline object -makeIncompatibleContinuationException(Thread* t) -{ - return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0); -} - -inline object -makeStackOverflowError(Thread* t) -{ - return makeStackOverflowError(t, 0, makeTrace(t), 0); -} - -inline object -makeNoSuchFieldError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNoSuchFieldError(t, message, trace, 0); -} - -inline object -makeNoSuchMethodError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNoSuchMethodError(t, message, trace, 0); -} - -inline object -makeNoClassDefFoundError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNoClassDefFoundError(t, message, trace, 0); -} - -inline object -makeUnsatisfiedLinkError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeUnsatisfiedLinkError(t, message, trace, 0); -} - -inline object -makeExceptionInInitializerError(Thread* t, object cause) -{ - PROTECT(t, cause); - object trace = makeTrace(t); - 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_) { - assert(t, t->state == Thread::ActiveState); + assert(t, t->state == Thread::NoState or t->state == Thread::ActiveState); PROTECT(t, class_); unsigned sizeInBytes = pad(classFixedSize(t, class_)); @@ -1910,6 +2164,9 @@ make(Thread* t, object class_) } } +object +makeByteArray(Thread* t, const char* format, va_list a); + object makeByteArray(Thread* t, const char* format, ...); @@ -1917,16 +2174,43 @@ object makeString(Thread* t, const char* format, ...); int -stringUTFLength(Thread* t, object string); +stringUTFLength(Thread* t, object string, unsigned start, unsigned length); + +inline int +stringUTFLength(Thread* t, object string) +{ + return stringUTFLength(t, string, 0, stringLength(t, string)); +} void -stringChars(Thread* t, object string, char* chars); +stringChars(Thread* t, object string, unsigned start, unsigned length, + char* chars); + +inline void +stringChars(Thread* t, object string, char* chars) +{ + stringChars(t, string, 0, stringLength(t, string), chars); +} void -stringChars(Thread* t, object string, uint16_t* chars); +stringChars(Thread* t, object string, unsigned start, unsigned length, + uint16_t* chars); + +inline void +stringChars(Thread* t, object string, uint16_t* chars) +{ + stringChars(t, string, 0, stringLength(t, string), chars); +} void -stringUTFChars(Thread* t, object string, char* chars, unsigned length); +stringUTFChars(Thread* t, object string, unsigned start, unsigned length, + char* chars, unsigned charsLength); + +inline void +stringUTFChars(Thread* t, object string, char* chars, unsigned charsLength) +{ + stringUTFChars(t, string, 0, stringLength(t, string), chars, charsLength); +} bool isAssignableFrom(Thread* t, object a, object b); @@ -1958,7 +2242,7 @@ markHashTaken(Thread* t, object o) ACQUIRE_RAW(t, t->m->heapLock); - cast(o, 0) |= HashTakenMark; + alias(o, 0) |= HashTakenMark; t->m->heap->pad(o); } @@ -2013,9 +2297,7 @@ stringHash(Thread* t, object s) { if (stringHashCode(t, s) == 0 and stringLength(t, s)) { object data = stringData(t, s); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { stringHashCode(t, s) = hash (&byteArrayBody(t, data, stringOffset(t, s)), stringLength(t, s)); } else { @@ -2030,9 +2312,7 @@ inline uint16_t stringCharAt(Thread* t, object s, int i) { object data = stringData(t, s); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { return byteArrayBody(t, data, stringOffset(t, s) + i); } else { return charArrayBody(t, data, stringOffset(t, s) + i); @@ -2149,7 +2429,7 @@ fieldSize(Thread* t, object field) } object -findLoadedSystemClass(Thread* t, object spec); +findLoadedClass(Thread* t, object loader, object spec); inline bool emptyMethod(Thread* t, object method) @@ -2159,27 +2439,30 @@ emptyMethod(Thread* t, object method) and (codeBody(t, methodCode(t, method), 0) == return_); } +object +parseUtf8(Thread* t, const char* data, unsigned length); + object parseClass(Thread* t, object loader, const uint8_t* data, unsigned length); object -resolveClass(Thread* t, object loader, object name); +resolveClass(Thread* t, object loader, object name, bool throw_ = true); inline object -resolveClass(Thread* t, object loader, const char* name) +resolveClass(Thread* t, object loader, const char* name, bool throw_ = true) { PROTECT(t, loader); object n = makeByteArray(t, "%s", name); - return resolveClass(t, loader, n); + return resolveClass(t, loader, n, throw_); } object -resolveSystemClass(Thread* t, object name); +resolveSystemClass(Thread* t, object loader, object name, bool throw_ = true); inline object -resolveSystemClass(Thread* t, const char* name) +resolveSystemClass(Thread* t, object loader, const char* name) { - return resolveSystemClass(t, makeByteArray(t, "%s", name)); + return resolveSystemClass(t, loader, makeByteArray(t, "%s", name)); } void @@ -2193,12 +2476,8 @@ inline object resolveMethod(Thread* t, object loader, const char* className, const char* methodName, const char* methodSpec) { - object class_ = resolveClass(t, loader, className); - if (LIKELY(t->exception == 0)) { - return resolveMethod(t, class_, methodName, methodSpec); - } else { - return 0; - } + return resolveMethod + (t, resolveClass(t, loader, className), methodName, methodSpec); } object @@ -2209,17 +2488,10 @@ inline object resolveField(Thread* t, object loader, const char* className, const char* fieldName, const char* fieldSpec) { - object class_ = resolveClass(t, loader, className); - if (LIKELY(t->exception == 0)) { - return resolveField(t, class_, fieldName, fieldSpec); - } else { - return 0; - } + return resolveField + (t, resolveClass(t, loader, className), fieldName, fieldSpec); } -object -resolveObjectArrayClass(Thread* t, object loader, object elementSpec); - bool classNeedsInit(Thread* t, object c); @@ -2233,13 +2505,15 @@ void initClass(Thread* t, object c); object -makeObjectArray(Thread* t, object loader, object elementClass, unsigned count); +resolveObjectArrayClass(Thread* t, object loader, object elementClass); + +object +makeObjectArray(Thread* t, 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); + return makeObjectArray(t, type(t, Machine::JobjectType), count); } object @@ -2254,6 +2528,16 @@ findFieldInClass(Thread* t, object class_, object name, object spec) (t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec); } +inline object +findFieldInClass2(Thread* t, object class_, const char* name, const char* spec) +{ + PROTECT(t, class_); + object n = makeByteArray(t, "%s", name); + PROTECT(t, n); + object s = makeByteArray(t, "%s", spec); + return findFieldInClass(t, class_, n, s); +} + inline object findMethodInClass(Thread* t, object class_, object name, object spec) { @@ -2261,23 +2545,132 @@ findMethodInClass(Thread* t, object class_, object name, object spec) (t, classMethodTable(t, class_), name, spec, methodName, methodSpec); } +inline object +makeThrowable +(Thread* t, Machine::Type type, object message = 0, object trace = 0, + object cause = 0) +{ + PROTECT(t, message); + PROTECT(t, trace); + PROTECT(t, cause); + + if (trace == 0) { + trace = makeTrace(t); + } + + object result = make(t, vm::type(t, type)); + + set(t, result, ThrowableMessage, message); + set(t, result, ThrowableTrace, trace); + set(t, result, ThrowableCause, cause); + + return result; +} + +inline object +makeThrowable(Thread* t, Machine::Type type, const char* format, va_list a) +{ + object s = makeByteArray(t, format, a); + + object message = t->m->classpath->makeString + (t, s, 0, byteArrayLength(t, s) - 1); + + return makeThrowable(t, type, message); +} + +inline object +makeThrowable(Thread* t, Machine::Type type, const char* format, ...) +{ + va_list a; + va_start(a, format); + object r = makeThrowable(t, type, format, a); + va_end(a); + + return r; +} + +void +popResources(Thread* t); + +inline void NO_RETURN +throw_(Thread* t, object e) +{ + assert(t, t->exception == 0); + + expect(t, not t->checkpoint->noThrow); + + t->exception = e; + + // printTrace(t, e); + + popResources(t); + + t->checkpoint->unwind(); + + abort(t); +} + +inline void NO_RETURN +throwNew +(Thread* t, Machine::Type type, object message = 0, object trace = 0, + object cause = 0) +{ + throw_(t, makeThrowable(t, type, message, trace, cause)); +} + +inline void NO_RETURN +throwNew(Thread* t, Machine::Type type, const char* format, ...) +{ + va_list a; + va_start(a, format); + object r = makeThrowable(t, type, format, a); + va_end(a); + + throw_(t, r); +} + object +findInHierarchyOrNull(Thread* t, object class_, object name, object spec, + object (*find)(Thread*, object, object, object)); + +inline object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - object (*makeError)(Thread*, object)); + Machine::Type errorType) +{ + object o = findInHierarchyOrNull(t, class_, name, spec, find); + + if (o == 0) { + throwNew(t, errorType, "%s %s not found in %s", + &byteArrayBody(t, name, 0), + &byteArrayBody(t, spec, 0), + &byteArrayBody(t, className(t, class_), 0)); + } + + return o; +} inline object findMethod(Thread* t, object class_, object name, object spec) { return findInHierarchy - (t, class_, name, spec, findMethodInClass, makeNoSuchMethodError); + (t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType); +} + +inline object +findMethodOrNull(Thread* t, object class_, const char* name, const char* spec) +{ + PROTECT(t, class_); + object n = makeByteArray(t, "%s", name); + PROTECT(t, n); + object s = makeByteArray(t, "%s", spec); + return findInHierarchyOrNull(t, class_, n, s, findMethodInClass); } inline object findVirtualMethod(Thread* t, object method, object class_) { - return arrayBody(t, classVirtualTable(t, class_), - methodOffset(t, method)); + return arrayBody(t, classVirtualTable(t, class_), methodOffset(t, method)); } inline object @@ -2289,8 +2682,8 @@ findInterfaceMethod(Thread* t, object method, object class_) 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)); + return arrayBody + (t, arrayBody(t, itable, i + 1), methodOffset(t, method)); } } abort(t); @@ -2321,6 +2714,36 @@ parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); +inline bool +zombified(Thread* t) +{ + return t->state == Thread::ZombieState + or t->state == Thread::JoinedState; +} + +inline bool +acquireSystem(Thread* t, Thread* target) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + if (not zombified(target)) { + atomicOr(&(target->flags), Thread::SystemFlag); + return true; + } else { + return false; + } +} + +inline void +releaseSystem(Thread* t, Thread* target) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, not zombified(target)); + + atomicAnd(&(target->flags), ~Thread::SystemFlag); +} + inline bool atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, object old, object new_) @@ -2468,10 +2891,12 @@ monitorRelease(Thread* t, object monitor) Thread* next = monitorAtomicPollAcquire(t, monitor, false); - if (next) { + if (next and acquireSystem(t, next)) { ACQUIRE(t, next->lock); next->lock->notify(t->systemThread); + + releaseSystem(t, next); } } } @@ -2481,10 +2906,10 @@ monitorAppendWait(Thread* t, object monitor) { assert(t, monitorOwner(t, monitor) == t); - expect(t, not t->waiting); + expect(t, (t->flags & Thread::WaitingFlag) == 0); expect(t, t->waitNext == 0); - t->waiting = true; + atomicOr(&(t->flags), Thread::WaitingFlag); if (monitorWaitTail(t, monitor)) { static_cast(monitorWaitTail(t, monitor))->waitNext = t; @@ -2517,7 +2942,7 @@ monitorRemoveWait(Thread* t, object monitor) } t->waitNext = 0; - t->waiting = false; + atomicAnd(&(t->flags), ~Thread::WaitingFlag); return; } else { @@ -2572,7 +2997,7 @@ monitorWait(Thread* t, object monitor, int64_t time) monitorDepth(t, monitor) = depth; - if (t->waiting) { + if (t->flags & Thread::WaitingFlag) { monitorRemoveWait(t, monitor); } else { expect(t, not monitorFindWait(t, monitor)); @@ -2592,7 +3017,7 @@ monitorPollWait(Thread* t, object monitor) if (next) { monitorWaitHead(t, monitor) = next->waitNext; - next->waiting = false; + atomicAnd(&(next->flags), ~Thread::WaitingFlag); next->waitNext = 0; if (next == monitorWaitTail(t, monitor)) { monitorWaitTail(t, monitor) = 0; @@ -2630,6 +3055,21 @@ monitorNotifyAll(Thread* t, object monitor) while (monitorNotify(t, monitor)) { } } +class ObjectMonitorResource { + public: + ObjectMonitorResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + monitorAcquire(protector.t, o); + } + + ~ObjectMonitorResource() { + monitorRelease(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + object objectMonitor(Thread* t, object o, bool createNew); @@ -2644,8 +3084,7 @@ acquire(Thread* t, object o) object m = objectMonitor(t, o, true); if (DebugMonitors) { - fprintf(stderr, "thread %p acquires %p for %x\n", - t, m, hash); + fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } monitorAcquire(t, m); @@ -2662,8 +3101,7 @@ release(Thread* t, object o) object m = objectMonitor(t, o, false); if (DebugMonitors) { - fprintf(stderr, "thread %p releases %p for %x\n", - t, m, hash); + fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } monitorRelease(t, m); @@ -2690,10 +3128,10 @@ wait(Thread* t, object o, int64_t milliseconds) bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { - t->exception = makeInterruptedException(t); + throwNew(t, Machine::InterruptedExceptionType); } } else { - t->exception = makeIllegalMonitorStateException(t); + throwNew(t, Machine::IllegalMonitorStateExceptionType); } if (DebugMonitors) { @@ -2722,7 +3160,7 @@ notify(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotify(t, m); } else { - t->exception = makeIllegalMonitorStateException(t); + throwNew(t, Machine::IllegalMonitorStateExceptionType); } } @@ -2739,32 +3177,16 @@ notifyAll(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotifyAll(t, m); } else { - t->exception = makeIllegalMonitorStateException(t); + throwNew(t, Machine::IllegalMonitorStateExceptionType); } } inline void -interrupt(Thread*, Thread* target) +interrupt(Thread* t, Thread* target) { - target->systemThread->interrupt(); -} - -inline void -setDaemon(Thread* t, object thread, bool daemon) -{ - ACQUIRE_RAW(t, t->m->stateLock); - - if ((threadDaemon(t, thread) != 0) != daemon) { - threadDaemon(t, thread) = daemon; - - if (daemon) { - ++ t->m->daemonCount; - } else { - expect(t, t->m->daemonCount); - -- t->m->daemonCount; - } - - t->m->stateLock->notifyAll(t->systemThread); + if (acquireSystem(t, target)) { + target->systemThread->interrupt(); + releaseSystem(t, target); } } @@ -2910,11 +3332,10 @@ resolveClassInObject(Thread* t, object loader, object container, unsigned classOffset) { object o = cast(container, classOffset); - if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { + if (objectClass(t, o) == type(t, Machine::ByteArrayType)) { PROTECT(t, container); o = resolveClass(t, loader, o); - if (UNLIKELY(t->exception)) return 0; set(t, container, classOffset, o); } @@ -2925,11 +3346,10 @@ inline object resolveClassInPool(Thread* t, object loader, object method, unsigned index) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); - if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType)) { + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); o = resolveClass(t, loader, referenceName(t, o)); - if (UNLIKELY(t->exception)) return 0; set(t, codePool(t, methodCode(t, method)), SingletonBody + (index * BytesPerWord), o); @@ -2947,10 +3367,10 @@ resolveClassInPool(Thread* t, object method, unsigned index) inline object resolve(Thread* t, object loader, object method, unsigned index, object (*find)(vm::Thread*, object, object, object), - object (*makeError)(vm::Thread*, object)) + Machine::Type errorType) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); - if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType)) + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); @@ -2958,12 +3378,10 @@ resolve(Thread* t, object loader, object method, unsigned index, PROTECT(t, reference); object class_ = resolveClassInObject(t, loader, o, ReferenceClass); - if (UNLIKELY(t->exception)) return 0; o = findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), - find, makeError); - if (UNLIKELY(t->exception)) return 0; + find, errorType); set(t, codePool(t, methodCode(t, method)), SingletonBody + (index * BytesPerWord), o); @@ -2976,7 +3394,7 @@ inline object resolveField(Thread* t, object loader, object method, unsigned index) { return resolve(t, loader, method, index, findFieldInClass, - makeNoSuchFieldError); + Machine::NoSuchFieldErrorType); } inline object @@ -2990,7 +3408,7 @@ inline object resolveMethod(Thread* t, object loader, object method, unsigned index) { return resolve(t, loader, method, index, findMethodInClass, - makeNoSuchMethodError); + Machine::NoSuchMethodErrorType); } inline object @@ -3000,9 +3418,163 @@ resolveMethod(Thread* t, object method, unsigned index) (t, classLoader(t, methodClass(t, method)), method, index); } +object +vectorAppend(Thread*, object, object); + +inline object +getClassRuntimeDataIfExists(Thread* t, object c) +{ + if (classRuntimeDataIndex(t, c)) { + return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), + classRuntimeDataIndex(t, c) - 1); + } else { + return 0; + } +} + +inline object +getClassRuntimeData(Thread* t, object c) +{ + if (classRuntimeDataIndex(t, c) == 0) { + PROTECT(t, c); + + ACQUIRE(t, t->m->classLock); + + if (classRuntimeDataIndex(t, c) == 0) { + object runtimeData = makeClassRuntimeData(t, 0, 0, 0, 0); + + setRoot(t, Machine::ClassRuntimeDataTable, vectorAppend + (t, root(t, Machine::ClassRuntimeDataTable), runtimeData)); + + classRuntimeDataIndex(t, c) = vectorSize + (t, root(t, Machine::ClassRuntimeDataTable)); + } + } + + return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), + classRuntimeDataIndex(t, c) - 1); +} + +inline object +getMethodRuntimeData(Thread* t, object method) +{ + if (methodRuntimeDataIndex(t, method) == 0) { + PROTECT(t, method); + + ACQUIRE(t, t->m->classLock); + + if (methodRuntimeDataIndex(t, method) == 0) { + object runtimeData = makeMethodRuntimeData(t, 0); + + setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend + (t, root(t, Machine::MethodRuntimeDataTable), runtimeData)); + + methodRuntimeDataIndex(t, method) = vectorSize + (t, root(t, Machine::MethodRuntimeDataTable)); + } + } + + return vectorBody(t, root(t, Machine::MethodRuntimeDataTable), + methodRuntimeDataIndex(t, method) - 1); +} + +inline object +getJClass(Thread* t, object c) +{ + PROTECT(t, c); + + object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); + if (jclass == 0) { + ACQUIRE(t, t->m->classLock); + + jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); + if (jclass == 0) { + jclass = t->m->classpath->makeJclass(t, c); + + set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass); + } + } + + return jclass; +} + +inline object +primitiveClass(Thread* t, char name) +{ + switch (name) { + case 'B': return type(t, Machine::JbyteType); + case 'C': return type(t, Machine::JcharType); + case 'D': return type(t, Machine::JdoubleType); + case 'F': return type(t, Machine::JfloatType); + case 'I': return type(t, Machine::JintType); + case 'J': return type(t, Machine::JlongType); + case 'S': return type(t, Machine::JshortType); + case 'V': return type(t, Machine::JvoidType); + case 'Z': return type(t, Machine::JbooleanType); + default: throwNew(t, Machine::IllegalArgumentExceptionType); + } +} + +inline void +registerNative(Thread* t, object method, void* function) +{ + PROTECT(t, method); + + expect(t, methodFlags(t, method) & ACC_NATIVE); + + object native = makeNative(t, function, false); + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, method); + + // ensure other threads only see the methodRuntimeDataNative field + // populated once the object it points to has been populated: + storeStoreMemoryBarrier(); + + set(t, runtimeData, MethodRuntimeDataNative, native); +} + +inline void +unregisterNatives(Thread* t, object c) +{ + if (classMethodTable(t, c)) { + for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { + object method = arrayBody(t, classMethodTable(t, c), i); + if (methodFlags(t, method) & ACC_NATIVE) { + set(t, getMethodRuntimeData(t, method), MethodRuntimeDataNative, 0); + } + } + } +} + +object +getCaller(Thread* t, unsigned target); + +object +defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); + void dumpHeap(Thread* t, FILE* out); +inline object +methodClone(Thread* t, object method) +{ + return makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodNativeID(t, method), + methodRuntimeDataIndex(t, method), + methodName(t, method), + methodSpec(t, method), + methodAddendum(t, method), + methodClass(t, method), + methodCode(t, method)); +} + } // namespace vm void diff --git a/src/main.cpp b/src/main.cpp index 383e324a3c..9996e6078d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -13,6 +13,9 @@ #include "string.h" #include "jni.h" +#include "system.h" +#include "finder.h" + #if (defined __MINGW32__) || (defined _MSC_VER) # define PATH_SEPARATOR ';' #else @@ -50,8 +53,105 @@ class RuntimeArray { #endif // not _MSC_VER +#ifdef BOOT_LIBRARY + +// since we aren't linking against libstdc++, we must implement this +// ourselves: +extern "C" void __cxa_pure_virtual(void) { abort(); } + +// we link against a System implmentation, which requires this at link +// time, but it should not be used at runtime: +extern "C" uint64_t +vmNativeCall(void*, void*, unsigned, unsigned) +{ + abort(); + // abort is not declared __declspec(noreturn) on MSVC, so we have to + // pretend it might return to make the compiler happy: + return 0; +} + +#endif // BOOT_LIBRARY + namespace { +bool +readLine(const uint8_t* base, unsigned total, unsigned* start, + unsigned* length) +{ + const uint8_t* p = base + *start; + const uint8_t* end = base + total; + while (p != end and (*p == '\n' or *p == '\r')) ++ p; + + *start = p - base; + while (p != end and not (*p == '\n' or *p == '\r')) ++ p; + + *length = (p - base) - *start; + + return *length != 0; +} + +const char* +mainClass(const char* jar) +{ + using namespace vm; + + System* system = makeSystem(0); + + class MyAllocator: public Allocator { + public: + MyAllocator(System* s): s(s) { } + + virtual void* tryAllocate(unsigned size) { + return s->tryAllocate(size); + } + + virtual void* allocate(unsigned size) { + void* p = tryAllocate(size); + if (p == 0) { + abort(s); + } + return p; + } + + virtual void free(const void* p, unsigned) { + s->free(p); + } + + System* s; + } allocator(system); + + Finder* finder = makeFinder(system, &allocator, jar, 0); + + char* result = 0; + + System::Region* region = finder->find("META-INF/MANIFEST.MF"); + if (region) { + unsigned start = 0; + unsigned length; + while (readLine(region->start(), region->length(), &start, &length)) { + const unsigned PrefixLength = 12; + if (strncmp("Main-Class: ", reinterpret_cast + (region->start() + start), PrefixLength) == 0) + { + result = static_cast(malloc(length + 1 - PrefixLength)); + memcpy(result, region->start() + start + PrefixLength, + length - PrefixLength); + result[length - PrefixLength] = 0; + break; + } + start += length; + } + + region->dispose(); + } + + finder->dispose(); + + system->dispose(); + + return result; +} + void usageAndExit(const char* name) { @@ -63,7 +163,7 @@ usageAndExit(const char* name) "\t[-Xbootclasspath:]\n" "\t[-Xbootclasspath/a:]\n" "\t[-D= ...]\n" - "\t [ ...]\n", name); + "\t{|-jar } [ ...]\n", name); exit(-1); } @@ -78,6 +178,7 @@ main(int ac, const char** av) vmArgs.ignoreUnrecognized = JNI_TRUE; const char* class_ = 0; + const char* jar = 0; int argc = 0; const char** argv = 0; const char* classpath = "."; @@ -87,12 +188,17 @@ main(int ac, const char** av) or strcmp(av[i], "-classpath") == 0) { classpath = av[++i]; + } else if (strcmp(av[i], "-jar") == 0) + { + jar = av[++i]; } else if (strncmp(av[i], "-X", 2) == 0 or strncmp(av[i], "-D", 2) == 0) { ++ vmArgs.nOptions; } else { - class_ = av[i++]; + if (jar == 0) { + class_ = av[i++]; + } if (i < ac) { argc = ac - i; argv = av + i; @@ -101,11 +207,18 @@ main(int ac, const char** av) } } -#ifdef BOOT_LIBRARY - ++ vmArgs.nOptions; -#endif + if (jar) { + classpath = jar; + + class_ = mainClass(jar); -#ifdef BOOT_CLASSPATH + if (class_ == 0) { + fprintf(stderr, "Main-Class manifest header not found in %s\n", jar); + exit(-1); + } + } + +#ifdef BOOT_LIBRARY ++ vmArgs.nOptions; #endif @@ -127,11 +240,6 @@ main(int ac, const char** av) = const_cast("-Davian.bootimage=" BOOT_IMAGE); #endif -#ifdef BOOT_CLASSPATH - vmArgs.options[optionIndex++].optionString - = const_cast("-Xbootclasspath:" BOOT_CLASSPATH); -#endif - #ifdef BOOT_LIBRARY vmArgs.options[optionIndex++].optionString = const_cast("-Davian.bootstrap=" BOOT_LIBRARY); @@ -178,6 +286,11 @@ main(int ac, const char** av) JNIEnv* e = static_cast(env); jclass c = e->FindClass(class_); + + if (jar) { + free(const_cast(class_)); + } + if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { diff --git a/src/openjdk/caseSensitive/WS2tcpip.h b/src/openjdk/caseSensitive/WS2tcpip.h new file mode 100644 index 0000000000..5caab3e7f6 --- /dev/null +++ b/src/openjdk/caseSensitive/WS2tcpip.h @@ -0,0 +1 @@ +#include "ws2tcpip.h" diff --git a/src/openjdk/caseSensitive/Wincon.h b/src/openjdk/caseSensitive/Wincon.h new file mode 100644 index 0000000000..40d2ad2a68 --- /dev/null +++ b/src/openjdk/caseSensitive/Wincon.h @@ -0,0 +1,3 @@ +// Console_md.c #includes "Wincon.h", which only matches "wincon.h" on +// a case insensive filesystem, so we redirect here. +#include "wincon.h" diff --git a/src/openjdk/jni_md.h b/src/openjdk/jni_md.h new file mode 100644 index 0000000000..bda8d5ef35 --- /dev/null +++ b/src/openjdk/jni_md.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef JNI_MD_H +#define JNI_MD_H + +#include "stdint.h" + +#if (defined __MINGW32__) || (defined _MSC_VER) +# define JNIEXPORT __declspec(dllexport) +# define JNICALL __stdcall +#else // not (defined __MINGW32__) || (defined _MSC_VER) +# define JNIEXPORT __attribute__ ((visibility("default"))) +# define JNICALL +#endif // not (defined __MINGW32__) || (defined _MSC_VER) + +#define JNIIMPORT + +typedef int32_t jint; +typedef int64_t jlong; +typedef int8_t jbyte; + +#endif//JNI_MD_H diff --git a/src/openjdk/my_net_util.c b/src/openjdk/my_net_util.c new file mode 100644 index 0000000000..11728df231 --- /dev/null +++ b/src/openjdk/my_net_util.c @@ -0,0 +1,20 @@ +#define JNI_OnLoad net_JNI_OnLoad +#include "net_util.c" + +#ifdef _WIN32 + +#undef IN6_SET_ADDR_UNSPECIFIED +#define IN6_SET_ADDR_UNSPECIFIED(a) \ + memset((a)->s6_bytes,0,sizeof(struct in6_addr)) + +void +IN6ADDR_SETANY(struct sockaddr_in6 *a) +{ + a->sin6_family = AF_INET6; + a->sin6_port = 0; + a->sin6_flowinfo = 0; + IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); + a->sin6_scope_id = 0; +} + +#endif diff --git a/src/posix.cpp b/src/posix.cpp index 0d34e2828a..b885e422fc 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,10 +8,11 @@ There is NO WARRANTY for this software. See license.txt for details. */ +#define __STDC_CONSTANT_MACROS + #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" # undef assert -# define _XOPEN_SOURCE #endif #include "sys/mman.h" @@ -28,6 +29,7 @@ #include "sys/ucontext.h" #include "stdint.h" #include "dirent.h" +#include "sched.h" #include "arch.h" #include "system.h" @@ -65,13 +67,19 @@ const int AltSegFaultSignal = SIGBUS; const int AltSegFaultSignal = InvalidSignal; #endif const unsigned AltSegFaultSignalIndex = 3; +const int PipeSignal = SIGPIPE; +const unsigned PipeSignalIndex = 4; +const int DivideByZeroSignal = SIGFPE; +const unsigned DivideByZeroSignalIndex = 5; const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal, - AltSegFaultSignal }; + AltSegFaultSignal, + PipeSignal, + DivideByZeroSignal }; -const unsigned SignalCount = 4; +const unsigned SignalCount = 6; class MySystem; MySystem* system; @@ -135,6 +143,12 @@ class MySystem: public System { r->setInterrupted(true); pthread_kill(thread, InterruptSignal); + + // pthread_kill won't necessarily wake a thread blocked in + // pthread_cond_{timed}wait (it does on Linux but not Mac OS), + // so we signal the condition as well: + int rv UNUSED = pthread_cond_signal(&condition); + expect(s, rv == 0); } virtual void join() { @@ -287,7 +301,9 @@ class MySystem: public System { owner_ = 0; pthread_mutex_unlock(&mutex); - if (time) { + // pretend anything greater than one million years (in + // milliseconds) is infinity so as to avoid overflow: + if (time and time < INT64_C(31536000000000000)) { int64_t then = s->now() + time; timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 }; int rv UNUSED = pthread_cond_timedwait @@ -465,13 +481,12 @@ class MySystem: public System { class Library: public System::Library { public: Library(System* s, void* p, const char* name, unsigned nameLength, - bool mapName, bool isMain): + bool isMain): s(s), p(p), mainExecutable(isMain), name_(name), nameLength(nameLength), - mapName_(mapName), next_(0) { } @@ -483,10 +498,6 @@ class MySystem: public System { return name_; } - virtual bool mapName() { - return mapName_; - } - virtual System::Library* next() { return next_; } @@ -500,7 +511,7 @@ class MySystem: public System { fprintf(stderr, "close %p\n", p); } - if (!mainExecutable) dlclose(p); + if (not mainExecutable) dlclose(p); if (next_) { next_->disposeAll(); @@ -518,7 +529,6 @@ class MySystem: public System { bool mainExecutable; const char* name_; unsigned nameLength; - bool mapName_; System::Library* next_; }; @@ -529,7 +539,10 @@ class MySystem: public System { expect(this, system == 0); system = this; + memset(handlers, 0, sizeof(handlers)); + registerHandler(&nullHandler, InterruptSignalIndex); + registerHandler(&nullHandler, PipeSignalIndex); registerHandler(&nullHandler, VisitSignalIndex); expect(this, make(&visitLock) == 0); @@ -629,14 +642,45 @@ class MySystem: public System { return s; } - virtual Status visit(System::Thread* st, System::Thread* sTarget, + virtual Status handleDivideByZero(SignalHandler* handler) { + return registerHandler(handler, DivideByZeroSignalIndex); + } + + virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { assert(this, st != sTarget); - Thread* t = static_cast(st); Thread* target = static_cast(sTarget); +#ifdef __APPLE__ + // On Mac OS, signals sent using pthread_kill are never delivered + // if the target thread is blocked (e.g. acquiring a lock or + // waiting on a condition), so we can't rely on it and must use + // the Mach-specific thread execution API instead. + + mach_port_t port = pthread_mach_thread_np(target->thread); + + if (thread_suspend(port)) return -1; + + THREAD_STATE_TYPE state; + mach_msg_type_number_t stateCount = THREAD_STATE_COUNT; + kern_return_t rv = thread_get_state + (port, THREAD_STATE, reinterpret_cast(&state), + &stateCount); + + if (rv == 0) { + visitor->visit(reinterpret_cast(THREAD_STATE_IP(state)), + reinterpret_cast(THREAD_STATE_STACK(state)), + reinterpret_cast(THREAD_STATE_LINK(state))); + } + + thread_resume(port); + + return rv ? -1 : 0; +#else // not __APPLE__ + Thread* t = static_cast(st); + ACQUIRE_MONITOR(t, visitLock); while (threadVisitor) visitLock->wait(t, 0); @@ -646,15 +690,23 @@ class MySystem: public System { int rv = pthread_kill(target->thread, VisitSignal); + int result; if (rv == 0) { while (visitTarget) visitLock->wait(t, 0); - threadVisitor = 0; - - return 0; + result = 0; } else { - return -1; + visitTarget = 0; + + result = -1; } + + threadVisitor = 0; + + system->visitLock->notifyAll(t); + + return result; +#endif // not __APPLE__ } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, @@ -696,43 +748,43 @@ class MySystem: public System { return status; } - virtual FileType identify(const char* name) { + virtual FileType stat(const char* name, unsigned* length) { struct stat s; - int r = stat(name, &s); + int r = ::stat(name, &s); if (r == 0) { if (S_ISREG(s.st_mode)) { + *length = s.st_size; return TypeFile; } else if (S_ISDIR(s.st_mode)) { + *length = 0; return TypeDirectory; } else { + *length = 0; return TypeUnknown; } } else { + *length = 0; return TypeDoesNotExist; } } + virtual const char* libraryPrefix() { + return SO_PREFIX; + } + + virtual const char* librarySuffix() { + return SO_SUFFIX; + } + virtual Status load(System::Library** lib, - const char* name, - bool mapName) + const char* name) { - void* p; - bool alreadyAllocated = false; - bool isMain = false; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName and name) { - unsigned size = nameLength + 3 + sizeof(SO_SUFFIX); - char buffer[size]; - vm::snprintf(buffer, size, "lib%s" SO_SUFFIX, name); - p = dlopen(buffer, RTLD_LAZY | RTLD_LOCAL); - } else { - if (!name) { - pathOfExecutable(this, &name, &nameLength); - alreadyAllocated = true; - isMain = true; - } - p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); + bool isMain = name == 0; + if (isMain) { + pathOfExecutable(this, &name, &nameLength); } + void* p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); if (p) { if (Verbose) { @@ -743,7 +795,7 @@ class MySystem: public System { if (name) { n = static_cast(allocate(this, nameLength + 1)); memcpy(n, name, nameLength + 1); - if (alreadyAllocated) { + if (isMain) { free(name); } } else { @@ -751,11 +803,13 @@ class MySystem: public System { } *lib = new (allocate(this, sizeof(Library))) - Library(this, p, n, nameLength, mapName, isMain); + Library(this, p, n, nameLength, isMain); return 0; } else { -// fprintf(stderr, "dlerror: %s\n", dlerror()); + if (Verbose) { + fprintf(stderr, "dlerror opening %s: %s\n", name, dlerror()); + } return 1; } } @@ -764,6 +818,10 @@ class MySystem: public System { return ':'; } + virtual char fileSeparator() { + return '/'; + } + virtual int64_t now() { timeval tv = { 0, 0 }; gettimeofday(&tv, 0); @@ -771,6 +829,10 @@ class MySystem: public System { (static_cast(tv.tv_usec) / 1000); } + virtual void yield() { + sched_yield(); + } + virtual void exit(int code) { ::exit(code); } @@ -784,6 +846,7 @@ class MySystem: public System { registerHandler(0, InterruptSignalIndex); registerHandler(0, VisitSignalIndex); + registerHandler(0, PipeSignalIndex); system = 0; ::free(this); @@ -806,14 +869,15 @@ handleSignal(int signal, siginfo_t* info, void* context) { ucontext_t* c = static_cast(context); -#ifndef BASE_REGISTER -# define BASE_REGISTER(x) 0 -#endif - void* ip = reinterpret_cast(IP_REGISTER(c)); - void* base = reinterpret_cast(BASE_REGISTER(c)); void* stack = reinterpret_cast(STACK_REGISTER(c)); void* thread = reinterpret_cast(THREAD_REGISTER(c)); + void* link = reinterpret_cast(LINK_REGISTER(c)); +#ifdef FRAME_REGISTER + void* frame = reinterpret_cast(FRAME_REGISTER(c)); +#else + void* frame = 0; +#endif unsigned index; @@ -821,7 +885,7 @@ handleSignal(int signal, siginfo_t* info, void* context) case VisitSignal: { index = VisitSignalIndex; - system->threadVisitor->visit(ip, base, stack); + system->threadVisitor->visit(ip, stack, link); System::Thread* t = system->visitTarget; system->visitTarget = 0; @@ -831,14 +895,27 @@ handleSignal(int signal, siginfo_t* info, void* context) } break; case SegFaultSignal: - case AltSegFaultSignal: { - if (signal == SegFaultSignal) { + case AltSegFaultSignal: + case DivideByZeroSignal: { + switch (signal) { + case SegFaultSignal: index = SegFaultSignalIndex; - } else { + break; + + case AltSegFaultSignal: index = AltSegFaultSignalIndex; + break; + + case DivideByZeroSignal: + index = DivideByZeroSignalIndex; + break; + + default: + abort(); } + bool jump = system->handlers[index]->handleSignal - (&ip, &base, &stack, &thread); + (&ip, &frame, &stack, &thread); if (jump) { // I'd like to use setcontext here (and get rid of the @@ -852,7 +929,7 @@ handleSignal(int signal, siginfo_t* info, void* context) sigaddset(&set, signal); sigprocmask(SIG_UNBLOCK, &set, 0); - vmJump(ip, base, stack, thread, 0, 0); + vmJump(ip, frame, stack, thread, 0, 0); } } break; @@ -860,10 +937,16 @@ handleSignal(int signal, siginfo_t* info, void* context) index = InterruptSignalIndex; } break; + case PipeSignal: { + index = PipeSignalIndex; + } break; + default: abort(); } - if (system->oldHandlers[index].sa_flags & SA_SIGINFO) { + if (system->oldHandlers[index].sa_flags & SA_SIGINFO + and system->oldHandlers[index].sa_sigaction) + { system->oldHandlers[index].sa_sigaction(signal, info, context); } else if (system->oldHandlers[index].sa_handler) { system->oldHandlers[index].sa_handler(signal); @@ -871,6 +954,7 @@ handleSignal(int signal, siginfo_t* info, void* context) switch (signal) { case VisitSignal: case InterruptSignal: + case PipeSignal: break; default: diff --git a/src/powerpc.S b/src/powerpc.S index fce2079af7..2b26f7985f 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -17,14 +17,15 @@ #define GPR_COUNT 8 #define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) #define LOCAL(x) L##x - + #ifdef __APPLE__ -.globl _vmNativeCall -_vmNativeCall: +# define GLOBAL(x) _##x #else -.globl vmNativeCall -vmNativeCall: +# define GLOBAL(x) x #endif + +.globl GLOBAL(vmNativeCall) +GLOBAL(vmNativeCall): // save return address mflr r0 stw r0,8(r1) @@ -151,16 +152,80 @@ LOCAL(exit): // return blr -#ifdef __APPLE__ -.globl _vmJump -_vmJump: -#else -.globl vmJump -vmJump: -#endif +.globl GLOBAL(vmJump) +GLOBAL(vmJump): mtlr r3 mr r1,r5 mr r13,r6 mr r4,r7 mr r3,r8 blr + +#define CHECKPOINT_THREAD 4 +#define CHECKPOINT_STACK 24 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // r3: function + // r4: arguments + // r5: checkpoint + + mflr r0 + stw r0,8(r1) + + stwu r1,-(MEMORY_BASE+88)(r1) + + stw r13,MEMORY_BASE+0(r1) + stw r14,MEMORY_BASE+4(r1) + stw r15,MEMORY_BASE+8(r1) + stw r16,MEMORY_BASE+12(r1) + stw r17,MEMORY_BASE+16(r1) + stw r18,MEMORY_BASE+20(r1) + stw r19,MEMORY_BASE+24(r1) + stw r20,MEMORY_BASE+28(r1) + stw r21,MEMORY_BASE+32(r1) + stw r22,MEMORY_BASE+36(r1) + stw r23,MEMORY_BASE+40(r1) + stw r24,MEMORY_BASE+44(r1) + stw r25,MEMORY_BASE+48(r1) + stw r26,MEMORY_BASE+52(r1) + stw r27,MEMORY_BASE+56(r1) + stw r28,MEMORY_BASE+60(r1) + stw r29,MEMORY_BASE+64(r1) + stw r30,MEMORY_BASE+68(r1) + stw r31,MEMORY_BASE+72(r1) + + stw r1,CHECKPOINT_STACK(r5) + + mr r6,r3 + lwz r3,CHECKPOINT_THREAD(r5) + + mtctr r6 + bctrl + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + lwz r13,MEMORY_BASE+0(r1) + lwz r14,MEMORY_BASE+4(r1) + lwz r15,MEMORY_BASE+8(r1) + lwz r16,MEMORY_BASE+12(r1) + lwz r17,MEMORY_BASE+16(r1) + lwz r18,MEMORY_BASE+20(r1) + lwz r19,MEMORY_BASE+24(r1) + lwz r20,MEMORY_BASE+28(r1) + lwz r21,MEMORY_BASE+32(r1) + lwz r22,MEMORY_BASE+36(r1) + lwz r23,MEMORY_BASE+40(r1) + lwz r24,MEMORY_BASE+44(r1) + lwz r25,MEMORY_BASE+48(r1) + lwz r26,MEMORY_BASE+52(r1) + lwz r27,MEMORY_BASE+56(r1) + lwz r28,MEMORY_BASE+60(r1) + lwz r29,MEMORY_BASE+64(r1) + lwz r30,MEMORY_BASE+68(r1) + lwz r31,MEMORY_BASE+72(r1) + + lwz r1,0(r1) + lwz r0,8(r1) + mtlr r0 + blr diff --git a/src/powerpc.cpp b/src/powerpc.cpp index a983f7039f..edcd587132 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -191,13 +191,15 @@ class MyBlock: public Assembler::Block { class Task; class ConstantPoolEntry; +class JumpPromise; class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), constantPool(0), constantPoolCount(0) + lastBlock(firstBlock), constantPool(0), jumps(0), constantPoolCount(0), + jumpCount(0) { } System* s; @@ -209,7 +211,9 @@ class Context { MyBlock* firstBlock; MyBlock* lastBlock; ConstantPoolEntry* constantPool; + JumpPromise* jumps; unsigned constantPoolCount; + unsigned jumpCount; }; class Task { @@ -312,6 +316,38 @@ offset(Context* c) Offset(c, c->lastBlock, c->code.length()); } +class JumpPromise: public Promise { + public: + JumpPromise(Context* c, uintptr_t target): + c(c), target(target), next(c->jumps), index(c->jumpCount++) + { + c->jumps = this; + } + + virtual bool resolved() { + return c->result != 0; + } + + virtual int64_t value() { + assert(c, resolved()); + + return reinterpret_cast + (c->result + c->code.length() + (index * BytesPerWord)); + } + + Context* c; + uintptr_t target; + JumpPromise* next; + unsigned index; +}; + +Promise* +jump(Context* c, uintptr_t target) +{ + return new (c->zone->allocate(sizeof(JumpPromise))) + JumpPromise(c, target); +} + bool bounded(int right, int left, int32_t v) { @@ -659,7 +695,6 @@ class ConstantPoolEntry: public Promise { Promise* constant; ConstantPoolEntry* next; void* address; - unsigned constantPoolCount; }; ConstantPoolEntry* @@ -1677,62 +1712,6 @@ jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) emit(c, b(0)); } -void -jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, beq(0)); -} - -void -jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, bne(0)); -} - -void -jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, bgt(0)); -} - -void -jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, bge(0)); -} - -void -jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, blt(0)); -} - -void -jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, ble(0)); -} - void return_(Context* c) { @@ -1747,6 +1726,60 @@ memoryBarrier(Context* c) // END OPERATION COMPILERS +unsigned +argumentFootprint(unsigned footprint) +{ + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); +} + +void +nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, + unsigned footprint, void* link, void*, + unsigned targetParameterFootprint, void** ip, void** stack) +{ + assert(c, *ip >= start); + assert(c, *ip <= start + (size / BytesPerWord)); + + int32_t* instruction = static_cast(*ip); + + if ((*start >> 26) == 32) { + // skip stack overflow check + start += 3; + } + + if (instruction <= start + 2 + or *instruction == lwz(0, 1, 8) + or *instruction == mtlr(0) + or *instruction == blr()) + { + *ip = link; + return; + } + + unsigned offset = footprint; + + if (TailCalls) { + if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { + offset += argumentFootprint(targetParameterFootprint) + - StackAlignmentInWords; + } + + // check for post-non-tail-call stack adjustment of the form "lwzx + // r0,0(r1); stwu r0,offset(r1)": + if (instruction < start + (size / BytesPerWord) - 1 + and (static_cast(instruction[1]) >> 16) == 0x9421) + { + offset += static_cast(instruction[1]); + } else if ((static_cast(*instruction) >> 16) == 0x9421) { + offset += static_cast(*instruction); + } + + // todo: check for and handle tail calls + } + + *ip = static_cast(*stack)[offset + 2]; + *stack = static_cast(*stack) + offset; +} void populateTables(ArchitectureContext* c) @@ -1903,7 +1936,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); + return ::argumentFootprint(footprint); + } + + virtual bool argumentAlignment() { + return false; } virtual unsigned argumentRegisterCount() { @@ -1972,6 +2009,15 @@ class MyArchitecture: public Assembler::Architecture { return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment); } + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) + { + ::nextFrame(&c, static_cast(start), size, footprint, link, + stackLimit, targetParameterFootprint, ip, stack); + } + virtual void* frameIp(void* stack) { return stack ? static_cast(stack)[2] : 0; } @@ -1996,12 +2042,6 @@ class MyArchitecture: public Assembler::Architecture { return 0; } - virtual void nextFrame(void** stack, void**) { - assert(&c, *static_cast(*stack) != *stack); - - *stack = *static_cast(*stack); - } - virtual BinaryOperation hasBinaryIntrinsic(Thread*, object) { return NoBinaryOperation; } @@ -2123,7 +2163,13 @@ class MyArchitecture: public Assembler::Architecture { case Divide: case Remainder: - if (BytesPerWord == 4 and aSize == 8) { + // todo: we shouldn't need to defer to thunks for integers which + // are smaller than or equal to tne native word size, but + // PowerPC doesn't generate traps for divide by zero, so we'd + // need to do the checks ourselves. Using an inline check + // should be faster than calling an out-of-line thunk, but the + // thunk is easier, so they's what we do for now. + if (true) {//if (BytesPerWord == 4 and aSize == 8) { *thunk = true; } else { *aTypeMask = (1 << RegisterOperand); @@ -2197,7 +2243,23 @@ class MyAssembler: public Assembler { return arch_; } - virtual void saveFrame(unsigned stackOffset, unsigned) { + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) + { + Register stack(StackRegister); + Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); + Constant handlerConstant(jump(&c, handler)); + branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, + &handlerConstant); + } + + virtual void saveFrame(unsigned stackOffset) { + Register returnAddress(0); + emit(&c, mflr(returnAddress.low)); + + Memory returnAddressDst(StackRegister, 8); + moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); + Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); @@ -2256,16 +2318,16 @@ class MyAssembler: public Assembler { moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); } - virtual void adjustFrame(unsigned footprint) { + virtual void adjustFrame(unsigned difference) { Register nextStack(0); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack); - Memory stackDst(StackRegister, -footprint * BytesPerWord); + Memory stackDst(StackRegister, -difference * BytesPerWord); moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst); } - virtual void popFrame() { + virtual void popFrame(unsigned) { Register stack(StackRegister); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); @@ -2312,15 +2374,17 @@ class MyAssembler: public Assembler { moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); } } else { - popFrame(); + popFrame(footprint); } } else { abort(&c); } } - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { - popFrame(); + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) + { + popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); @@ -2339,9 +2403,10 @@ class MyAssembler: public Assembler { return_(&c); } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) { - popFrame(); + popFrame(frameFootprint); Register tmp1(0); Memory stackSrc(StackRegister, 0); @@ -2405,12 +2470,20 @@ class MyAssembler: public Assembler { virtual void writeTo(uint8_t* dst) { c.result = dst; - + for (MyBlock* b = c.firstBlock; b; b = b->next) { memcpy(dst + b->start, c.code.data + b->offset, b->size); } + + for (JumpPromise* j = c.jumps; j; j = j->next) { + uint8_t* instruction + = dst + c.code.length() + (c.jumpCount - j->index - 1); + int32_t op = ::b(0); + memcpy(instruction, &op, BytesPerWord); + updateOffset(c.s, instruction, false, j->target); + } - unsigned index = c.code.length(); + unsigned index = c.code.length() + (c.jumpCount * BytesPerWord); assert(&c, index % BytesPerWord == 0); for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { e->address = dst + index; @@ -2427,7 +2500,7 @@ class MyAssembler: public Assembler { } } - virtual Promise* offset() { + virtual Promise* offset(bool) { return ::offset(&c); } @@ -2443,12 +2516,16 @@ class MyAssembler: public Assembler { return b; } + virtual void endEvent() { + // ignore + } + virtual unsigned length() { return c.code.length(); } - virtual unsigned scratchSize() { - return c.constantPoolCount * BytesPerWord; + virtual unsigned footerSize() { + return (c.jumpCount + c.constantPoolCount) * BytesPerWord; } virtual void dispose() { diff --git a/src/powerpc.h b/src/powerpc.h index 9a55c13266..b519ac8064 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -14,20 +14,39 @@ #include "types.h" #include "common.h" +#define VA_LIST(x) (&(x)) + #ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__srr0) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__r1) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__r13) +# include "mach/mach_types.h" +# include "mach/ppc/thread_act.h" +# include "mach/ppc/thread_status.h" + +# define THREAD_STATE PPC_THREAD_STATE +# define THREAD_STATE_TYPE ppc_thread_state_t +# define THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT + +# if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) +# define FIELD(x) __##x # else -# define IP_REGISTER(context) (context->uc_mcontext->ss.srr0) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.r1) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.r13) +# define FIELD(x) x # endif + +# define THREAD_STATE_IP(state) ((state).FIELD(srr0)) +# define THREAD_STATE_STACK(state) ((state).FIELD(r1)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(r13)) +# define THREAD_STATE_LINK(state) ((state).FIELD(lr)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) + #else -# define IP_REGISTER(context) (context->uc_mcontext.gregs[32]) -# define STACK_REGISTER(context) (context->uc_mcontext.gregs[1]) -# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[13]) +# error "non-Apple PowerPC-based platforms not yet supported" #endif extern "C" uint64_t diff --git a/src/process.cpp b/src/process.cpp index e4897dcaf0..b3a25ebe8e 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -153,13 +153,13 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, { unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false); // extra 6 is for code below: - RUNTIME_ARRAY(char, undecorated, undecoratedSize + 1 + 6); + THREAD_RUNTIME_ARRAY(t, char, undecorated, undecoratedSize + 1 + 6); makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(undecorated) + 1, method, false); unsigned decoratedSize = prefixLength + jniNameLength(t, method, true); // extra 6 is for code below: - RUNTIME_ARRAY(char, decorated, decoratedSize + 1 + 6); + THREAD_RUNTIME_ARRAY(t, char, decorated, decoratedSize + 1 + 6); makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1, method, true); @@ -203,25 +203,54 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, return 0; } +object +resolveNativeMethod(Thread* t, object method) +{ + void* p = resolveNativeMethod(t, method, "Avian_", 6, 3); + if (p) { + return makeNative(t, p, true); + } + + p = resolveNativeMethod(t, method, "Java_", 5, -1); + if (p) { + return makeNative(t, p, false); + } + + return 0; +} + } // namespace namespace vm { -void* -resolveNativeMethod(Thread* t, object method) +void +resolveNative(Thread* t, object method) { - void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3); - if (p) { - methodVmFlags(t, method) |= FastNative; - return p; - } + PROTECT(t, method); - p = ::resolveNativeMethod(t, method, "Java_", 5, -1); - if (p) { - return p; - } + assert(t, methodFlags(t, method) & ACC_NATIVE); - return 0; + initClass(t, methodClass(t, method)); + + if (methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) { + object native = resolveNativeMethod(t, method); + if (UNLIKELY(native == 0)) { + throwNew(t, Machine::UnsatisfiedLinkErrorType, "%s.%s%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); + } + + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, method); + + // ensure other threads only see the methodRuntimeDataNative field + // populated once the object it points to has been populated: + storeStoreMemoryBarrier(); + + set(t, runtimeData, MethodRuntimeDataNative, native); + } } int diff --git a/src/process.h b/src/process.h index 95da97cde8..27f7788a6b 100644 --- a/src/process.h +++ b/src/process.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -56,9 +56,6 @@ isSpecialMethod(Thread* t, object method, object class_) and isSuperclass(t, methodClass(t, method), class_); } -void* -resolveNativeMethod(Thread* t, object method); - inline void populateMultiArray(Thread* t, object array, int32_t* counts, unsigned index, unsigned dimensions) @@ -77,7 +74,8 @@ populateMultiArray(Thread* t, object array, int32_t* counts, &byteArrayBody(t, spec, 1), byteArrayLength(t, spec) - 1); - object class_ = resolveSystemClass(t, elementSpec); + object class_ = resolveClass + (t, classLoader(t, objectClass(t, array)), elementSpec); PROTECT(t, class_); for (int32_t i = 0; i < counts[index]; ++i) { @@ -89,6 +87,9 @@ populateMultiArray(Thread* t, object array, int32_t* counts, } } +void +resolveNative(Thread* t, object method); + int findLineNumber(Thread* t, object method, unsigned ip); diff --git a/src/processor.h b/src/processor.h index 398b2d930b..0b71ed1782 100644 --- a/src/processor.h +++ b/src/processor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -128,7 +128,7 @@ class Processor { DelayedPromise** addresses, object method) = 0; virtual void - visitRoots(HeapWalker* w) = 0; + visitRoots(Thread* t, HeapWalker* w) = 0; virtual unsigned* makeCallTable(Thread* t, HeapWalker* w) = 0; diff --git a/src/system.h b/src/system.h index fb3b85df80..6e2ea14721 100644 --- a/src/system.h +++ b/src/system.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -35,7 +35,7 @@ class System { class ThreadVisitor { public: - virtual void visit(void* ip, void* base, void* stack) = 0; + virtual void visit(void* ip, void* stack, void* link) = 0; }; class Runnable { @@ -87,9 +87,8 @@ class System { class Library { public: - virtual void* resolve(const char* function) = 0; + virtual void* resolve(const char* symbol) = 0; virtual const char* name() = 0; - virtual bool mapName() = 0; virtual Library* next() = 0; virtual void setNext(Library* lib) = 0; virtual void disposeAll() = 0; @@ -97,7 +96,7 @@ class System { class SignalHandler { public: - virtual bool handleSignal(void** ip, void** base, void** stack, + virtual bool handleSignal(void** ip, void** frame, void** stack, void** thread) = 0; }; @@ -127,17 +126,22 @@ class System { virtual Status make(Monitor**) = 0; virtual Status make(Local**) = 0; virtual Status handleSegFault(SignalHandler* handler) = 0; + virtual Status handleDivideByZero(SignalHandler* handler) = 0; virtual Status visit(Thread* thread, Thread* target, ThreadVisitor* visitor) = 0; virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, unsigned count, unsigned size, unsigned returnType) = 0; virtual Status map(Region**, const char* name) = 0; - virtual FileType identify(const char* name) = 0; + virtual FileType stat(const char* name, unsigned* length) = 0; virtual Status open(Directory**, const char* name) = 0; - virtual Status load(Library**, const char* name, bool mapName) = 0; + virtual const char* libraryPrefix() = 0; + virtual const char* librarySuffix() = 0; + virtual Status load(Library**, const char* name) = 0; virtual char pathSeparator() = 0; + virtual char fileSeparator() = 0; virtual int64_t now() = 0; + virtual void yield() = 0; virtual void exit(int code) = 0; virtual void abort() = 0; virtual void dispose() = 0; diff --git a/src/thunks.cpp b/src/thunks.cpp index f55c0018a9..4d863ecca4 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -48,4 +48,5 @@ THUNK(instanceOf64) THUNK(makeNewGeneral64) THUNK(makeNew64) THUNK(set) +THUNK(getJClass64) THUNK(gcIfNecessary) diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 0000000000..4036e7d197 --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef TOKENIZER_H +#define TOKENIZER_H + +namespace vm { + +class Tokenizer { + public: + class Token { + public: + Token(const char* s, unsigned length): s(s), length(length) { } + + const char* s; + unsigned length; + }; + + Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } + + bool hasMore() { + while (*s == delimiter) ++s; + return *s != 0; + } + + Token next() { + const char* p = s; + while (*s and *s != delimiter) ++s; + return Token(p, s - p); + } + + const char* s; + char delimiter; +}; + +} // namespace + +#endif//TOKENIZER_H diff --git a/src/type-generator.cpp b/src/type-generator.cpp index fc0fb72061..aed82c3f35 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -12,9 +12,13 @@ #include "stdio.h" #include "stdint.h" #include "string.h" -#include "assert.h" +#include "errno.h" #include "constants.h" +#include "finder.h" +#include "stream.h" + +#include "assert.h" #define UNREACHABLE abort() @@ -28,6 +32,8 @@ using namespace vm; namespace { +namespace local { + #ifndef POINTER_SIZE # define POINTER_SIZE sizeof(void*) #endif @@ -38,7 +44,7 @@ inline unsigned pad(unsigned size, unsigned alignment) { unsigned n = alignment; - while (size and n % size and n % BytesPerWord) ++ n; + while (size and n % size) ++ n; return n - alignment; } @@ -177,7 +183,7 @@ class Output { void write(int i) { static const int Size = 32; char s[Size]; - int c UNUSED = snprintf(s, Size, "%d", i); + int c UNUSED = ::snprintf(s, Size, "%d", i); assert(c > 0 and c < Size); write(s); } @@ -213,63 +219,6 @@ class FileOutput : public Output { } }; -class Stream { - public: - Stream(FILE* stream, bool close): - stream(stream), close(close) - { - assert(stream); - } - - ~Stream() { - if (close) fclose(stream); - } - - void skip(unsigned size) { - fseek(stream, size, SEEK_CUR); - } - - void read(uint8_t* data, unsigned size) { - fread(data, 1, size, stream); - } - - uint8_t read1() { - uint8_t v; - read(&v, 1); - return v; - } - - uint16_t read2() { - uint16_t a = read1(); - uint16_t b = read1(); - return (a << 8) | b; - } - - uint32_t read4() { - uint32_t a = read2(); - uint32_t b = read2(); - return (a << 16) | b; - } - - uint64_t read8() { - uint64_t a = read4(); - uint64_t b = read4(); - return (a << 32) | b; - } - - uint32_t readFloat() { - return read4(); - } - - uint64_t readDouble() { - return read8(); - } - - private: - FILE* stream; - bool close; -}; - class Object { public: typedef enum { @@ -400,6 +349,8 @@ class Array : public Scalar { o->typeName = typeName; o->name = name; o->elementSize = elementSize; + o->noassert = false; + o->nogc = false; return o; } }; @@ -455,7 +406,7 @@ memberTypeName(Object* o) } } -const char* +const char*& memberName(Object* o) { switch (o->type) { @@ -935,11 +886,11 @@ class MemberIterator { offset_(type->type == Object::Pod ? 0 : BytesPerWord), size_(0), padding_(0), - alignment_(0) + alignment_(BytesPerWord) { while (skipSupers and hasMore() and this->type != type) next(); padding_ = 0; - alignment_ = 0; + alignment_ = BytesPerWord; } bool hasMore() { @@ -973,7 +924,7 @@ class MemberIterator { case Object::Scalar: { size_ = memberSize(member); padding_ = pad(size_, alignment_); - alignment_ = (alignment_ + size_ + padding_) % BytesPerWord; + alignment_ = (alignment_ + size_ + padding_) % 8; } break; case Object::Array: { @@ -987,8 +938,11 @@ class MemberIterator { offset_ += padding_; -// printf("size: %d; padding: %d; alignment: %d; offset: %d;\n", -// size_, padding_, alignment_, offset_); + // fprintf(stderr, + // "type: %s; member: %s; size: %d; padding: %d; alignment: %d;" + // " offset: %d;\n", + // typeName(type), memberName(member), size_, padding_, alignment_, + // offset_); return member; } @@ -1087,6 +1041,27 @@ parseArray(Object* t, Object* p, Object* declarations) typeName, name, sizeOf(typeName, declarations)); } +Object* +parseMember(Object* t, Object* p, Object* declarations); + +Object* +parseMember(Object* t, Object* p, Object* declarations, bool* isNew) +{ + Object* member = parseMember(t, p, declarations); + for (MemberIterator it(t); it.hasMore();) { + Object* m = it.next(); + if (equal(memberName(m), memberName(member))) { + if (not equal(memberTypeName(m), memberTypeName(member))) { + abort(); + } + *isNew = false; + return m; + } + } + *isNew = true; + return member; +} + Object* parseMember(Object* t, Object* p, Object* declarations) { @@ -1094,13 +1069,24 @@ parseMember(Object* t, Object* p, Object* declarations) if (equal(spec, "array")) { return parseArray(t, cdr(p), declarations); } else if (equal(spec, "noassert")) { - Object* member = parseMember(t, cdr(p), declarations); + bool isNew; + Object* member = parseMember(t, cdr(p), declarations, &isNew); memberNoAssert(member) = true; - return member; + return isNew ? member : 0; } else if (equal(spec, "nogc")) { - Object* member = parseMember(t, cdr(p), declarations); + bool isNew; + Object* member = parseMember(t, cdr(p), declarations, &isNew); memberNoGC(member) = true; - return member; + return isNew ? member : 0; + } else if (equal(spec, "require")) { + bool isNew; + Object* member = parseMember(t, cdr(p), declarations, &isNew); + return isNew ? member : 0; + } else if (equal(spec, "alias")) { + bool isNew; + Object* member = parseMember(t, cdr(cdr(p)), declarations, &isNew); + memberName(member) = string(car(cdr(p))); + return 0; } else { return Scalar::make(t, declaration(spec, declarations), spec, string(car(cdr(p))), @@ -1120,7 +1106,9 @@ parseSubdeclaration(Object* t, Object* p, Object* declarations) assert(typeSuper(t)->type == Object::Type); } else { Object* member = parseMember(t, p, declarations); - addMember(t, member); + if (member) { + addMember(t, member); + } } } @@ -1311,14 +1299,6 @@ parseJavaClass(Object* type, Stream* s, Object* declarations) Object* member = Scalar::make (type, 0, memberType, name, sizeOf(memberType, declarations)); - if (equal(typeJavaName(type), "java/lang/ref/Reference") - and (equal(name, "vmNext") - or equal(name, "target") - or equal(name, "queue"))) - { - memberNoGC(member) = true; - } - addMember(type, member); } } @@ -1353,8 +1333,8 @@ parseJavaClass(Object* type, Stream* s, Object* declarations) } Object* -parseType(Object::ObjectType type, Object* p, Object* declarations, - const char* javaClassDirectory) +parseType(Finder* finder, Object::ObjectType type, Object* p, + Object* declarations) { const char* name = string(car(p)); @@ -1369,9 +1349,16 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, bool isJavaType = javaName and *javaName != '['; if (isJavaType) { - const char* file = append(javaClassDirectory, "/", javaName, ".class"); - Stream s(fopen(file, "rb"), true); + class Client: public Stream::Client { + public: + virtual void NO_RETURN handleError() { + abort(); + } + } client; + System::Region* region = finder->find(append(javaName, ".class")); + Stream s(&client, region->start(), region->length()); parseJavaClass(t, &s, declarations); + region->dispose(); } for (p = cdr(p); p; p = cdr(p)) { @@ -1379,8 +1366,10 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, parseSubdeclaration(t, car(p), declarations); } else { Object* member = parseMember(t, car(p), declarations); - assert(member->type == Object::Scalar); - addMember(t, member); + if (member) { + assert(member->type == Object::Scalar); + addMember(t, member); + } } } @@ -1396,14 +1385,13 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, } Object* -parseDeclaration(Object* p, Object* declarations, - const char* javaClassDirectory) +parseDeclaration(Finder* finder, Object* p, Object* declarations) { const char* spec = string(car(p)); if (equal(spec, "type")) { - return parseType(Object::Type, cdr(p), declarations, javaClassDirectory); + return parseType(finder, Object::Type, cdr(p), declarations); } else if (equal(spec, "pod")) { - return parseType(Object::Pod, cdr(p), declarations, javaClassDirectory); + return parseType(finder, Object::Pod, cdr(p), declarations); } else { fprintf(stderr, "unexpected declaration spec: %s\n", spec); abort(); @@ -1411,7 +1399,7 @@ parseDeclaration(Object* p, Object* declarations, } Object* -parse(Input* in, const char* javaClassDirectory) +parse(Finder* finder, Input* in) { Object* eos = Singleton::make(Object::Eos); List declarations; @@ -1419,7 +1407,7 @@ parse(Input* in, const char* javaClassDirectory) Object* o; while ((o = read(in, eos, 0)) != eos) { declarations.append - (parseDeclaration(o, declarations.first, javaClassDirectory)); + (parseDeclaration(finder, o, declarations.first)); } return declarations.first; @@ -1489,7 +1477,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) if (not unsafe) { out->write("const unsigned "); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); out->write(" = "); writeOffset(out, offset); @@ -1514,7 +1502,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) writeAccessorName(out, member, unsafe); if (memberOwner(member)->type == Object::Pod) { out->write("("); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write("*"); } else { out->write("(Thread* t UNUSED, object"); @@ -1530,13 +1518,13 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) out->write(" assert(t, t->m->unsafe or "); out->write("instanceOf(t, arrayBodyUnsafe"); out->write("(t, t->m->types, Machine::"); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write("Type)"); out->write(", o));\n"); if (member->type != Object::Scalar) { out->write(" assert(t, i < "); - out->write(::typeName(memberOwner(member))); + out->write(local::typeName(memberOwner(member))); out->write("Length(t, o));\n"); } } @@ -1566,7 +1554,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) out->write("["); } - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); if (member->type != Object::Scalar) { @@ -2184,66 +2172,135 @@ writeJavaInitializations(Output* out, Object* declarations) } } +void +writeNameInitialization(Output* out, Object* type) +{ + out->write("nameClass(t, Machine::"); + out->write(capitalize(typeName(type))); + out->write("Type, \"vm::"); + out->write(typeName(type)); + out->write("\");\n"); +} + +void +writeNameInitializations(Output* out, Object* declarations) +{ + for (Object* p = declarations; p; p = cdr(p)) { + Object* o = car(p); + if (o->type == Object::Type and typeJavaName(o) == 0) { + writeNameInitialization(out, o); + } + } +} + void usageAndExit(const char* command) { fprintf(stderr, - "usage: %s " + "usage: %s " "{enums,declarations,constructors,initializations," - "java-initializations}\n", + "java-initializations,name-initializations}\n", command); exit(-1); } +} // namespace local + } // namespace +extern "C" uint64_t +vmNativeCall(void*, void*, unsigned, unsigned) +{ + abort(); +} + +extern "C" void +vmJump(void*, void*, void*, void*, uintptr_t, uintptr_t) +{ + abort(); +} + int main(int ac, char** av) { - if ((ac != 2 and ac != 3) - or (ac == 3 - and not equal(av[2], "enums") - and not equal(av[2], "declarations") - and not equal(av[2], "constructors") - and not equal(av[2], "initializations") - and not equal(av[2], "java-initializations"))) + if (ac != 5 + or not (local::equal(av[4], "enums") + or local::equal(av[4], "declarations") + or local::equal(av[4], "constructors") + or local::equal(av[4], "initializations") + or local::equal(av[4], "java-initializations") + or local::equal(av[4], "name-initializations"))) { - usageAndExit(av[0]); + local::usageAndExit(av[0]); } - FileInput in(0, stdin, false); + System* system = makeSystem(0); - Object* declarations = parse(&in, av[1]); + class MyAllocator: public Allocator { + public: + MyAllocator(System* s): s(s) { } - FileOutput out(0, stdout, false); + virtual void* tryAllocate(unsigned size) { + return s->tryAllocate(size); + } - if (ac == 2 or equal(av[2], "enums")) { - writeEnums(&out, declarations); + virtual void* allocate(unsigned size) { + void* p = tryAllocate(size); + if (p == 0) { + abort(s); + } + return p; + } + + virtual void free(const void* p, unsigned) { + s->free(p); + } + + System* s; + } allocator(system); + + Finder* finder = makeFinder(system, &allocator, av[1], 0); + + FILE* inStream = ::fopen(av[2], "rb"); + if (inStream == 0) { + fprintf(stderr, "unable to open %s: %s\n", av[2], strerror(errno)); + return -1; } + local::FileInput in(0, inStream, false); - if (ac == 2 or equal(av[2], "declarations")) { + local::Object* declarations = local::parse(finder, &in); + + finder->dispose(); + system->dispose(); + + FILE* outStream = ::fopen(av[3], "wb"); + if (outStream == 0) { + fprintf(stderr, "unable to open %s: %s\n", av[3], strerror(errno)); + return -1; + } + local::FileOutput out(0, outStream, false); + + if (local::equal(av[4], "enums")) { + local::writeEnums(&out, declarations); + } else if (local::equal(av[4], "declarations")) { out.write("const unsigned TypeCount = "); - out.Output::write(typeCount(declarations)); + out.Output::write(local::typeCount(declarations)); out.write(";\n\n"); - writePods(&out, declarations); - writeAccessors(&out, declarations); - writeSizes(&out, declarations); - writeInitializerDeclarations(&out, declarations); - writeConstructorDeclarations(&out, declarations); - } - - if (ac == 2 or equal(av[2], "constructors")) { - writeInitializers(&out, declarations); - writeConstructors(&out, declarations); - } - - if (ac == 2 or equal(av[2], "initializations")) { - writeInitializations(&out, declarations); - } - - if (ac == 2 or equal(av[2], "java-initializations")) { - writeJavaInitializations(&out, declarations); + local::writePods(&out, declarations); + local::writeAccessors(&out, declarations); + local::writeSizes(&out, declarations); + local::writeInitializerDeclarations(&out, declarations); + local::writeConstructorDeclarations(&out, declarations); + } else if (local::equal(av[4], "constructors")) { + local::writeInitializers(&out, declarations); + local::writeConstructors(&out, declarations); + } else if (local::equal(av[4], "initializations")) { + local::writeInitializations(&out, declarations); + } else if (local::equal(av[4], "java-initializations")) { + local::writeJavaInitializations(&out, declarations); + } else if (local::equal(av[4], "name-initializations")) { + local::writeNameInitializations(&out, declarations); } return 0; diff --git a/src/types.def b/src/types.def index 184df800a0..8b8d980ffc 100644 --- a/src/types.def +++ b/src/types.def @@ -1,36 +1,71 @@ (type jobject java/lang/Object) -(type class java/lang/Class +(type class avian/VMClass (array void* vtable)) +(type jclass java/lang/Class + (require object vmClass)) + +(type jaccessibleObject java/lang/reflect/AccessibleObject) + +(type jfield java/lang/reflect/Field) + +(type jmethod java/lang/reflect/Method) + +(type jconstructor java/lang/reflect/Constructor) + +(type constantPool sun/reflect/ConstantPool) + (type singleton (array uintptr_t body)) (type classLoader java/lang/ClassLoader (object map)) -(type systemClassLoader avian/SystemClassLoader) +(type systemClassLoader avian/SystemClassLoader + (void* finder)) -(type accessibleObject java/lang/reflect/AccessibleObject) +(type field avian/VMField) -(type field java/lang/reflect/Field) - -(type method java/lang/reflect/Method) - -(type proxy java/lang/reflect/Proxy) +(type method avian/VMMethod) (type addendum avian/Addendum) (type classAddendum avian/ClassAddendum) -(type nativeMethodData - (void* function) - (uint16_t argumentTableSize) - (array uint8_t parameterTypes)) +(type methodAddendum avian/MethodAddendum) + +(type fieldAddendum avian/FieldAddendum) + +(type classRuntimeData + (object arrayClass) + (object jclass) + (object pool) + (object signers)) + +(type methodRuntimeData + (object native)) (type pointer (void* value)) +(type native + (void* function) + (uint8_t fast)) + +(type nativeIntercept + (extends native) + (object original)) + +(type finder + (void* finder) + (object name) + (object next)) + +(type region + (void* region) + (unsigned position)) + (pod exceptionHandler (uint16_t start) (uint16_t end) @@ -51,6 +86,7 @@ (object pool) (object exceptionHandlerTable) (object lineNumberTable) + (intptr_t compiled) (uint16_t maxStack) (uint16_t maxLocals) (array uint8_t body)) @@ -143,15 +179,25 @@ (type callbackReceiver avian/CallbackReceiver) -(type string java/lang/String) +(type string java/lang/String + (alias data object value) + (alias length uint32_t count) + (alias hashCode uint32_t hash)) -(type thread java/lang/Thread) +(type thread java/lang/Thread + (require object sleepLock) + (require object interruptLock) + (require uint8_t interrupted) + (require uint8_t unparked) + (alias peer uint64_t eetop)) (type threadGroup java/lang/ThreadGroup) (type stackTraceElement java/lang/StackTraceElement) -(type throwable java/lang/Throwable) +(type throwable java/lang/Throwable + (alias message object detailMessage) + (alias trace object backtrace)) (type exception java/lang/Exception) @@ -159,6 +205,8 @@ (type nullPointerException java/lang/NullPointerException) +(type arithmeticException java/lang/ArithmeticException) + (type illegalStateException java/lang/IllegalStateException) (type illegalArgumentException java/lang/IllegalArgumentException) @@ -185,6 +233,8 @@ (type virtualMachineError java/lang/VirtualMachineError) +(type outOfMemoryError java/lang/OutOfMemoryError) + (type stackOverflowError java/lang/StackOverflowError) (type linkageError java/lang/LinkageError) @@ -201,6 +251,10 @@ (type exceptionInInitializerError java/lang/ExceptionInInitializerError) +(type ioException java/io/IOException) + +(type fileNotFoundException java/io/FileNotFoundException) + (type incompatibleContinuationException avian/IncompatibleContinuationException) @@ -222,9 +276,17 @@ (type double java/lang/Double) -(type referenceQueue java/lang/ref/ReferenceQueue) +(type referenceQueue java/lang/ref/ReferenceQueue + (alias front object head)) -(type jreference java/lang/ref/Reference) +(type jreference java/lang/ref/Reference + (alias target object referent) + (alias queue object queue) + (alias jNext object next) + (alias vmNext object discovered) + (nogc object target) + (nogc object queue) + (nogc object vmNext)) (type weakReference java/lang/ref/WeakReference) diff --git a/src/util.cpp b/src/util.cpp index a15b57d77b..1c7702d853 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -66,32 +66,32 @@ inline object getTreeNodeValue(Thread*, object n) { return reinterpret_cast - (cast(n, TreeNodeValue) & PointerMask); + (alias(n, TreeNodeValue) & PointerMask); } inline void setTreeNodeValue(Thread* t, object n, object value) { - intptr_t red = cast(n, TreeNodeValue) & (~PointerMask); + intptr_t red = alias(n, TreeNodeValue) & (~PointerMask); set(t, n, TreeNodeValue, value); - cast(n, TreeNodeValue) |= red; + alias(n, TreeNodeValue) |= red; } inline bool treeNodeRed(Thread*, object n) { - return (cast(n, TreeNodeValue) & (~PointerMask)) == 1; + return (alias(n, TreeNodeValue) & (~PointerMask)) == 1; } inline void setTreeNodeRed(Thread*, object n, bool red) { if (red) { - cast(n, TreeNodeValue) |= 1; + alias(n, TreeNodeValue) |= 1; } else { - cast(n, TreeNodeValue) &= PointerMask; + alias(n, TreeNodeValue) &= PointerMask; } } @@ -108,7 +108,7 @@ cloneTreeNode(Thread* t, object n) object treeFind(Thread* t, object tree, intptr_t key, object sentinal, - intptr_t (*compare)(Thread* t, intptr_t key, object b)) + intptr_t (*compare)(Thread* t, intptr_t key, object b)) { object node = tree; while (node != sentinal) { @@ -140,6 +140,7 @@ treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node, object new_ = newRoot; PROTECT(t, new_); + int count = 0; while (old != sentinal) { c->ancestors = path(c, new_, c->ancestors); @@ -162,6 +163,13 @@ treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node, c->ancestors = c->ancestors->next; return; } + + if (++ count > 100) { + // if we've gone this deep, we probably have an unbalanced tree, + // which should only happen if there's a serious bug somewhere + // in our insertion process + abort(t); + } } setTreeNodeValue(t, new_, getTreeNodeValue(t, node)); @@ -318,8 +326,7 @@ hashMapFindNode(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); if (array) { @@ -367,9 +374,7 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), } if (oldArray) { - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); - + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) { object next; for (object p = arrayBody(t, oldArray, i); p; p = next) { @@ -407,8 +412,7 @@ hashMapInsert(Thread* t, object map, object key, object value, uint32_t h = hash(t, key); - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); @@ -432,7 +436,8 @@ hashMapInsert(Thread* t, object map, object key, object value, object r = makeWeakReference(t, 0, 0, 0, 0); jreferenceTarget(t, r) = key; jreferenceVmNext(t, r) = t->m->weakReferences; - k = t->m->weakReferences = r; + t->m->weakReferences = r; + k = r; array = hashMapArray(t, map); } @@ -465,8 +470,7 @@ hashMapRemove(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); object o = 0; @@ -533,11 +537,6 @@ vectorAppend(Thread* t, object vector, object value) vectorSize(t, vector) * BytesPerWord); } - memset(&vectorBody(t, newVector, vectorSize(t, vector) + 1), - 0, - (vectorLength(t, newVector) - vectorSize(t, vector) - 1) - * BytesPerWord); - vector = newVector; } @@ -546,6 +545,22 @@ vectorAppend(Thread* t, object vector, object value) return vector; } +object +growArray(Thread* t, object array) +{ + PROTECT(t, array); + + object newArray = makeArray + (t, array == 0 ? 16 : (arrayLength(t, array) * 2)); + + if (array) { + memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), + arrayLength(t, array)); + } + + return newArray; +} + object treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) diff --git a/src/util.h b/src/util.h index bf895f6bae..40a70b5bfb 100644 --- a/src/util.h +++ b/src/util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -84,6 +84,9 @@ listAppend(Thread* t, object list, object value); object vectorAppend(Thread* t, object vector, object value); +object +growArray(Thread* t, object array); + object treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)); diff --git a/src/windows.cpp b/src/windows.cpp index b0146334b6..4c75b80870 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -49,6 +49,11 @@ class MutexResource { HANDLE m; }; +const unsigned SegFaultIndex = 0; +const unsigned DivideByZeroIndex = 1; + +const unsigned HandlerCount = 2; + class MySystem; MySystem* system; @@ -91,7 +96,7 @@ class MySystem: public System { if (flags & Waiting) { int r UNUSED = SetEvent(event); - assert(s, r == 0); + assert(s, r != 0); } } @@ -457,11 +462,10 @@ class MySystem: public System { class Library: public System::Library { public: - Library(System* s, HMODULE handle, const char* name, bool mapName): + Library(System* s, HMODULE handle, const char* name): s(s), handle(handle), name_(name), - mapName_(mapName), next_(0) { } @@ -476,10 +480,6 @@ class MySystem: public System { return name_; } - virtual bool mapName() { - return mapName_; - } - virtual System::Library* next() { return next_; } @@ -490,7 +490,7 @@ class MySystem: public System { virtual void disposeAll() { if (Verbose) { - fprintf(stderr, "close %p\n", handle); + fprintf(stderr, "close %p\n", handle); fflush(stderr); } if (name_) { @@ -511,22 +511,61 @@ class MySystem: public System { System* s; HMODULE handle; const char* name_; - bool mapName_; System::Library* next_; }; MySystem(const char* crashDumpDirectory): - segFaultHandler(0), - oldSegFaultHandler(0), + oldHandler(0), crashDumpDirectory(crashDumpDirectory) { expect(this, system == 0); system = this; + memset(handlers, 0, sizeof(handlers)); + mutex = CreateMutex(0, false, 0); assert(this, mutex); } + bool findHandler() { + for (unsigned i = 0; i < HandlerCount; ++i) { + if (handlers[i]) return true; + } + return false; + } + + int registerHandler(System::SignalHandler* handler, int index) { + if (handler) { + handlers[index] = handler; + + if (oldHandler == 0) { +#ifdef ARCH_x86_32 + oldHandler = SetUnhandledExceptionFilter(handleException); +#elif defined ARCH_x86_64 + AddVectoredExceptionHandler(1, handleException); + oldHandler = reinterpret_cast(1); +#endif + } + + return 0; + } else if (handlers[index]) { + handlers[index] = 0; + + if (not findHandler()) { +#ifdef ARCH_x86_32 + SetUnhandledExceptionFilter(oldHandler); + oldHandler = 0; +#elif defined ARCH_x86_64 + // do nothing, handlers are never "unregistered" anyway +#endif + } + + return 0; + } else { + return 1; + } + } + virtual void* tryAllocate(unsigned sizeInBytes) { return malloc(sizeInBytes); } @@ -584,27 +623,11 @@ class MySystem: public System { } virtual Status handleSegFault(SignalHandler* handler) { - if (handler) { - segFaultHandler = handler; + return registerHandler(handler, SegFaultIndex); + } -#ifdef ARCH_x86_32 - oldSegFaultHandler = SetUnhandledExceptionFilter(handleException); -#elif defined ARCH_x86_64 - AddVectoredExceptionHandler(1, handleException); - oldSegFaultHandler = 0; -#endif - return 0; - } else if (segFaultHandler) { - segFaultHandler = 0; -#ifdef ARCH_x86_32 - SetUnhandledExceptionFilter(oldSegFaultHandler); -#elif defined ARCH_x86_64 - //do nothing, handlers are never "unregistered" anyway -#endif - return 0; - } else { - return 1; - } + virtual Status handleDivideByZero(SignalHandler* handler) { + return registerHandler(handler, DivideByZeroIndex); } virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, @@ -701,35 +724,40 @@ class MySystem: public System { return status; } - virtual FileType identify(const char* name) { + virtual FileType stat(const char* name, unsigned* length) { struct _stat s; int r = _stat(name, &s); if (r == 0) { if (S_ISREG(s.st_mode)) { + *length = s.st_size; return TypeFile; } else if (S_ISDIR(s.st_mode)) { + *length = 0; return TypeDirectory; } else { + *length = 0; return TypeUnknown; } } else { + *length = 0; return TypeDoesNotExist; } } + virtual const char* libraryPrefix() { + return SO_PREFIX; + } + + virtual const char* librarySuffix() { + return SO_SUFFIX; + } + virtual Status load(System::Library** lib, - const char* name, - bool mapName) + const char* name) { HMODULE handle; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName and name) { - unsigned size = sizeof(SO_PREFIX) + nameLength + sizeof(SO_SUFFIX); - RUNTIME_ARRAY(char, buffer, size);; - vm::snprintf - (RUNTIME_ARRAY_BODY(buffer), size, SO_PREFIX "%s" SO_SUFFIX, name); - handle = LoadLibrary(RUNTIME_ARRAY_BODY(buffer)); - } else if (name) { + if (name) { handle = LoadLibrary(name); } else { handle = GetModuleHandle(0); @@ -737,7 +765,7 @@ class MySystem: public System { if (handle) { if (Verbose) { - fprintf(stderr, "open %s as %p\n", name, handle); + fprintf(stderr, "open %s as %p\n", name, handle); fflush(stderr); } char* n; @@ -748,11 +776,15 @@ class MySystem: public System { n = 0; } - *lib = new (allocate(this, sizeof(Library))) - Library(this, handle, n, mapName); + *lib = new (allocate(this, sizeof(Library))) Library(this, handle, n); return 0; } else { + if (Verbose) { + fprintf(stderr, "unable to open %s: %ld\n", name, GetLastError()); + fflush(stderr); + } + return 1; } } @@ -761,25 +793,22 @@ class MySystem: public System { return ';'; } + virtual char fileSeparator() { + return '\\'; + } + virtual int64_t now() { - static LARGE_INTEGER frequency; - static LARGE_INTEGER time; - static bool init = true; + // We used to use _ftime here, but that only gives us 1-second + // resolution on Windows 7. _ftime_s might work better, but MinGW + // doesn't have it as of this writing. So we use this mess instead: + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((static_cast(time.dwHighDateTime) << 32) + | time.dwLowDateTime) / 10000) - 11644473600000LL; + } - if (init) { - QueryPerformanceFrequency(&frequency); - - if (frequency.QuadPart == 0) { - return 0; - } - - init = false; - } - - QueryPerformanceCounter(&time); - return static_cast - (((static_cast(time.QuadPart)) * 1000.0) / - (static_cast(frequency.QuadPart))); + virtual void yield() { + SwitchToThread(); } virtual void exit(int code) { @@ -799,16 +828,18 @@ class MySystem: public System { } HANDLE mutex; - System::SignalHandler* segFaultHandler; - LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler; + SignalHandler* handlers[HandlerCount]; + LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; const char* crashDumpDirectory; }; +#pragma pack(push,4) struct MINIDUMP_EXCEPTION_INFORMATION { DWORD thread; LPEXCEPTION_POINTERS exception; BOOL exceptionInCurrentAddressSpace; }; +#pragma pack(pop) struct MINIDUMP_USER_STREAM_INFORMATION; struct MINIDUMP_CALLBACK_INFORMATION; @@ -849,16 +880,16 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) if (file != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION exception - = { GetCurrentThreadId(), e, true }; + = { GetCurrentThreadId(), e, true }; - MiniDumpWriteDump - (GetCurrentProcess(), - GetCurrentProcessId(), - file, - MiniDumpWithFullMemory, - &exception, - 0, - 0); + MiniDumpWriteDump + (GetCurrentProcess(), + GetCurrentProcessId(), + file, + MiniDumpWithFullMemory, + &exception, + 0, + 0); CloseHandle(file); } @@ -871,7 +902,15 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) { + System::SignalHandler* handler = 0; if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + handler = system->handlers[SegFaultIndex]; + } else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) + { + handler = system->handlers[DivideByZeroIndex]; + } + + if (handler) { #ifdef ARCH_x86_32 void* ip = reinterpret_cast(e->ContextRecord->Eip); void* base = reinterpret_cast(e->ContextRecord->Ebp); @@ -884,8 +923,8 @@ handleException(LPEXCEPTION_POINTERS e) void* thread = reinterpret_cast(e->ContextRecord->Rbx); #endif - bool jump = system->segFaultHandler->handleSignal - (&ip, &base, &stack, &thread); + bool jump = handler->handleSignal(&ip, &base, &stack, &thread); + #ifdef ARCH_x86_32 e->ContextRecord->Eip = reinterpret_cast(ip); e->ContextRecord->Ebp = reinterpret_cast(base); @@ -901,10 +940,10 @@ handleException(LPEXCEPTION_POINTERS e) if (jump) { return EXCEPTION_CONTINUE_EXECUTION; } + } - if (system->crashDumpDirectory) { - dump(e, system->crashDumpDirectory); - } + if (system->crashDumpDirectory) { + dump(e, system->crashDumpDirectory); } return EXCEPTION_CONTINUE_SEARCH; diff --git a/src/x86.S b/src/x86.S index ebee7a4474..d711d17056 100644 --- a/src/x86.S +++ b/src/x86.S @@ -12,7 +12,8 @@ #define LOCAL(x) .L##x -#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ +#if defined __APPLE__ \ + || ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__) # define GLOBAL(x) _##x #else # define GLOBAL(x) x @@ -22,6 +23,9 @@ #ifdef __x86_64__ +#define CHECKPOINT_THREAD 8 +#define CHECKPOINT_STACK 48 + #ifdef __MINGW32__ .globl GLOBAL(detectFeature) GLOBAL(detectFeature): @@ -172,6 +176,47 @@ GLOBAL(vmJump): movq %r8,%rsp movq %r9,%rbx jmp *%rcx + +#define VMRUN_FRAME_SIZE 80 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // %rcx: function + // %rdx: arguments + // %r8 : checkpoint + pushq %rbp + movq %rsp,%rbp + subq $VMRUN_FRAME_SIZE,%rsp + + movq %rbx,16(%rsp) + movq %r12,24(%rsp) + movq %r13,32(%rsp) + movq %r14,40(%rsp) + movq %r15,48(%rsp) + movq %rsi,56(%rsp) + movq %rdi,64(%rsp) + + movq %rsp,CHECKPOINT_STACK(%r8) + + movq %rcx,%r11 + movq CHECKPOINT_THREAD(%r8),%rcx + + call *%r11 + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + + movq 16(%rsp),%rbx + movq 24(%rsp),%r12 + movq 32(%rsp),%r13 + movq 40(%rsp),%r14 + movq 48(%rsp),%r15 + movq 56(%rsp),%rsi + movq 64(%rsp),%rdi + + addq $VMRUN_FRAME_SIZE,%rsp + popq %rbp + ret #else // not __MINGW32__ .globl GLOBAL(detectFeature) @@ -313,10 +358,51 @@ GLOBAL(vmJump): movq %r9,%rdx jmp *%rdi +#define VMRUN_FRAME_SIZE 64 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // %rdi: function + // %rsi: arguments + // %rdx: checkpoint + pushq %rbp + movq %rsp,%rbp + subq $VMRUN_FRAME_SIZE,%rsp + + movq %rbx,16(%rsp) + movq %r12,24(%rsp) + movq %r13,32(%rsp) + movq %r14,40(%rsp) + movq %r15,48(%rsp) + + movq %rsp,CHECKPOINT_STACK(%rdx) + + movq %rdi,%r11 + movq CHECKPOINT_THREAD(%rdx),%rdi + + call *%r11 + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + + movq 16(%rsp),%rbx + movq 24(%rsp),%r12 + movq 32(%rsp),%r13 + movq 40(%rsp),%r14 + movq 48(%rsp),%r15 + + addq $VMRUN_FRAME_SIZE,%rsp + popq %rbp + ret + #endif // not __MINGW32__ #elif defined __i386__ +#define CHECKPOINT_THREAD 4 +#define CHECKPOINT_STACK 24 +#define CHECKPOINT_BASE 28 + .globl GLOBAL(detectFeature) GLOBAL(detectFeature): pushl %ebp @@ -431,4 +517,41 @@ GLOBAL(vmJump): movl 12(%esp),%esp jmp *%esi -#endif //def __x86_64__ +#define VMRUN_FRAME_SIZE 24 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // 8(%ebp): function + // 12(%ebp): arguments + // 16(%ebp): checkpoint + pushl %ebp + movl %esp,%ebp + subl $VMRUN_FRAME_SIZE,%esp + + movl %ebx,8(%esp) + movl %esi,12(%esp) + movl %edi,16(%esp) + + movl 12(%ebp),%eax + movl %eax,4(%esp) + + movl 16(%ebp),%ecx + movl CHECKPOINT_THREAD(%ecx),%eax + movl %eax,0(%esp) + + movl %esp,CHECKPOINT_STACK(%ecx) + + call *8(%ebp) + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + + movl 8(%esp),%ebx + movl 12(%esp),%esi + movl 16(%esp),%edi + + addl $VMRUN_FRAME_SIZE,%esp + popl %ebp + ret + +#endif // __i386__ diff --git a/src/x86.cpp b/src/x86.cpp index 2d4d3e55f7..97ef3c2bb3 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -65,7 +65,7 @@ const unsigned GeneralRegisterMask const unsigned FloatRegisterMask = BytesPerWord == 4 ? 0x00ff0000 : 0xffff0000; -const unsigned FrameHeaderSize = 2; +const unsigned FrameHeaderSize = (UseFramePointer ? 2 : 1); const int LongJumpRegister = r10; @@ -91,6 +91,12 @@ unsigned padding(AlignmentPadding* p, unsigned index, unsigned offset, AlignmentPadding* limit); +class Context; +class MyBlock; + +ResolvedPromise* +resolved(Context* c, int64_t value); + class MyBlock: public Assembler::Block { public: MyBlock(unsigned offset): @@ -113,8 +119,6 @@ class MyBlock: public Assembler::Block { unsigned size; }; -class Context; - typedef void (*OperationType)(Context*); typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); @@ -881,22 +885,6 @@ popR(Context* c, unsigned size, Assembler::Register* a) } } -void -popM(Context* c, unsigned size, Assembler::Memory* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - - popM(c, 4, a); - popM(c, 4, &ah); - } else { - assert(c, BytesPerWord == 4 or size == 8); - - opcode(c, 0x8f); - modrmSibImm(c, 0, a->scale, a->index, a->base, a->offset); - } -} - void addCarryCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b); @@ -1403,17 +1391,18 @@ addRR(Context* c, unsigned aSize, Assembler::Register* a, } void -addCarryCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, +addCarryCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b) { int64_t v = a->value->value(); + maybeRex(c, size, b); if (isInt8(v)) { - maybeRex(c, size, b); opcode(c, 0x83, 0xd0 + regCode(b)); c->code.append(v); } else { - abort(c); + opcode(c, 0x81, 0xd0 + regCode(b)); + c->code.append4(v); } } @@ -1740,16 +1729,31 @@ multiplyRR(Context* c, unsigned aSize, Assembler::Register* a, Assembler::Register ah(a->high); Assembler::Register bh(b->high); + Assembler::Register tmp(-1); + Assembler::Register* scratch; + if (a->low == b->low) { + tmp.low = c->client->acquireTemporary + (GeneralRegisterMask & ~(1 << rax)); + scratch = &tmp; + moveRR(c, 4, b, 4, scratch); + } else { + scratch = b; + } + moveRR(c, 4, b, 4, &axdx); - multiplyRR(c, 4, &ah, 4, b); + multiplyRR(c, 4, &ah, 4, scratch); multiplyRR(c, 4, a, 4, &bh); - addRR(c, 4, &bh, 4, b); + addRR(c, 4, &bh, 4, scratch); // mul a->low,%eax%edx opcode(c, 0xf7, 0xe0 + a->low); - addRR(c, 4, b, 4, &bh); + addRR(c, 4, scratch, 4, &bh); moveRR(c, 4, &axdx, 4, b); + + if (tmp.low != -1) { + c->client->releaseTemporary(tmp.low); + } } else { maybeRex(c, aSize, b, a); opcode(c, 0x0f, 0xaf); @@ -2510,6 +2514,94 @@ absoluteRR(Context* c, unsigned aSize, Assembler::Register* a, c->client->releaseTemporary(rdx); } +unsigned +argumentFootprint(unsigned footprint) +{ + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); +} + +uint32_t +read4(uint8_t* p) +{ + uint32_t v; memcpy(&v, p, 4); + return v; +} + +void +nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, + unsigned footprint, void*, void* stackLimit, + unsigned targetParameterFootprint, void** ip, void** stack) +{ + assert(c, *ip >= start); + assert(c, *ip <= start + size); + + uint8_t* instruction = static_cast(*ip); + + // skip stack overflow check, if present: + if (BytesPerWord == 4) { + if (*start == 0x39) { + start += 11; + } + } else if (*start == 0x48 and start[1] == 0x39) { + start += 12; + } + + if (instruction <= start) { + *ip = static_cast(*stack)[0]; + return; + } + + if (UseFramePointer) { + // skip preamble + start += (BytesPerWord == 4 ? 3 : 4); + + if (instruction <= start or *instruction == 0x5d) { + *ip = static_cast(*stack)[1]; + *stack = static_cast(*stack) + 1; + return; + } + } + + if (*instruction == 0xc3) { // return + *ip = static_cast(*stack)[0]; + return; + } + + unsigned offset = footprint + FrameHeaderSize + - (stackLimit == *stack ? 1 : 0); + + if (TailCalls) { + if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { + offset += argumentFootprint(targetParameterFootprint) + - StackAlignmentInWords; + } + + // check for post-non-tail-call stack adjustment of the form "add + // $offset,%rsp": + if (BytesPerWord == 4) { + if ((*instruction == 0x83 or *instruction == 0x81) + and instruction[1] == 0xec) + { + offset + -= (*instruction == 0x83 ? instruction[2] : read4(instruction + 2)) + / BytesPerWord; + } + } else if (*instruction == 0x48 + and (instruction[1] == 0x83 or instruction[1] == 0x81) + and instruction[2] == 0xec) + { + offset + -= (instruction[1] == 0x83 ? instruction[3] : read4(instruction + 3)) + / BytesPerWord; + } + + // todo: check for and handle tail calls + } + + *ip = static_cast(*stack)[offset]; + *stack = static_cast(*stack) + offset; +} + void populateTables(ArchitectureContext* c) { @@ -2685,6 +2777,8 @@ class MyArchitecture: public Assembler::Architecture { virtual bool reserved(int register_) { switch (register_) { case rbp: + return UseFramePointer; + case rsp: case rbx: return true; @@ -2705,7 +2799,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); + return local::argumentFootprint(footprint); + } + + virtual bool argumentAlignment() { + return false; } virtual unsigned argumentRegisterCount() { @@ -2830,6 +2928,15 @@ class MyArchitecture: public Assembler::Architecture { - FrameHeaderSize; } + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) + { + local::nextFrame(&c, static_cast(start), size, footprint, + link, stackLimit, targetParameterFootprint, ip, stack); + } + virtual void* frameIp(void* stack) { return stack ? *static_cast(stack) : 0; } @@ -2874,14 +2981,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual int framePointerOffset() { - return -1; - } - - virtual void nextFrame(void** stack, void** base) { - assert(&c, *static_cast(*base) != *base); - - *stack = static_cast(*base) + 1; - *base = *static_cast(*base); + return UseFramePointer ? -1 : 0; } virtual void plan @@ -2914,8 +3014,12 @@ class MyArchitecture: public Assembler::Architecture { break; case Absolute: - *aTypeMask = (1 << RegisterOperand); - *aRegisterMask = (static_cast(1) << rax); + if (aSize <= BytesPerWord) { + *aTypeMask = (1 << RegisterOperand); + *aRegisterMask = (static_cast(1) << rax); + } else { + *thunk = true; + } break; case FloatAbsolute: @@ -3268,16 +3372,21 @@ class MyAssembler: public Assembler { return arch_; } - virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) { + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) + { + Register stack(rsp); + Memory stackLimit(rbx, stackLimitOffsetFromThread); + Constant handlerConstant(resolved(&c, handler)); + branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, + &handlerConstant); + } + + virtual void saveFrame(unsigned stackOffset) { Register stack(rsp); Memory stackDst(rbx, stackOffset); apply(Move, BytesPerWord, RegisterOperand, &stack, BytesPerWord, MemoryOperand, &stackDst); - - Register base(rbp); - Memory baseDst(rbx, baseOffset); - apply(Move, BytesPerWord, RegisterOperand, &base, - BytesPerWord, MemoryOperand, &baseDst); } virtual void pushFrame(unsigned argumentCount, ...) { @@ -3327,12 +3436,15 @@ class MyAssembler: public Assembler { } virtual void allocateFrame(unsigned footprint) { - Register base(rbp); - pushR(&c, BytesPerWord, &base); - Register stack(rsp); - apply(Move, BytesPerWord, RegisterOperand, &stack, - BytesPerWord, RegisterOperand, &base); + + if (UseFramePointer) { + Register base(rbp); + pushR(&c, BytesPerWord, &base); + + apply(Move, BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &base); + } Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, @@ -3340,24 +3452,32 @@ class MyAssembler: public Assembler { BytesPerWord, RegisterOperand, &stack); } - virtual void adjustFrame(unsigned footprint) { + virtual void adjustFrame(unsigned difference) { Register stack(rsp); - Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); - apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, + Constant differenceConstant(resolved(&c, difference * BytesPerWord)); + apply(Subtract, BytesPerWord, ConstantOperand, &differenceConstant, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &stack); } - virtual void popFrame() { - Register base(rbp); - Register stack(rsp); - apply(Move, BytesPerWord, RegisterOperand, &base, - BytesPerWord, RegisterOperand, &stack); + virtual void popFrame(unsigned frameFootprint) { + if (UseFramePointer) { + Register base(rbp); + Register stack(rsp); + apply(Move, BytesPerWord, RegisterOperand, &base, + BytesPerWord, RegisterOperand, &stack); - popR(&c, BytesPerWord, &base); + popR(&c, BytesPerWord, &base); + } else { + Register stack(rsp); + Constant footprint(resolved(&c, frameFootprint * BytesPerWord)); + apply(Add, BytesPerWord, ConstantOperand, &footprint, + BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &stack); + } } - virtual void popFrameForTailCall(unsigned footprint, + virtual void popFrameForTailCall(unsigned frameFootprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) @@ -3366,22 +3486,28 @@ class MyAssembler: public Assembler { if (offset) { Register tmp(c.client->acquireTemporary()); - Memory returnAddressSrc(rsp, (footprint + 1) * BytesPerWord); + unsigned baseSize = UseFramePointer ? 1 : 0; + + Memory returnAddressSrc + (rsp, (frameFootprint + baseSize) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); - Memory returnAddressDst(rsp, (footprint - offset + 1) * BytesPerWord); + Memory returnAddressDst + (rsp, (frameFootprint - offset + baseSize) * BytesPerWord); moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst); c.client->releaseTemporary(tmp.low); - Memory baseSrc(rsp, footprint * BytesPerWord); - Register base(rbp); - moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); + if (UseFramePointer) { + Memory baseSrc(rsp, frameFootprint * BytesPerWord); + Register base(rbp); + moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); + } Register stack(rsp); - Constant footprintConstant - (resolved(&c, (footprint - offset + 1) * BytesPerWord)); - addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); + Constant footprint + (resolved(&c, (frameFootprint - offset + baseSize) * BytesPerWord)); + addCR(&c, BytesPerWord, &footprint, BytesPerWord, &stack); if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); @@ -3399,15 +3525,17 @@ class MyAssembler: public Assembler { moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); } } else { - popFrame(); + popFrame(frameFootprint); } } else { abort(&c); } } - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { - popFrame(); + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) + { + popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); @@ -3428,9 +3556,10 @@ class MyAssembler: public Assembler { } } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) { - popFrame(); + popFrame(frameFootprint); Register returnAddress(rcx); popR(&c, BytesPerWord, &returnAddress); @@ -3516,7 +3645,7 @@ class MyAssembler: public Assembler { } } - virtual Promise* offset() { + virtual Promise* offset(bool) { return local::offset(&c); } @@ -3532,11 +3661,15 @@ class MyAssembler: public Assembler { return b; } + virtual void endEvent() { + // ignore + } + virtual unsigned length() { return c.code.length(); } - virtual unsigned scratchSize() { + virtual unsigned footerSize() { return 0; } diff --git a/src/x86.h b/src/x86.h index 93278cdd7d..9a0b60cccd 100644 --- a/src/x86.h +++ b/src/x86.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -22,25 +22,54 @@ # undef interface #endif +#if (defined ARCH_x86_32) || (defined PLATFORM_WINDOWS) +# define VA_LIST(x) (&(x)) +#else +# define VA_LIST(x) (x) +#endif + +#ifdef __APPLE__ +# include "mach/mach_types.h" +# include "mach/i386/thread_act.h" +# include "mach/i386/thread_status.h" + +# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +# define FIELD(x) __##x +# else +# define FIELD(x) x +# endif +#endif + #ifdef ARCH_x86_32 # ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip) -# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.eip) -# define BASE_REGISTER(context) (context->uc_mcontext->ss.ebp) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) -# endif +# define THREAD_STATE x86_THREAD_STATE32 +# define THREAD_STATE_TYPE x86_thread_state32_t +# define THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT + +# define THREAD_STATE_IP(state) ((state).FIELD(eip)) +# define THREAD_STATE_STACK(state) ((state).FIELD(esp)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(ebx)) +# define THREAD_STATE_LINK(state) ((state).FIELD(ecx)) +# define THREAD_STATE_FRAME(state) ((state).FIELD(ebp)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) +# define FRAME_REGISTER(context) \ + THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) + # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) -# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX]) +# define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_ECX]) +# define FRAME_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) # endif extern "C" uint64_t @@ -61,22 +90,33 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, #elif defined ARCH_x86_64 # ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__rip) -# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__rbp) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__rsp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__rbx) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.rip) -# define BASE_REGISTER(context) (context->uc_mcontext->ss.rbp) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.rsp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.rbx) -# endif +# define THREAD_STATE x86_THREAD_STATE64 +# define THREAD_STATE_TYPE x86_thread_state64_t +# define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT + +# define THREAD_STATE_IP(state) ((state).FIELD(rip)) +# define THREAD_STATE_STACK(state) ((state).FIELD(rsp)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(rbx)) +# define THREAD_STATE_LINK(state) ((state).FIELD(rcx)) +# define THREAD_STATE_FRAME(state) ((state).FIELD(rbp)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) +# define FRAME_REGISTER(context) \ + THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) + # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) -# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) +# define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_RCX]) +# define FRAME_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) # endif extern "C" uint64_t @@ -223,6 +263,19 @@ atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_) (reinterpret_cast(p), new_, old); #elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); +#elif defined ARCH_x86_32 + uint8_t result; + + __asm__ __volatile__("lock; cmpxchg8b %0; setz %1" + : "=m"(*p), "=q"(result) + : "a"(static_cast(old)), + "d"(static_cast(old >> 32)), + "b"(static_cast(new_)), + "c"(static_cast(new_ >> 32)), + "m"(*p) + : "memory"); + + return result != 0; #else uint8_t result; diff --git a/test/Arrays.java b/test/Arrays.java index 2dd2bcfc30..96f5f598f0 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -15,6 +15,17 @@ public class Arrays { expect(exception != null); } + { int[] array = new int[0]; + Exception exception = null; + try { + int x = array[-1]; + } catch (ArrayIndexOutOfBoundsException e) { + exception = e; + } + + expect(exception != null); + } + { int[] array = new int[3]; int i = 0; array[i++] = 1; @@ -54,5 +65,17 @@ public class Arrays { p = false; expect(array[1] == array[p ? 0 : 1]); } + + { int[] array = new int[1024]; + array[1023] = -1; + expect(array[1023] == -1); + expect(array[1022] == 0); + } + + { Integer[] array = (Integer[]) + java.lang.reflect.Array.newInstance(Integer.class, 1); + array[0] = Integer.valueOf(42); + expect(array[0].intValue() == 42); + } } } diff --git a/test/DefineClass.java b/test/DefineClass.java new file mode 100644 index 0000000000..ea3b6362ae --- /dev/null +++ b/test/DefineClass.java @@ -0,0 +1,86 @@ +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; + +public class DefineClass { + private static File findClass(String name, File directory) { + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().equals(name + ".class")) { + return file; + } + } else if (file.isDirectory()) { + File result = findClass(name, file); + if (result != null) { + return result; + } + } + } + return null; + } + + private static byte[] read(File file) throws IOException { + byte[] bytes = new byte[(int) file.length()]; + FileInputStream in = new FileInputStream(file); + try { + if (in.read(bytes) != (int) file.length()) { + throw new RuntimeException(); + } + return bytes; + } finally { + in.close(); + } + } + + private static Class loadClass(String name) throws Exception { + return new MyClassLoader(DefineClass.class.getClassLoader()).defineClass + (name, read(findClass(name, new File(System.getProperty("user.dir"))))); + } + + private static void testStatic() throws Exception { + loadClass("DefineClass$Hello") + .getMethod("main", String[].class).invoke(null, (Object) new String[0]); + } + + private static void testDerived() throws Exception { + System.out.println + (String.valueOf + (((Base) loadClass("DefineClass$Derived").newInstance()).zip())); + } + + public static void main(String[] args) throws Exception { + //testStatic(); + testDerived(); + } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + public Class defineClass(String name, byte[] bytes) { + return super.defineClass(name, bytes, 0, bytes.length); + } + } + + public static class Hello { + public static void main(String[] args) { + System.out.println("hello, world!"); + } + } + + public abstract static class Base { + public int foo; + public int[] array; + + public void bar() { } + + public abstract int zip(); + } + + public static class Derived extends Base { + public int zip() { + return 42; + } + } +} diff --git a/test/DivideByZero.java b/test/DivideByZero.java new file mode 100644 index 0000000000..80f308adcb --- /dev/null +++ b/test/DivideByZero.java @@ -0,0 +1,135 @@ +public class DivideByZero { + private static int divide(int n, int d) { + return n / d; + } + + private static int modulo(int n, int d) { + return n % d; + } + + private static long divide(long n, long d) { + return n / d; + } + + private static long modulo(long n, long d) { + return n % d; + } + + private static float divide(float n, float d) { + return n / d; + } + + private static float modulo(float n, float d) { + return n % d; + } + + private static double divide(double n, double d) { + return n / d; + } + + private static double modulo(double n, double d) { + return n % d; + } + + public static void main(String[] args) { + try { + int x = 1 / 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int x = 1 % 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int y = 2; + int x = y / 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int y = 2; + int x = y % 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int z = 0; + int y = 2; + int x = y / z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int z = 0; + int y = 2; + int x = y % z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + long z = 0; + long y = 2; + long x = y / z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + long z = 0; + long y = 2; + long x = y % z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + divide(5, 0); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + modulo(6, 0); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + divide(5L, 0L); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + modulo(6L, 0L); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + divide(5F, 0F); + modulo(6F, 0F); + + divide(5D, 0D); + modulo(6D, 0D); + } +} diff --git a/test/FileOutput.java b/test/FileOutput.java new file mode 100644 index 0000000000..539b73fc59 --- /dev/null +++ b/test/FileOutput.java @@ -0,0 +1,47 @@ +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.io.File; +import java.io.IOException; + +public class FileOutput { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static void test(boolean appendFirst) throws IOException { + try { + FileOutputStream f = new FileOutputStream("test.txt", appendFirst); + f.write("Hello world!\n".getBytes()); + f.close(); + + FileOutputStream f2 = new FileOutputStream("test.txt", true); + f2.write("Hello world again!".getBytes()); + f2.close(); + + FileInputStream in = new FileInputStream("test.txt"); + byte[] buffer = new byte[256]; + int c; + int offset = 0; + while ((c = in.read(buffer, offset, buffer.length - offset)) != -1) { + offset += c; + } + in.close(); + + if (! "Hello world!\nHello world again!".equals + (new String(buffer, 0, offset))) + { + throw new RuntimeException(); + } + } finally { + expect(new File("test.txt").delete()); + } + } + + public static void main(String[] args) throws IOException { + expect(new File("nonexistent-file").length() == 0); + + test(false); + test(true); + } + +} diff --git a/test/GC.java b/test/GC.java index d04c577fc8..9fabee0cc9 100644 --- a/test/GC.java +++ b/test/GC.java @@ -1,4 +1,14 @@ public class GC { + private static final Integer cache[] = new Integer[100]; + private static final Integer MAX_INT_OBJ = new Integer(Integer.MAX_VALUE); + + private static Integer valueOf(int i) { + try { + return cache[i]; + } catch (ArrayIndexOutOfBoundsException e) { + return (i == Integer.MAX_VALUE) ? MAX_INT_OBJ : new Integer(i); + } + } private static void small() { for (int i = 0; i < 1024; ++i) { @@ -145,6 +155,8 @@ public class GC { } public static void main(String[] args) { + valueOf(1000); + Object[] array = new Object[1024 * 1024]; array[0] = new Object(); diff --git a/test/Integers.java b/test/Integers.java index 80e1a0e3a5..c88803b518 100644 --- a/test/Integers.java +++ b/test/Integers.java @@ -21,6 +21,11 @@ public class Integers { } public static void main(String[] args) { + { int foo = 1028; + foo -= 1023; + expect(foo == 5); + } + expect(gcd(12, 4) == 4); { int a = 2; diff --git a/test/Longs.java b/test/Longs.java index e868dca385..9beaf8a996 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -60,6 +60,13 @@ public class Longs { } public static void main(String[] args) throws Exception { + { long a = 0x1FFFFFFFFL; + long b = -1; + expect(a != b); + } + + expect(Math.abs(-123L) == 123L); + expect(readLongFrom(new java.io.InputStream() { int step; @@ -241,6 +248,23 @@ public class Longs { expect(buffer.getLong() == 231); expect(unsignedShiftRight32(231) == 0); + + { int[] x = new int[] { 1701899151 }; + int[] z = new int[x.length * 2]; + final long LONG_MASK = 0xffffffffL; + + int lastProductLowWord = 0; + for (int j=0, i=0; j>> 33); + z[i++] = (int) (product >>> 1); + lastProductLowWord = (int) product; + } + + expect(z[0] == 337192406); + expect(z[1] == -437261072); + } } } diff --git a/test/Misc.java b/test/Misc.java index 5542ce5cfd..7ff2f25378 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -1,4 +1,16 @@ public class Misc { + private interface Bar { + public int baz(); + } + + private static abstract class Bim implements Bar { } + + private static class Baz extends Bim { + public int baz() { + return 42; + } + } + private static int alpha; private static int beta; private static byte byte1, byte2, byte3; @@ -92,7 +104,31 @@ public class Misc { return (o == null ? default_ : o); } + private static class Zam { + public void bim() { } + } + + private static class Zim { + public Object zum() { + return null; + } + } + + private static Zim zim = new Zim(); + + private static void zam() { + Zam z; + while ((z = (Zam) zim.zum()) != null) { + z.bim(); + } + } + public static void main(String[] args) { + zam(); + + Bim bim = new Baz(); + expect(bim.baz() == 42); + expect(queryDefault(new Object()) != null); { Foo foo = new Foo(); @@ -189,5 +225,15 @@ public class Misc { } while (x != 1); } } + + System.out.println(new java.util.Date().toString()); + + System.out.println('x'); + System.out.println(true); + System.out.println(42); + System.out.println(123456789012345L); + System.out.println(75.62); + System.out.println(75.62d); + System.out.println(new char[] { 'h', 'i' }); } } diff --git a/test/NullPointer.java b/test/NullPointer.java index c09dc83340..6c6e5c7b50 100644 --- a/test/NullPointer.java +++ b/test/NullPointer.java @@ -2,10 +2,33 @@ public class NullPointer { private int x; private Object y; + private static void throw_(Object o) { + o.toString(); + } + + private static void throwAndCatch(Object o) { + try { + o.toString(); + throw new RuntimeException(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + } + public static void main(String[] args) { + try { + throw_(null); + throw new RuntimeException(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + + throwAndCatch(null); + // invokeinterface try { ((Runnable) null).run(); + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -13,6 +36,7 @@ public class NullPointer { // invokevirtual try { ((Object) null).toString(); + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -20,6 +44,7 @@ public class NullPointer { // arraylength try { int a = ((byte[]) null).length; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -27,6 +52,7 @@ public class NullPointer { // iaload try { int a = ((byte[]) null)[42]; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -34,6 +60,7 @@ public class NullPointer { // aaload try { Object a = ((Object[]) null)[42]; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -41,6 +68,7 @@ public class NullPointer { // getfield (int) try { int a = ((NullPointer) null).x; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -48,6 +76,7 @@ public class NullPointer { // getfield (Object) try { Object a = ((NullPointer) null).y; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -55,6 +84,7 @@ public class NullPointer { // iastore try { ((byte[]) null)[42] = 42; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -62,6 +92,7 @@ public class NullPointer { // aastore try { ((Object[]) null)[42] = null; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -69,6 +100,7 @@ public class NullPointer { // putfield (int) try { ((NullPointer) null).x = 42; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -76,6 +108,7 @@ public class NullPointer { // putfield (Object) try { ((NullPointer) null).y = null; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -85,6 +118,7 @@ public class NullPointer { synchronized ((Object) null) { int a = 42; } + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } diff --git a/test/OutOfMemory.java b/test/OutOfMemory.java new file mode 100644 index 0000000000..fbcb614fdf --- /dev/null +++ b/test/OutOfMemory.java @@ -0,0 +1,62 @@ +public class OutOfMemory { + // assume a 128MB heap size: + private static final int Padding = 120 * 1024 * 1024; + + private static class Node { + Object value; + Node next; + } + + private static void bigObjects() { + Object[] root = null; + while (true) { + Object[] x = new Object[1024 * 1024]; + x[0] = root; + root = x; + } + } + + private static void littleObjects() { + byte[] padding = new byte[Padding]; + Node root = null; + while (true) { + Node x = new Node(); + x.next = root; + root = x; + } + } + + private static void bigAndLittleObjects() { + byte[] padding = new byte[Padding]; + Node root = null; + while (true) { + Node x = new Node(); + x.value = new Object[1024 * 1024]; + x.next = root; + root = x; + } + } + + public static void main(String[] args) { + try { + bigObjects(); + throw new RuntimeException(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + + try { + littleObjects(); + throw new RuntimeException(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + + try { + bigAndLittleObjects(); + throw new RuntimeException(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + } +} diff --git a/test/StackOverflow.java b/test/StackOverflow.java new file mode 100644 index 0000000000..c613fe5616 --- /dev/null +++ b/test/StackOverflow.java @@ -0,0 +1,29 @@ +public class StackOverflow { + private static int test1() { + return test1() + 1; + } + + private static int test2() { + return test3() + 1; + } + + private static int test3() { + return test2() + 1; + } + + public static void main(String[] args) { + try { + test1(); + throw new RuntimeException(); + } catch (StackOverflowError e) { + e.printStackTrace(); + } + + try { + test2(); + throw new RuntimeException(); + } catch (StackOverflowError e) { + e.printStackTrace(); + } + } +} diff --git a/test/Strings.java b/test/Strings.java index 9927ba2983..d98c1f13f9 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -3,6 +3,24 @@ public class Strings { if (! v) throw new RuntimeException(); } + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + private static boolean arraysEqual(Object[] a, Object[] b) { + if (a.length != b.length) { + return false; + } + + for (int i = 0; i < a.length; ++i) { + if (! equal(a[i], b[i])) { + return false; + } + } + + return true; + } + public static void main(String[] args) { expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97, 116, 101, 46, 110, 97, 116, 46, 98, 117, @@ -13,6 +31,31 @@ public class Strings { expect(months.split("\u00ae").length == 3); expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar.")); + expect(arraysEqual + ("xyz".split("", 0), new String[] { "", "x", "y", "z" })); + expect(arraysEqual + ("xyz".split("", 1), new String[] { "xyz" })); + expect(arraysEqual + ("xyz".split("", 2), new String[] { "", "xyz" })); + expect(arraysEqual + ("xyz".split("", 3), new String[] { "", "x", "yz" })); + expect(arraysEqual + ("xyz".split("", 4), new String[] { "", "x", "y", "z" })); + expect(arraysEqual + ("xyz".split("", 5), new String[] { "", "x", "y", "z", "" })); + expect(arraysEqual + ("xyz".split("", 6), new String[] { "", "x", "y", "z", "" })); + expect(arraysEqual + ("xyz".split("", -1), new String[] { "", "x", "y", "z", "" })); + + expect(arraysEqual("".split("xyz", 0), new String[] { "" })); + expect(arraysEqual("".split("xyz", 1), new String[] { "" })); + expect(arraysEqual("".split("xyz", -1), new String[] { "" })); + + expect(arraysEqual("".split("", 0), new String[] { "" })); + expect(arraysEqual("".split("", 1), new String[] { "" })); + expect(arraysEqual("".split("", -1), new String[] { "" })); + expect("foo_foofoo__foo".replaceAll("_", "__") .equals("foo__foofoo____foo")); @@ -28,5 +71,11 @@ public class Strings { sb.append('$'); sb.append('2'); expect(sb.substring(1).equals("2")); + + expect(Character.forDigit(Character.digit('0', 10), 10) == '0'); + expect(Character.forDigit(Character.digit('9', 10), 10) == '9'); + expect(Character.forDigit(Character.digit('b', 16), 16) == 'b'); + expect(Character.forDigit(Character.digit('f', 16), 16) == 'f'); + expect(Character.forDigit(Character.digit('z', 36), 36) == 'z'); } } diff --git a/test/Subroutine.java b/test/Subroutine.java index 2516d34398..b02ec9ba81 100644 --- a/test/Subroutine.java +++ b/test/Subroutine.java @@ -1,8 +1,93 @@ +import avian.Stream; +import avian.ConstantPool; +import avian.ConstantPool.PoolEntry; +import avian.Assembler; +import avian.Assembler.MethodData; + +import java.util.ArrayList; +import java.util.List; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.IOException; + public class Subroutine { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } + private static byte[] makeTestCode(List pool) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Stream.write2(out, 1); // max stack + Stream.write2(out, 1); // max locals + Stream.write4(out, 0); // length (we'll set the real value later) + + // 0: + Stream.write1(out, Assembler.ldc_w); + Stream.write2(out, ConstantPool.addString(pool, "foo") + 1); + + // 3: + Stream.write1(out, Assembler.astore_0); + + // 4: + Stream.write1(out, Assembler.invokestatic); + Stream.write2(out, ConstantPool.addMethodRef + (pool, "java/lang/System", "gc", "()V") + 1); + + // 7: + Stream.write1(out, Assembler.goto_); + Stream.write2(out, 9); // 16 + + // 10: + Stream.write1(out, Assembler.astore_0); + + // 11: + Stream.write1(out, Assembler.invokestatic); + Stream.write2(out, ConstantPool.addMethodRef + (pool, "java/lang/System", "gc", "()V") + 1); + + // 14: + Stream.write1(out, Assembler.ret); + Stream.write1(out, 0); + + // 16: + Stream.write1(out, Assembler.jsr); + Stream.write2(out, -6); // 10 + + // 19: + Stream.write1(out, Assembler.invokestatic); + Stream.write2(out, ConstantPool.addMethodRef + (pool, "java/lang/System", "gc", "()V") + 1); + + // 22: + Stream.write1(out, Assembler.return_); + + Stream.write2(out, 0); // exception handler table length + Stream.write2(out, 0); // attribute count + + byte[] result = out.toByteArray(); + Stream.set4(result, 4, result.length - 12); + + return result; + } + + private static Class makeTestClass() throws IOException { + List pool = new ArrayList(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + String name = "$SubroutineTest$"; + + Assembler.writeClass + (out, pool, ConstantPool.addClass(pool, name), + ConstantPool.addClass(pool, "java/lang/Object"), + new int[0], new MethodData[] + { new MethodData(Assembler.ACC_STATIC | Assembler.ACC_PUBLIC, + ConstantPool.addUtf8(pool, "test"), + ConstantPool.addUtf8(pool, "()V"), + makeTestCode(pool)) }); + + return new MyClassLoader(Subroutine.class.getClassLoader()) + .defineClass(name, out.toByteArray()); + } + // These tests are intended to cover the jsr and ret instructions. // However, recent Sun javac versions avoid generating these // instructions by default, so we must compile this class using @@ -138,7 +223,20 @@ public class Subroutine { } } - public static void main(String[] args) { + private boolean test5(boolean predicate) { + try { + if (predicate) { + return false; + } + } finally { + synchronized (this) { + notifyAll(); + } + } + return true; + } + + public static void main(String[] args) throws Exception { test(false, false); test(false, true); test(true, false); @@ -188,7 +286,23 @@ public class Subroutine { String.valueOf(test4(3)); expect(test4(1) == 0xFABFABFABFL); + + new Subroutine().test5(true); + new Subroutine().test5(false); + + makeTestClass().getMethod("test", new Class[0]).invoke + (null, new Object[0]); } private static class DummyException extends RuntimeException { } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + public Class defineClass(String name, byte[] bytes) { + return super.defineClass(name, bytes, 0, bytes.length); + } + } } diff --git a/test/Trace.java b/test/Trace.java new file mode 100644 index 0000000000..79aa3b421d --- /dev/null +++ b/test/Trace.java @@ -0,0 +1,100 @@ +public class Trace implements Runnable { + private volatile boolean alive = true; + + private static void throwSomething() { + throw new RuntimeException(); + } + + private void bar(Object o) { + o.toString(); + } + + private void foo() { + { long a = 42; + long b = 25; + long c = a / b; + } + + try { + long a = 42; + long b = 0; + long c = a / b; + } catch (Exception e) { } + + try { + throw new Exception(); + } catch (Exception e) { } + + try { + throwSomething(); + } catch (Exception e) { } + + try { + Trace.class.getMethod("bar", Object.class).invoke(this, this); + } catch (Exception e) { } + } + + private static void dummy() { + byte[] a = new byte[10]; + byte[] b = new byte[10]; + System.arraycopy(a, 0, b, 0, 10); + } + + private static void tail1(int a, int b, int c, int d, int e, int f) { + dummy(); + } + + private static void tail2() { + tail1(1, 2, 3, 4, 5, 6); + tail1(1, 2, 3, 4, 5, 6); + } + + private static void test(Trace trace) { + tail1(1, 2, 3, 4, 5, 6); + tail2(); + trace.foo(); + } + + public void run() { + synchronized (this) { + notifyAll(); + } + + try { + for (int i = 0; i < 10000; ++i) { + test(this); + + if (i % 100 == 0) { + System.out.print("r"); + System.out.flush(); + } + } + } finally { + alive = false; + } + } + + public static void main(String[] args) throws Exception { + Trace trace = new Trace(); + Thread thread = new Thread(trace); + + synchronized (trace) { + thread.start(); + trace.wait(); + + int count = 0; + while (trace.alive) { + thread.getStackTrace(); + ++ count; + + if (count % 100 == 0) { + Thread.yield(); + System.out.print("t"); + System.out.flush(); + } + } + + System.out.println("\ngot " + count + " traces"); + } + } +} diff --git a/test/Tree.java b/test/Tree.java index ded42a27ea..12f1e8fa08 100644 --- a/test/Tree.java +++ b/test/Tree.java @@ -1,6 +1,8 @@ import java.util.Comparator; import java.util.TreeSet; import java.util.TreeMap; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Iterator; @@ -87,5 +89,13 @@ public class Tree { map.put("y", "Y"); isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z"); + + Collection list = new ArrayList(); + list.add(7); + list.add(2); + list.add(9); + list.add(2); + + isEqual(printList(new TreeSet(list)), "2, 7, 9"); } } diff --git a/test/Zip.java b/test/Zip.java index 2aea1760f1..9b34444023 100644 --- a/test/Zip.java +++ b/test/Zip.java @@ -1,27 +1,49 @@ import java.io.InputStream; +import java.io.File; import java.util.Enumeration; import java.util.zip.ZipFile; import java.util.zip.ZipEntry; public class Zip { + + private static String findJar(File directory) { + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().endsWith(".jar")) { + return file.getAbsolutePath(); + } + } else if (file.isDirectory()) { + String result = findJar(file); + if (result != null) { + return result; + } + } + } + return null; + } public static void main(String[] args) throws Exception { - ZipFile file = new ZipFile("build/classpath.jar"); + ZipFile file = new ZipFile + (findJar(new File(System.getProperty("user.dir")))); - byte[] buffer = new byte[4096]; - for (Enumeration e = file.entries(); - e.hasMoreElements();) - { - ZipEntry entry = e.nextElement(); - InputStream in = file.getInputStream(entry); - try { - int size = 0; - int c; while ((c = in.read(buffer)) != -1) size += c; - System.out.println - (entry.getName() + " " + entry.getCompressedSize() + " " + size); - } finally { - in.read(); + try { + byte[] buffer = new byte[4096]; + for (Enumeration e = file.entries(); + e.hasMoreElements();) + { + ZipEntry entry = e.nextElement(); + InputStream in = file.getInputStream(entry); + try { + int size = 0; + int c; while ((c = in.read(buffer)) != -1) size += c; + System.out.println + (entry.getName() + " " + entry.getCompressedSize() + " " + size); + } finally { + in.close(); + } } + } finally { + file.close(); } } diff --git a/test/extra/DumpStats.java b/test/extra/DumpStats.java new file mode 100644 index 0000000000..73b9170bed --- /dev/null +++ b/test/extra/DumpStats.java @@ -0,0 +1,159 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; +import java.util.Map; +import java.util.HashMap; +import java.util.Comparator; +import java.util.Arrays; + +/** + * This is a simple utility to generate and print statistics from a + * heap dump generated by Avian's heapdump.cpp. The output is a list + * of classes (identified by number in the case of anonymous, + * VM-internal classes), each followed by (1) the total memory + * footprint of all instances of the class in machine words, and (2) + * the number of instances. The output is ordered by instance memory + * footprint. + */ +public class DumpStats { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static int readInt(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 (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static Record record(Map map, int key) { + Record r = map.get(key); + if (r == null) { + map.put(key, r = new Record(key)); + } + return r; + } + + private static Map read(InputStream in) + throws IOException + { + boolean done = false; + boolean popped = false; + int size = 0; + int last = 0; + Map map = new HashMap(); + + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + last = readInt(in); + popped = false; + } break; + + case ClassName: { + record(map, last).name = readString(in); + } break; + + case Push: { + last = readInt(in); + if (! popped) { + Record r = record(map, last); + r.footprint += size; + ++ r.count; + } + popped = false; + } break; + + case Pop: { + popped = true; + } break; + + case Size: { + size = readInt(in); + } break; + + case -1: + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + + return map; + } + + private static void usageAndExit() { + System.err.println("usage: java DumpStats "); + } + + public static void main(String[] args) throws Exception { + if (args.length != 2) { + usageAndExit(); + } + + Map map = read + (new BufferedInputStream(new FileInputStream(args[0]))); + + Record[] array = map.values().toArray(new Record[map.size()]); + Arrays.sort(array, new Comparator() { + public int compare(Record a, Record b) { + return b.footprint - a.footprint; + } + }); + + int wordSize = Integer.parseInt(args[1]); + + int footprint = 0; + int count = 0; + for (Record r: array) { + if (r.name == null) { + r.name = String.valueOf(r.key); + } + System.out.println + (r.name + ": " + (r.footprint * wordSize) + " " + r.count); + footprint += r.footprint; + count += r.count; + } + + System.out.println(); + System.out.println("total: " + (footprint * wordSize) + " " + count); + } + + private static class Record { + public final int key; + public String name; + public int footprint; + public int count; + + public Record(int key) { + this.key = key; + } + } +} diff --git a/test/extra/PrintDump.java b/test/extra/PrintDump.java new file mode 100644 index 0000000000..8f43f419c9 --- /dev/null +++ b/test/extra/PrintDump.java @@ -0,0 +1,101 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; + +/** + * This is a simple utility to print the contents of a heap dump + * generated by Avian's heapdump.cpp in a human-readable format. + */ +public class PrintDump { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static void indent(PrintStream out, int level) { + for (; level > 0; --level) out.print(" "); + } + + private static int readInt(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 (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static void pipe(InputStream in, PrintStream out) + throws IOException + { + boolean done = false; + boolean popped = false; + int level = 0; + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + out.print("\nroot " + readInt(in)); + popped = false; + } break; + + case ClassName: { + out.print(" class " + readString(in)); + } break; + + case Push: { + ++ level; + out.println(); + indent(out, level); + if (! popped) { + out.print("first "); + } + out.print("child " + readInt(in)); + popped = false; + } break; + + case Pop: { + -- level; + popped = true; + } break; + + case Size: { + out.print(" size " + readInt(in)); + } break; + + case -1: + out.println(); + out.flush(); + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + } + + public static void main(String[] args) throws Exception { + pipe(new BufferedInputStream(new FileInputStream(args[0])), System.out); + } +} diff --git a/test/extra/QueryDump.java b/test/extra/QueryDump.java new file mode 100644 index 0000000000..156cd64d36 --- /dev/null +++ b/test/extra/QueryDump.java @@ -0,0 +1,358 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.Comparator; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +public class QueryDump { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static int readInt(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 (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static Record record(Map map, int key) { + Record r = map.get(key); + if (r == null) { + map.put(key, r = new Record(key)); + } + return r; + } + + private static void push(List stack, T value) { + stack.add(value); + } + + private static T pop(List stack) { + return stack.remove(stack.size() - 1); + } + + private static T peek(List stack, int offset) { + return stack.get(stack.size() - 1 - offset); + } + + private static T peek(List stack) { + return peek(stack, 0); + } + + private static Set nodes(Record record) { + if (record.nodes == null) { + record.nodes = new HashSet(2); + } + return record.nodes; + } + + private static void query(Map nodes, Record[] query, + List stack, int index) + { + Node node = nodes.get(peek(stack, index).key); + if (node != null) { + int base = node.index(); + for (int i = base + 1; i < query.length; ++i) { + int peek = index + i - base; + if (peek < stack.size()) { + Instance instance = peek(stack, peek); + if (query[i] == instance.record) { + TreeNode next = (TreeNode) nodes.get(instance); + if (next == null) { + nodes.put(instance.key, next = new TreeNode(instance, i)); + } + next.children.add(node); + node = next; + } else { + return; + } + } else { + return; + } + } + + if (index + query.length - base < stack.size()) { + nodes(peek(stack, index + query.length - base).record).add(node); + } + } + } + + private static void query(Map nodes, Record[] query, + List stack) + { + if (stack.size() > 1) { + Instance instance = peek(stack, 1); + if (instance != null && instance.record == query[0]) { + Node node = nodes.get(instance.key); + if (node == null) { + nodes.put(instance.key, new LeafNode(instance)); + query(nodes, query, stack, 1); + } + return; + } + } + + query(nodes, query, stack, 0); + } + + private static Map read(InputStream in, + String[] queryClasses) + throws IOException + { + boolean done = false; + boolean popped = false; + Map records = new HashMap(); + Map nodes = new HashMap(); + List stack = new ArrayList(); + Record[] query = new Record[queryClasses.length]; + + Record roots = new Record(-1, ""); + records.put(roots.key, roots); + + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + stack.clear(); + push(stack, new Instance(readInt(in))); + + query(nodes, query, stack); + + popped = false; + // System.out.println("root " + last); + } break; + + case ClassName: { + String name = readString(in); + Record r = record(records, peek(stack).key); + r.name = name; + + for (int i = 0; i < queryClasses.length; ++i) { + if (queryClasses[i].equals(name)) { + query[i] = r; + } + } + + query(nodes, query, stack); + } break; + + case Push: { + int key = readInt(in); + + if (! popped) { + peek(stack).record = record(records, key); + } + + push(stack, new Instance(key)); + + query(nodes, query, stack); + + popped = false; + } break; + + case Pop: { + pop(stack); + + popped = true; + } break; + + case Size: { + peek(stack).size = readInt(in); + } break; + + case -1: + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + + return records; + } + + private static String[] copy(String[] array, int offset, int length) { + String[] copy = new String[length]; + if (length > 0) { + System.arraycopy(array, offset, copy, 0, length); + } + + return copy; + } + + private static void visitLeaves(Set nodes, LeafVisitor visitor) { + for (Node n: nodes) { + n.visitLeaves(visitor); + } + } + + private static void usageAndExit() { + System.err.println("usage: java QueryDump " + + " ..."); + } + + public static void main(String[] args) throws Exception { + if (args.length < 3) { + usageAndExit(); + } + + Map map = read + (new BufferedInputStream(new FileInputStream(args[0])), + copy(args, 2, args.length - 2)); + + for (Iterator it = map.values().iterator(); it.hasNext();) { + final Record r = it.next(); + if (r.nodes == null) { + it.remove(); + } else { + visitLeaves(r.nodes, new LeafVisitor() { + private Set set = new HashSet(); + + public void visit(LeafNode node) { + if (! set.contains(node.instance)) { + r.footprint += node.instance.size; + ++ r.count; + } + set.add(node.instance); + } + }); + } + } + + Record[] array = map.values().toArray(new Record[map.size()]); + Arrays.sort(array, new Comparator() { + public int compare(Record a, Record b) { + return b.footprint - a.footprint; + } + }); + + int wordSize = Integer.parseInt(args[1]); + + int footprint = 0; + int count = 0; + for (Record r: array) { + if (r.name == null) { + r.name = String.valueOf(r.key); + } + System.out.println + (r.name + ": " + (r.footprint * wordSize) + " " + r.count); + footprint += r.footprint; + count += r.count; + } + + System.out.println(); + System.out.println("total: " + (footprint * wordSize) + " " + count); + } + + private static class Record { + public final int key; + public String name; + public int footprint; + public int count; + public Set nodes; + + public Record(int key) { + this(key, null); + } + + public Record(int key, String name) { + this.key = key; + this.name = name; + } + + public String toString() { + return name; + } + } + + private static class Instance { + public final int key; + public int size; + public Record record; + + public Instance(int key) { + this.key = key; + } + + public String toString() { + return "[" + key + " " + record + "]"; + } + } + + public interface Node { + public void visitLeaves(LeafVisitor visitor); + public int index(); + } + + public static class LeafNode implements Node { + public final Instance instance; + + public LeafNode(Instance instance) { + this.instance = instance; + } + + public void visitLeaves(LeafVisitor visitor) { + visitor.visit(this); + } + + public int index() { + return 0; + } + } + + public static class TreeNode implements Node { + public final Instance instance; + public final int index; + + public final Set children = new HashSet(2); + + public TreeNode(Instance instance, int index) { + this.instance = instance; + this.index = index; + } + + public void visitLeaves(LeafVisitor visitor) { + QueryDump.visitLeaves(children, visitor); + } + + public int index() { + return index; + } + } + + public interface LeafVisitor { + public void visit(LeafNode node); + } +} diff --git a/test/test.sh b/test/test.sh index 55b4ff54a6..defd6af06a 100644 --- a/test/test.sh +++ b/test/test.sh @@ -14,14 +14,15 @@ echo -n "" >${log} echo for test in ${tests}; do - printf "%16s" "${test}: " + printf "%24s" "${test}: " case ${mode} in debug|debug-fast|fast|small ) ${vm} ${flags} ${test} >>${log} 2>&1;; stress* ) - ${vg} ${vm} ${flags} ${test} >>${log} 2>&1;; + ${vg} ${vm} ${flags} ${test} \ + >>${log} 2>&1;; * ) echo "unknown mode: ${mode}" >&2 diff --git a/vm.pro b/vm.pro index a6a2a54413..2cdd1baef5 100644 --- a/vm.pro +++ b/vm.pro @@ -12,6 +12,7 @@ -keepclassmembers class java.lang.ClassLoader { !static ; } -keepclassmembers class java.lang.String { !static ; } -keepclassmembers class java.lang.Thread { !static ; } +-keepclassmembers class java.lang.ThreadGroup { !static ; } -keepclassmembers class java.lang.StackTraceElement { !static ; } -keepclassmembers class java.lang.Throwable { !static ; } -keepclassmembers class java.lang.Byte { !static ; } @@ -28,6 +29,17 @@ -keepclassmembers class java.lang.ref.PhantomReference { !static ; } -keepclassmembers class java.lang.reflect.Field { !static ; } -keepclassmembers class java.lang.reflect.Method { !static ; } +-keepclassmembers class java.lang.reflect.Constructor { !static ; } +-keepclassmembers class java.lang.reflect.AccessibleObject { !static ; } +-keepclassmembers class sun.reflect.ConstantPool { !static ; } +-keepclassmembers class avian.VMClass { !static ; } +-keepclassmembers class avian.VMMethod { !static ; } +-keepclassmembers class avian.VMField { !static ; } +-keepclassmembers class avian.ClassAddendum { !static ; } +-keepclassmembers class avian.MethodAddendum { !static ; } +-keepclassmembers class avian.FieldAddendum { !static ; } +-keepclassmembers class avian.Continuations$Continuation { !static ; } +-keepclassmembers class avian.Continuations$UnwindResult { !static ; } # the VM may throw instances of the following: @@ -45,6 +57,7 @@ -keep public class java.lang.ClassCastException -keep public class java.lang.ClassNotFoundException -keep public class java.lang.NullPointerException +-keep public class java.lang.ArithmeticException -keep public class java.lang.InterruptedException -keep public class java.lang.StackOverflowError -keep public class java.lang.NoSuchFieldError @@ -64,6 +77,7 @@ # the VM references these classes by name, so protect them from obfuscation: -keepnames public class java.lang.** +-keepnames public class avian.** # Don't optimize calls to ResourceBundle -keep,allowshrinking,allowobfuscation public class java.util.ResourceBundle { @@ -97,3 +111,15 @@ -keepnames public class avian.Callback -keepnames public class java.util.concurrent.Callable + +# Proguard gets confused about clone() and array classes (http://sourceforge.net/tracker/index.php?func=detail&aid=2851344&group_id=54750&atid=474704): + +-keepclassmembers class java.lang.Object { + protected java.lang.Object clone(); + } + +# called by name in the VM: + +-keepclassmembers class java.lang.ClassLoader { + public java.lang.Class loadClass(java.lang.String); + }