From cddea7187d1886a521abbec719691d4fda8135d8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Sep 2010 15:05:29 -0600 Subject: [PATCH] preliminary support for using OpenJDK's class library Whereas the GNU Classpath port used the strategy of patching Classpath with core classes from Avian so as to minimize changes to the VM, this port uses the opposite strategy: abstract and isolate classpath-specific features in the VM similar to how we abstract away platform-specific features in system.h. This allows us to use an unmodified copy of OpenJDK's class library, including its core classes and augmented by a few VM-specific classes in the "avian" package. --- classpath/avian/Addendum.java | 2 +- classpath/avian/Classes.java | 268 +++ classpath/avian/FieldAddendum.java | 13 + classpath/avian/MethodAddendum.java | 15 + classpath/avian/SystemClassLoader.java | 276 +-- classpath/avian/VMField.java | 2 +- classpath/avian/VMMethod.java | 2 +- classpath/avian/resource/Handler.java | 4 + classpath/java-lang.cpp | 1 - classpath/java/lang/Class.java | 60 +- classpath/java/lang/OutOfMemoryError.java | 2 +- classpath/java/lang/StackTraceElement.java | 2 +- classpath/java/lang/ref/ReferenceQueue.java | 10 +- classpath/java/lang/reflect/Field.java | 2 +- makefile | 203 +- openjdk.ld | 288 +++ src/builtin.cpp | 767 +------ src/classpath-avian.cpp | 601 ++++++ src/classpath-common.h | 271 +++ src/classpath-openjdk.cpp | 2096 +++++++++++++++++++ src/common.h | 10 + src/compile-x86.S | 2 +- src/compile.cpp | 110 +- src/continuations-x86.S | 8 +- src/interpret.cpp | 190 +- src/jnienv.cpp | 159 +- src/machine.cpp | 261 ++- src/machine.h | 289 ++- src/posix.cpp | 2 +- src/process.cpp | 7 +- src/process.h | 2 +- src/processor.h | 4 + src/system.h | 2 +- src/type-generator.cpp | 69 +- src/types.def | 49 +- test/test.sh | 6 +- 36 files changed, 4452 insertions(+), 1603 deletions(-) create mode 100644 classpath/avian/Classes.java create mode 100644 classpath/avian/FieldAddendum.java create mode 100644 classpath/avian/MethodAddendum.java create mode 100644 openjdk.ld create mode 100644 src/classpath-avian.cpp create mode 100644 src/classpath-common.h create mode 100644 src/classpath-openjdk.cpp diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java index 80f3df6f8e..433b81e3c3 100644 --- a/classpath/avian/Addendum.java +++ b/classpath/avian/Addendum.java @@ -12,5 +12,5 @@ package avian; public class Addendum { public Object pool; - public Object annotationTable; + public Object annotationTable; } diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java new file mode 100644 index 0000000000..f312690606 --- /dev/null +++ b/classpath/avian/Classes.java @@ -0,0 +1,268 @@ +/* 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 + (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 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] = 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/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/avian/MethodAddendum.java b/classpath/avian/MethodAddendum.java new file mode 100644 index 0000000000..a2e40a5261 --- /dev/null +++ b/classpath/avian/MethodAddendum.java @@ -0,0 +1,15 @@ +/* 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 + 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 MethodAddendum extends Addendum { + public Object exceptionTable; +} diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 4ad1e3130a..d93be28114 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -10,24 +10,10 @@ 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.net.URL; import java.net.MalformedURLException; -import java.io.InputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; public class SystemClassLoader extends ClassLoader { - private static final int LinkFlag = 1 << 8; - - public static native VMClass defineVMClass - (ClassLoader loader, byte[] b, int offset, int length); - private static native VMClass findVMClass(String name) throws ClassNotFoundException; @@ -35,6 +21,8 @@ public class SystemClassLoader extends ClassLoader { return getClass(findVMClass(name)); } + public static native Class getClass(VMClass vmClass); + private static native VMClass findLoadedVMClass(String name); protected Class reallyFindLoadedClass(String name){ @@ -44,9 +32,6 @@ public class SystemClassLoader extends ClassLoader { private static native boolean resourceExists(String name); - private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) - throws ClassNotFoundException; - protected URL findResource(String name) { if (resourceExists(name)) { try { @@ -55,261 +40,4 @@ public class SystemClassLoader extends ClassLoader { } return null; } - - 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 - (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 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] = 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; - } - - 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; - } - - loadVMClass(loader, spec, start, end - start); - - return result; - } - - private static native void acquireClassLock(); - - private static native void releaseClassLock(); - - public static Class getClass(VMClass vmClass) { - if (vmClass.addendum == null) { - SystemClassLoader.acquireClassLock(); - try { - if (vmClass.addendum == null) { - vmClass.addendum = new ClassAddendum(); - } - } finally { - SystemClassLoader.releaseClassLock(); - } - } - - if (vmClass.addendum.class_ == null) { - SystemClassLoader.acquireClassLock(); - try { - if (vmClass.addendum.class_ == null) { - vmClass.addendum.class_ = new Class(vmClass); - } - } finally { - SystemClassLoader.releaseClassLock(); - } - } - - return vmClass.addendum.class_; - } - - public static native VMClass getVMClass(Object o); - - 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); - } } diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java index 96c2959f73..699a68e5f8 100644 --- a/classpath/avian/VMField.java +++ b/classpath/avian/VMField.java @@ -17,6 +17,6 @@ public class VMField { public short offset; public byte[] name; public byte[] spec; - public avian.Addendum addendum; + public FieldAddendum addendum; public VMClass class_; } diff --git a/classpath/avian/VMMethod.java b/classpath/avian/VMMethod.java index 374b424d84..5a6754c034 100644 --- a/classpath/avian/VMMethod.java +++ b/classpath/avian/VMMethod.java @@ -20,7 +20,7 @@ public class VMMethod { public int nativeID; public byte[] name; public byte[] spec; - public avian.Addendum addendum; + 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..38d0312ff4 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/resource/Handler.java @@ -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 { diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 8303e3e4e1..720b364729 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -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" diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 4b053d89ca..6d234f3765 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -47,8 +47,6 @@ public final class Class this.vmClass = vmClass; } - public static native VMClass vmClass(Object o); - public String toString() { return getName(); } @@ -71,23 +69,23 @@ public final class Class public static String getName(VMClass c) { if (c.name == null) { if ((c.vmFlags & PrimitiveFlag) != 0) { - if (c == primitiveClass('V')) { + if (c == SystemClassLoader.primitiveClass('V')) { c.name = "void\0".getBytes(); - } else if (c == primitiveClass('Z')) { + } else if (c == SystemClassLoader.primitiveClass('Z')) { c.name = "boolean\0".getBytes(); - } else if (c == primitiveClass('B')) { + } else if (c == SystemClassLoader.primitiveClass('B')) { c.name = "byte\0".getBytes(); - } else if (c == primitiveClass('C')) { + } else if (c == SystemClassLoader.primitiveClass('C')) { c.name = "char\0".getBytes(); - } else if (c == primitiveClass('S')) { + } else if (c == SystemClassLoader.primitiveClass('S')) { c.name = "short\0".getBytes(); - } else if (c == primitiveClass('I')) { + } else if (c == SystemClassLoader.primitiveClass('I')) { c.name = "int\0".getBytes(); - } else if (c == primitiveClass('F')) { + } else if (c == SystemClassLoader.primitiveClass('F')) { c.name = "float\0".getBytes(); - } else if (c == primitiveClass('J')) { + } else if (c == SystemClassLoader.primitiveClass('J')) { c.name = "long\0".getBytes(); - } else if (c == primitiveClass('D')) { + } else if (c == SystemClassLoader.primitiveClass('D')) { c.name = "double\0".getBytes(); } else { throw new AssertionError(); @@ -154,15 +152,11 @@ public final class Class Class c = loader.loadClass(name); SystemClassLoader.link(c.vmClass, loader); if (initialize) { - initialize(c.vmClass); + SystemClassLoader.initialize(c.vmClass); } return c; } - private static native VMClass primitiveClass(char name); - - private static native void initialize(VMClass vmClass); - public static Class forCanonicalName(String name) { return forCanonicalName(null, name); } @@ -175,7 +169,8 @@ public final class Class return forName(name.substring(1, name.length() - 1), true, loader); } else { if (name.length() == 1) { - return SystemClassLoader.getClass(primitiveClass(name.charAt(0))); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass(name.charAt(0))); } else { throw new ClassNotFoundException(name); } @@ -189,21 +184,29 @@ public final class Class if (isArray()) { String n = getName(); if ("[Z".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('Z')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('Z')); } else if ("[B".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('B')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('B')); } else if ("[S".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('S')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('S')); } else if ("[C".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('C')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('C')); } else if ("[I".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('I')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('I')); } else if ("[F".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('F')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('F')); } else if ("[J".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('J')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('J')); } else if ("[D".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('D')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('D')); } if (vmClass.staticTable == null) throw new AssertionError(); @@ -213,10 +216,8 @@ public final class Class } } - public static native boolean isAssignableFrom(VMClass a, VMClass b); - public boolean isAssignableFrom(Class c) { - return isAssignableFrom(vmClass, c.vmClass); + return SystemClassLoader.isAssignableFrom(vmClass, c.vmClass); } private static Field findField(VMClass vmClass, String name) { @@ -533,7 +534,8 @@ public final class Class } public static boolean isInstance(VMClass c, Object o) { - return o != null && isAssignableFrom(c, SystemClassLoader.getVMClass(o)); + return o != null && SystemClassLoader.isAssignableFrom + (c, SystemClassLoader.getVMClass(o)); } public boolean isInstance(Object o) { diff --git a/classpath/java/lang/OutOfMemoryError.java b/classpath/java/lang/OutOfMemoryError.java index 50848a9ae4..29cae34d73 100644 --- a/classpath/java/lang/OutOfMemoryError.java +++ b/classpath/java/lang/OutOfMemoryError.java @@ -10,7 +10,7 @@ package java.lang; -public class OutOfMemoryError extends Error { +public class OutOfMemoryError extends VirtualMachineError { public OutOfMemoryError(String message) { super(message, null); } diff --git a/classpath/java/lang/StackTraceElement.java b/classpath/java/lang/StackTraceElement.java index db16585c73..9b933412e9 100644 --- a/classpath/java/lang/StackTraceElement.java +++ b/classpath/java/lang/StackTraceElement.java @@ -56,7 +56,7 @@ public class StackTraceElement { } public String getClassName() { - return class_.replace('/', '.'); + return class_; } public String getMethodName() { diff --git a/classpath/java/lang/ref/ReferenceQueue.java b/classpath/java/lang/ref/ReferenceQueue.java index 46eb1f26ce..068a5bfbc1 100644 --- a/classpath/java/lang/ref/ReferenceQueue.java +++ b/classpath/java/lang/ref/ReferenceQueue.java @@ -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/Field.java b/classpath/java/lang/reflect/Field.java index 504b85d402..b8f9ac0cf3 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -204,7 +204,7 @@ public class Field extends AccessibleObject { } else { throw new IllegalArgumentException ("needed " + getType() + ", got " - + Class.getName(Class.vmClass(target)) + + + Class.getName(SystemClassLoader.vmClass(target)) + " when setting " + Class.getName(vmField.class_) + "." + getName()); } break; diff --git a/makefile b/makefile index f0dcab31a5..d388a28570 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -MAKEFLAGS = -s +#MAKEFLAGS = -s name = avian version = 0.3 @@ -39,11 +39,17 @@ endif ifeq ($(continuations),true) options := $(options)-continuations endif + +classpath = avian + +test-library-path = . +test-executable = $(executable) + ifdef gnu + classpath = gnu options := $(options)-gnu - gnu-sources = $(src)/gnu.cpp - gnu-jar = $(gnu)/share/classpath/glibj.zip - gnu-libraries = \ + classapth-jar = $(gnu)/share/classpath/glibj.zip + classpath-libraries = \ $(gnu)/lib/classpath/libjavaio.a \ $(gnu)/lib/classpath/libjavalang.a \ $(gnu)/lib/classpath/libjavalangreflect.a \ @@ -51,10 +57,20 @@ ifdef gnu $(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") + classpath-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU + classpath-lflags = -lgmp +endif +ifdef openjdk + classpath = openjdk + options := $(options)-openjdk + ifeq ($(arch),x86_64) + openjdk-lib-dir = $(openjdk)/jre/lib/amd64 + else + openjdk-lib-dir = $(openjdk)/jre/lib + endif + classpath-jar = $(openjdk)/jre/lib/rt.jar + test-library-path = $(openjdk-lib-dir):$(native-build) + test-executable = $(executable-dynamic) endif root := $(shell (cd .. && pwd)) @@ -63,13 +79,16 @@ native-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 +ifneq ($(classpath),avian) + classpath-object-dep = $(build)/classpath-object.dep + classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") else - avian-classpath-build = $(classpath-build) + jni-sources := $(shell find $(classpath-src) -name '*.cpp') + jni-objects = \ + $(call cpp-objects,$(jni-sources),$(classpath-src),$(native-build)) endif input = List @@ -79,12 +98,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) @@ -112,14 +131,14 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS $(gnu-cflags) + -DUSE_ATOMIC_OPERATIONS $(classpath-cflags) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread cflags = $(build-cflags) -common-lflags = -lm -lz $(gnu-lflags) +common-lflags = -lm -lz $(classpath-lflags) build-lflags = @@ -297,9 +316,6 @@ 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 \ @@ -307,26 +323,7 @@ generated-code = \ $(native-build)/type-initializations.cpp \ $(native-build)/type-java-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,10 +332,10 @@ 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 @@ -428,48 +425,37 @@ converter = $(native-build)/binaryToObject static-library = $(native-build)/lib$(name).a executable = $(native-build)/$(name)${exe-suffix} -dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix) +dynamic-library = $(native-build)/$(so-prefix)jvm$(so-suffix) executable-dynamic = $(native-build)/$(name)-dynamic${exe-suffix} -classpath-sources := $(shell find $(classpath) -name '*.java') +ifneq ($(classpath),avian) + classpath-sources := \ + $(classpath-src)/avian/Continuations.java \ + $(classpath-src)/avian/Callback.java \ + $(classpath-src)/avian/CallbackReceiver.java \ + $(classpath-src)/avian/IncompatibleContinuationException.java \ + $(classpath-src)/avian/SystemClassLoader.java \ + $(classpath-src)/avian/Machine.java \ + $(classpath-src)/avian/Addendum.java \ + $(classpath-src)/avian/ClassAddendum.java \ + $(classpath-src)/avian/MethodAddendum.java \ + $(classpath-src)/avian/FieldAddendum.java \ + $(classpath-src)/avian/VMClass.java \ + $(classpath-src)/avian/VMField.java \ + $(classpath-src)/avian/VMMethod.java \ + $(classpath-src)/avian/resource/Handler.java +else + classpath-sources := $(shell find $(classpath-src) -name '*.java') +endif + classpath-classes = \ - $(call java-classes,$(classpath-sources),$(classpath),$(classpath-build)) + $(call java-classes,$(classpath-sources),$(classpath-src),$(classpath-build)) classpath-object = $(native-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)) @@ -510,7 +496,7 @@ vg: build .PHONY: test test: build /bin/sh $(test)/test.sh 2>/dev/null \ - $(executable) $(mode) "$(flags)" \ + $(test-library-path) $(test-executable) $(mode) "$(flags)" \ $(call class-names,$(test-build),$(test-classes)) .PHONY: tarball @@ -549,27 +535,20 @@ $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) $(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) $(classpath-jar) @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) +ifneq ($(classpath),avian) (wd=$$(pwd) && \ cd $(classpath-build) && \ - $(jar) xf $(gnu-jar) && \ - rm $(gnu-blacklist) && \ - jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")") + $(jar) xf $(classpath-jar)) endif + $(javac) -d $(classpath-build) \ + -bootclasspath $(classpath-build) \ + $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -625,7 +604,7 @@ $(driver-object): $(driver-source) $(driver-dynamic-object): $(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) @@ -668,14 +647,14 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ -c $(<) -o $(@) -$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp +$(jni-objects): $(native-build)/%.o: $(classpath-src)/%.cpp $(compile-object) -$(static-library): $(gnu-object-dep) +$(static-library): $(classpath-object-dep) $(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) $(call gnu-objects) + $(ar) cru $(@) $(^) $(call classpath-objects) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -687,13 +666,13 @@ $(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) +$(classpath-object-dep): $(classpath-libraries) + @mkdir -p $(build)/classpath-objects + (cd $(build)/classpath-objects && \ + for x in $(classpath-libraries); do ar x $${x}; done) @touch $(@) -$(executable): $(gnu-object-dep) +$(executable): $(classpath-object-dep) $(executable): \ $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ $(boot-object) $(vm-classpath-object) @@ -704,13 +683,13 @@ ifdef msvc -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(dlltool) -z $(@).def $(^) $(call gnu-objects) + $(dlltool) -z $(@).def $(^) $(call classpath-objects) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@) + $(ld) $(@).exp $(^) $(call classpath-objects) $(lflags) -o $(@) endif else - $(ld) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(ld) $(^) $(call classpath-objects) $(rdynamic) $(lflags) \ + $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -740,18 +719,18 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -$(dynamic-library): $(gnu-object-dep) +$(dynamic-library): $(classpath-object-dep) $(dynamic-library): \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) $(gnu-libraries) + $(boot-object) $(vm-classpath-object) $(classpath-libraries) @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ -IMPLIB:$(native-build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(ld) $(^) -Wl,--version-script=openjdk.ld \ + $(call classpath-objects) $(shared) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) 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/src/builtin.cpp b/src/builtin.cpp index 13333a1fb6..2d0d115a3c 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -39,135 +39,14 @@ search(Thread* t, object name, object (*op)(Thread*, object), return reinterpret_cast(r); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } -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); - } -} - -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); - } -} - } // 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_getVMClass -(Thread* t, object, uintptr_t* arguments) -{ - object o = reinterpret_cast(arguments[0]); - - return reinterpret_cast(objectClass(t, o)); -} - -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*) @@ -195,8 +74,6 @@ Avian_avian_SystemClassLoader_defineVMClass (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]; @@ -204,20 +81,9 @@ Avian_avian_SystemClassLoader_defineVMClass uint8_t* buffer = static_cast (t->m->heap->allocate(length)); memcpy(buffer, &byteArrayBody(t, b, offset), length); - object c = parseClass(t, loader, buffer, length); + object c = defineClass(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); } @@ -260,62 +126,21 @@ Avian_avian_SystemClassLoader_resourceExists stringChars(t, name, RUNTIME_ARRAY_BODY(n)); return t->m->finder->exists(RUNTIME_ARRAY_BODY(n)); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_io_ObjectInputStream_makeInstance +Avian_avian_SystemClassLoader_primitiveClass (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; - } + return reinterpret_cast(primitiveClass(t, arguments[0])); } extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Class_initialize +Avian_avian_SystemClassLoader_initialize (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); @@ -324,7 +149,7 @@ Avian_java_lang_Class_initialize } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_isAssignableFrom +Avian_avian_SystemClassLoader_isAssignableFrom (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); @@ -333,392 +158,12 @@ Avian_java_lang_Class_isAssignableFrom if (LIKELY(that)) { return vm::isAssignableFrom(t, this_, that); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); 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); -} - #ifdef AVIAN_HEAPDUMP extern "C" JNIEXPORT void JNICALL @@ -753,193 +198,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) @@ -973,7 +231,8 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open return reinterpret_cast (t->m->finder->find(RUNTIME_ARRAY_BODY(p))); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp new file mode 100644 index 0000000000..b9b5570eda --- /dev/null +++ b/src/classpath-avian.cpp @@ -0,0 +1,601 @@ +/* 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, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, + group); + } + + virtual void + runThread(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); + } + } + + virtual object + makeThrowable + (Thread* t, Machine::Type type, object message, object trace, object cause) + { + PROTECT(t, message); + PROTECT(t, cause); + + if (trace == 0) { + trace = makeTrace(t); + } + + object result = make(t, arrayBody(t, t->m->types, type)); + + set(t, result, ThrowableMessage, message); + set(t, result, ThrowableTrace, trace); + set(t, result, ThrowableCause, cause); + + return result; + } + + 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) +{ + 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) +{ + object o = reinterpret_cast(arguments[0]); + + return reinterpret_cast(objectClass(t, o)); +} + +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]); + + object v = t->m->processor->invokeArray(t, method, instance, args); + if (t->exception) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, 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 = t->m->classpath->makeThrowable + (t, Machine::IllegalArgumentExceptionType); + } + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + } + 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) +{ + 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 { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + 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)); + + 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); + + 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) +{ + 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 = arrayLength(t, trace); + object elementType = arrayBody + (t, t->m->types, Machine::StackTraceElementType); + object array = makeObjectArray + (t, classLoader(t, elementType), elementType, length); + PROTECT(t, array); + + for (unsigned i = 0; i < length; ++i) { + object ste = makeStackTraceElement(t, arrayBody(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_setDaemon +(Thread* t, object, uintptr_t* arguments) +{ + object thread = reinterpret_cast(arguments[0]); + bool daemon = arguments[1] != 0; + + setDaemon(t, thread, daemon); +} diff --git a/src/classpath-common.h b/src/classpath-common.h new file mode 100644 index 0000000000..23cccb8684 --- /dev/null +++ b/src/classpath-common.h @@ -0,0 +1,271 @@ +/* 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 + +namespace vm { + +inline 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; +} + +inline 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, 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 v.trace; +} + +inline 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)))); +} + +inline 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 { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IndexOutOfBoundsExceptionType); + return; + } + } else { + return; + } + } + } + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + return; + } + + t->exception = t->m->classpath->makeThrowable + (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, bool mapName, bool runOnLoad) +{ + ACQUIRE(t, t->m->classLock); + + const char* builtins = findProperty(t, "avian.builtins"); + if (mapName and builtins) { + const char* s = builtins; + while (*s) { + unsigned length = strlen(name); + if (::strncmp(s, name, length) == 0 + and (s[length] == ',' or s[length] == 0)) + { + // library is built in to this executable + if (runOnLoad and not t->m->triedBuiltinOnLoad) { + t->m->triedBuiltinOnLoad = true; + runOnLoadIfFound(t, t->m->libraries); + } + return t->m->libraries; + } 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(), name) == 0 + and lib->mapName() == mapName) + { + // already loaded + return lib; + } + last = lib; + } + + System::Library* lib; + if (LIKELY(t->m->system->success(t->m->system->load(&lib, name, mapName)))) { + last->setNext(lib); + if (runOnLoad) { + runOnLoadIfFound(t, lib); + } + return lib; + } else { + object message = makeString(t, "library not found: %s", name); + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, message); + return 0; + } +} + +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_); + + RUNTIME_ARRAY(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..39c6592bc9 --- /dev/null +++ b/src/classpath-openjdk.cpp @@ -0,0 +1,2096 @@ +/* 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" + +// todo: move platform-specific stuff into system.h and implementations + +#ifdef PLATFORM_WINDOWS + +# include +# include +# include +# include + +# define CLOSE _close +# define READ _read +# define WRITE _write + +# 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 _wopen +# define CREAT _wcreat +# endif + +#else // not PLATFORM_WINDOWS + +# include +# include +# include +# include +# include + +# define OPEN open +# define CLOSE close +# define READ read +# define WRITE write +# define LSEEK lseek + +#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; + +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) +{ + RUNTIME_ARRAY(char, s, byteArrayLength(t, name)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), + reinterpret_cast(&byteArrayBody(t, name, 0))); + + return makeString(t, "%s", s); +} + +class MyClasspath : public Classpath { + public: + MyClasspath(Allocator* allocator): + allocator(allocator) + { } + + virtual object + makeJclass(Thread* t, object 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) + == arrayBody(t, t->m->types, 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 = makeThreadGroup + (t, 0, 0, MaxPriority, false, false, false, 0, 0, 0, 0, 0); + } + + return vm::makeThread + (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, t->m->loader, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, false); + } + + virtual void + runThread(Thread* t) + { + object method = resolveMethod + (t, t->m->loader, "java/lang/Thread", "run", "()V"); + + if (LIKELY(t->exception == 0)) { + t->m->processor->invoke(t, method, t->javaThread); + } + } + + virtual object + makeThrowable + (Thread* t, Machine::Type type, object message, object trace, object cause) + { + PROTECT(t, message); + PROTECT(t, cause); + + if (trace == 0) { + trace = makeTrace(t); + } + + object result = make(t, arrayBody(t, t->m->types, type)); + + set(t, result, ThrowableMessage, message); + set(t, result, ThrowableTrace, trace); + set(t, result, ThrowableCause, cause); + + return result; + } + + virtual void + boot(Thread* t) + { + globalMachine = t->m; + + if (loadLibrary(t, "java", true, true) == 0) { + abort(t); + } + + t->m->processor->invoke + (t, t->m->loader, "java/lang/System", "initializeSystemClass", "()V", 0); + } + + virtual void + dispose() + { + allocator->free(this, sizeof(*this)); + } + + Allocator* allocator; +}; + +struct JVM_ExceptionTableEntryType{ + jint start_pc; + jint end_pc; + jint handler_pc; + jint catchType; +}; + +struct jvm_version_info { + unsigned int jvm_version; + unsigned int update_version: 8; + unsigned int special_update_version: 8; + unsigned int reserved1: 16; + unsigned int reserved2; + unsigned int is_attach_supported: 1; + unsigned int is_kernel_jvm: 1; + unsigned int: 30; + unsigned int: 32; + unsigned int: 32; +}; + +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) { + return objectArrayLength(t, table); + } else { + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmField = arrayBody(t, table, i); + if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { + ++ count; + } + } + return count; + } +} + +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': { + RUNTIME_ARRAY(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 '[': { + RUNTIME_ARRAY(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) +{ + object c = resolveClassBySpec(t, loader, spec, specLength); + + if (UNLIKELY(t->exception)) return 0; + + return getJClass(t, c); +} + +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); + if (UNLIKELY(t->exception)) { + return 0; + } + + 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); + if (UNLIKELY(t->exception)) { + return 0; + } + + 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); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, list); + + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, 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) { + return makeObjectArray + (t, loader, arrayBody(t, t->m->types, Machine::JclassType), 0); + } + + PROTECT(t, loader); + PROTECT(t, addendum); + + object array = makeObjectArray + (t, loader, arrayBody(t, t->m->types, 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) + == arrayBody(t, t->m->types, Machine::ReferenceType)) + { + o = resolveClass(t, loader, referenceName(t, o)); + if (UNLIKELY(t->exception)) return 0; + + 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); +} + +} // namespace local + +} // namespace + +namespace vm { + +Classpath* +makeClasspath(System*, Allocator* allocator) +{ + return new (allocator->allocate(sizeof(local::MyClasspath))) + local::MyClasspath(allocator); +} + +} // 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 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_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_getObjectVolatile +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + unsigned offset = arguments[2]; + object value = cast(o, offset); + loadMemoryBarrier(); + return reinterpret_cast(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); + 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_allocateMemory +(Thread* t, object, uintptr_t* arguments) +{ + void* p = malloc(arguments[1]); + if (p) { + return reinterpret_cast(p); + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::OutOfMemoryErrorType); + return 0; + } +} + +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_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 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 void JNICALL +Avian_sun_misc_Unsafe_ensureClassInitialized +(Thread* t, object, uintptr_t* arguments) +{ + initClass(t, jclassVmClass(t, reinterpret_cast(arguments[1]))); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_GetInterfaceVersion() +{ + return local::InterfaceVersion; +} + +extern "C" JNIEXPORT jint JNICALL +JVM_IHashCode(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + return objectHash(t, *o); +} + +extern "C" JNIEXPORT void JNICALL +JVM_MonitorWait(Thread* t, jobject o, jlong milliseconds) +{ + ENTER(t, Thread::ActiveState); + + vm::wait(t, *o, milliseconds); +} + +extern "C" JNIEXPORT void JNICALL +JVM_MonitorNotify(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + notify(t, *o); +} + +extern "C" JNIEXPORT void JNICALL +JVM_MonitorNotifyAll(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + notifyAll(t, *o); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_Clone(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, clone(t, *o)); +} + +extern "C" JNIEXPORT jstring JNICALL +JVM_InternString(Thread* t, jstring s) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, intern(t, *s)); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_CurrentTimeMillis(Thread* t, jclass) +{ + return t->m->system->now(); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_NanoTime(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_ArrayCopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, + jint dstOffset, jint length) +{ + ENTER(t, Thread::ActiveState); + + arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_InitProperties(Thread* t, jobject properties) +{ + ENTER(t, Thread::ActiveState); + + 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 0; + } + + 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, "java.home", "/tmp"); + local::setProperty(t, method, *properties, "user.home", getenv("HOME")); + local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); + + // todo: set this to something sane: + local::setProperty(t, method, *properties, "sun.boot.library.path", + getenv("LD_LIBRARY_PATH")); + +#endif + 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 == '=') { + RUNTIME_ARRAY(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 properties; +} + +extern "C" JNIEXPORT void JNICALL +JVM_OnExit(void (*)(void)) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Exit(jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Halt(jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GC() +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + collect(t, Heap::MajorCollection); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_MaxObjectInspectionAge(void) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_TraceInstructions(jboolean) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_TraceMethodCalls(jboolean) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_TotalMemory(void) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_FreeMemory(void) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_MaxMemory(void) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ActiveProcessorCount(void) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +JVM_LoadLibrary(const char* name) +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + return loadLibrary(t, name, false, false); +} + +extern "C" JNIEXPORT void JNICALL +JVM_UnloadLibrary(void*) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +JVM_FindLibraryEntry(void* library, const char* name) +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + return static_cast(library)->resolve(name); +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsSupportedJNIVersion(jint version) +{ + return version <= JNI_VERSION_1_4; +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsNaN(jdouble) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_FillInStackTrace(Thread* t, jobject throwable) +{ + ENTER(t, Thread::ActiveState); + + object trace = getTrace(t, 1); + set(t, *throwable, ThrowableTrace, trace); +} + +extern "C" JNIEXPORT void JNICALL +JVM_PrintStackTrace(Thread*, jobject, jobject) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetStackTraceDepth(Thread* t, jobject throwable) +{ + ENTER(t, Thread::ActiveState); + + return arrayLength(t, throwableTrace(t, *throwable)); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetStackTraceElement(Thread* t, jobject throwable, jint index) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, makeStackTraceElement + (t, arrayBody(t, throwableTrace(t, *throwable), index))); +} + +extern "C" JNIEXPORT void JNICALL +JVM_InitializeCompiler (Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsSilentCompiler(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_CompileClass(Thread*, jclass, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_CompileClasses(Thread*, jclass, jstring) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_CompilerCommand(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_EnableCompiler(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_DisableCompiler(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_StartThread(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + startThread(t, *thread); +} + +extern "C" JNIEXPORT void JNICALL +JVM_StopThread(Thread*, jobject, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsThreadAlive(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + Thread* p = reinterpret_cast(threadPeer(t, *thread)); + if (p) { + switch (p->state) { + case Thread::ActiveState: + case Thread::IdleState: + case Thread::ExclusiveState: + return true; + + case Thread::NoState: + case Thread::ZombieState: + case Thread::JoinedState: + case Thread::ExitState: + return false; + + default: + abort(t); + } + } else { + return false; + } +} + +extern "C" JNIEXPORT void JNICALL +JVM_SuspendThread(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_ResumeThread(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetThreadPriority(Thread*, jobject, jint) +{ + // ignore +} + +extern "C" JNIEXPORT void JNICALL +JVM_Yield(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Sleep(Thread* t, jclass, jlong milliseconds) +{ + ENTER(t, Thread::ActiveState); + + 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)); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_CurrentThread(Thread* t, jclass) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, t->javaThread); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_CountStackFrames(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Interrupt(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsInterrupted(Thread*, jobject, jboolean) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_HoldsLock(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_DumpAllStacks(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetAllThreads(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_DumpThreads(Thread*, jclass, jobjectArray) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_CurrentLoadedClass(Thread*) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_CurrentClassLoader(Thread*) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassContext(Thread*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ClassDepth(Thread*, jstring) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ClassLoaderDepth(Thread*) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_GetSystemPackage(Thread*, jstring) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetSystemPackages(Thread*) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_AllocateNewObject(Thread*, jobject, jclass, + jclass) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_AllocateNewArray(Thread*, jobject, jclass, + jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_LatestUserDefinedLoader(Thread*) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_LoadClass0(Thread*, jobject, jclass, + jstring) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetArrayLength(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetArrayElement(Thread*, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jvalue JNICALL +JVM_GetPrimitiveArrayElement(Thread*, jobject, jint, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetArrayElement(Thread*, jobject, jint, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetPrimitiveArrayElement(Thread*, jobject, jint, jvalue, + unsigned char) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_NewArray(Thread* t, jclass elementClass, jint length) +{ + ENTER(t, Thread::ActiveState); + + 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 makeLocalReference(t, makeBooleanArray(t, length)); + } else { + return makeLocalReference(t, makeByteArray(t, length)); + } + case 'c': return makeLocalReference(t, makeCharArray(t, length)); + case 'd': return makeLocalReference(t, makeDoubleArray(t, length)); + case 'f': return makeLocalReference(t, makeFloatArray(t, length)); + case 'i': return makeLocalReference(t, makeIntArray(t, length)); + case 'l': return makeLocalReference(t, makeLongArray(t, length)); + case 's': return makeLocalReference(t, makeShortArray(t, length)); + default: abort(t); + } + } else { + return makeLocalReference + (t, makeObjectArray(t, t->m->loader, c, length)); + } +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_NewMultiArray(Thread*, jclass, jintArray) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +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 +JVM_FindPrimitiveClass(Thread* t, const char* name) +{ + ENTER(t, Thread::ActiveState); + + switch (*name) { + case 'b': + if (name[1] == 'o') { + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JbooleanType))); + } else { + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JbyteType))); + } + case 'c': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JcharType))); + case 'd': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JdoubleType))); + case 'f': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JfloatType))); + case 'i': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JintType))); + case 'l': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JlongType))); + case 's': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JshortType))); + case 'v': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JvoidType))); + default: + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalArgumentExceptionType); + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +JVM_ResolveClass(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindClassFromClassLoader(Thread* t, const char* name, jboolean init, + jobject loader, jboolean throwError) +{ + ENTER(t, Thread::ActiveState); + + object c = resolveClass(t, loader ? *loader : t->m->loader, name); + if (t->exception) { + if (throwError) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoClassDefFoundErrorType, + throwableMessage(t, t->exception), + throwableTrace(t, t->exception), + throwableCause(t, t->exception)); + } + return 0; + } + + if (init) { + PROTECT(t, c); + + initClass(t, c); + } + + return makeLocalReference(t, getJClass(t, c)); +} + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindClassFromClass(Thread*, const char*, jboolean, + jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindLoadedClass(Thread*, jobject, jstring) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_DefineClass(Thread*, const char*, jobject, const jbyte*, + jsize, jobject) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_DefineClassWithSource(Thread*, const char*, jobject, + const jbyte*, jsize, jobject, + const char*) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_GetClassName(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, jclassName(t, *c)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassInterfaces(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object table = classInterfaceTable(t, jclassVmClass(t, *c)); + if (table) { + unsigned stride = + (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; + + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, 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 makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), + 0)); + } +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetClassLoader(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object loader = classLoader(t, jclassVmClass(t, *c)); + return loader == t->m->loader ? 0 : makeLocalReference(t, loader); +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsInterface(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) != 0; +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassSigners(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetClassSigners(Thread*, jclass, jobjectArray) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetProtectionDomain(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetProtectionDomain(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsArrayClass(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return classArrayDimensions(t, jclassVmClass(t, *c)) != 0; +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsPrimitiveClass(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return (classVmFlags(t, jclassVmClass(t, *c)) & PrimitiveFlag) != 0; +} + +extern "C" JNIEXPORT jclass JNICALL +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 +JVM_GetClassModifiers(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return classFlags(t, jclassVmClass(t, *c)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetDeclaredClasses(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_GetDeclaringClass(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_GetClassSignature(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jbyteArray JNICALL +JVM_GetClassAnnotations(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, addendumAnnotationTable(t, classAddendum(t, jclassVmClass(t, *c)))); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) +{ + ENTER(t, Thread::ActiveState); + + object table = classMethodTable(t, jclassVmClass(t, *c)); + if (table) { + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, 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); + + if (UNLIKELY(t->exception)) return 0; + + 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); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, returnType); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, jclassVmClass(t, *c)), + methodAddendum(t, vmMethod)); + + if (UNLIKELY(t->exception)) return 0; + + 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) { + fprintf(stderr, "method %s.%s has annotations\n", + &byteArrayBody(t, className(t, jclassVmClass(t, *c)), 0), + &byteArrayBody(t, methodName(t, vmMethod), 0)); + + set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + 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 makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JmethodType), + 0)); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) +{ + ENTER(t, Thread::ActiveState); + + object table = classFieldTable(t, jclassVmClass(t, *c)); + if (table) { + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, 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); + + if (UNLIKELY(t->exception)) { + return 0; + } + + 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) { + set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + 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); + } + } + + return makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JfieldType), 0)); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredConstructors(Thread* t, jclass c, jboolean publicOnly) +{ + ENTER(t, Thread::ActiveState); + + object table = classMethodTable(t, jclassVmClass(t, *c)); + if (table) { + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, 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); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, parameterTypes); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, jclassVmClass(t, *c)), + methodAddendum(t, vmMethod)); + + if (UNLIKELY(t->exception)) return 0; + + 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) { + set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + 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 makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JconstructorType), + 0)); + } +} + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassAccessFlags(Thread* t, jclass c) +{ + return JVM_GetClassModifiers(t, c); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_InvokeMethod(Thread* t, jobject method, jobject instance, + jobjectArray arguments) +{ + ENTER(t, Thread::ActiveState); + + object vmMethod = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jmethodClazz(t, *method))), + jmethodSlot(t, *method)); + + object result; + if (arguments) { + result = t->m->processor->invokeArray + (t, vmMethod, instance ? *instance : 0, *arguments); + } else { + result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); + } + + return result ? makeLocalReference(t, result) : 0; +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_NewInstanceFromConstructor(Thread* t, jobject constructor, + jobjectArray arguments) +{ + ENTER(t, Thread::ActiveState); + + 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 (arguments) { + t->m->processor->invokeArray(t, method, instance, *arguments); + } else { + t->m->processor->invoke(t, method, instance); + } + + if (UNLIKELY(t->exception)) { + return 0; + } else { + return makeLocalReference(t, instance); + } +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetClassConstantPool(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, makeConstantPool + (t, addendumPool(t, classAddendum(t, jclassVmClass(t, *c))))); +} + +extern "C" JNIEXPORT jint JNICALL +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 +JVM_ConstantPoolGetClassAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_ConstantPoolGetClassAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetMethodAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetMethodAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetFieldAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetFieldAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_ConstantPoolGetMemberRefInfoAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ConstantPoolGetIntAt(Thread* t, jobject, jobject pool, jint index) +{ + ENTER(t, Thread::ActiveState); + + return singletonValue(t, *pool, index - 1); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_ConstantPoolGetLongAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jfloat JNICALL +JVM_ConstantPoolGetFloatAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jdouble JNICALL +JVM_ConstantPoolGetDoubleAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_ConstantPoolGetStringAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_ConstantPoolGetUTF8At(Thread* t, jobject, jobject pool, jint index) +{ + ENTER(t, Thread::ActiveState); + + object array = singletonObject(t, *pool, index - 1); + + return makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1)); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_DoPrivileged +(Thread* t, jclass, jobject action, jobject, jboolean wrapException) +{ + ENTER(t, Thread::ActiveState); + + object privilegedAction = resolveClass + (t, t->m->loader, "java/security/PrivilegedAction"); + + if (UNLIKELY(t->exception)) { + return 0; + } + + object method; + if (instanceOf(t, privilegedAction, *action)) { + method = resolveMethod + (t, privilegedAction, "run", "()Ljava/lang/Object;"); + } else { + object privilegedExceptionAction = resolveClass + (t, t->m->loader, "java/security/PrivilegedExceptionAction"); + + if (UNLIKELY(t->exception)) { + return 0; + } + + method = resolveMethod + (t, privilegedExceptionAction, "run", "()Ljava/lang/Object;"); + } + + if (LIKELY(t->exception == 0)) { + object result = t->m->processor->invoke(t, method, *action); + + if (LIKELY(t->exception == 0)) { + return makeLocalReference(t, result); + } else { + if (wrapException and not + (instanceOf + (t, arrayBody(t, t->m->types, Machine::ErrorType), t->exception) + or instanceOf + (t, arrayBody(t, t->m->types, Machine::RuntimeExceptionType), + t->exception))) + { + object cause = t->exception; + PROTECT(t, cause); + + t->exception = 0; + + object paeClass = resolveClass + (t, t->m->loader, "java/security/PrivilegedActionException"); + + if (LIKELY(t->exception == 0)) { + PROTECT(t, paeClass); + + object paeConstructor = resolveMethod + (t, paeClass, "", "(Ljava/lang/Exception;)V"); + PROTECT(t, paeConstructor); + + if (LIKELY(t->exception == 0)) { + object result = make(t, paeClass); + PROTECT(t, result); + + t->m->processor->invoke(t, paeConstructor, result, cause); + + if (LIKELY(t->exception == 0)) { + t->exception = result; + } + } + } + } + } + } + + return 0; +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetInheritedAccessControlContext(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetStackAccessControlContext(Thread*, jclass) +{ + return 0; +} + +extern "C" JNIEXPORT void* JNICALL +JVM_RegisterSignal(jint, void*) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_RaiseSignal(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_FindSignal(const char*) +{ + return -1; +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_DesiredAssertionStatus(Thread*, jclass, jclass) +{ + return false; +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_AssertionStatusDirectives(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_SupportsCX8(void) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetClassNameUTF(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetClassCPTypes(Thread*, jclass, unsigned char*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassCPEntriesCount(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassFieldsCount(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassMethodsCount(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetMethodIxExceptionIndexes(Thread*, jclass, jint, + unsigned short*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxExceptionsCount(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetMethodIxByteCode(Thread*, jclass, jint, + unsigned char*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxByteCodeLength(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetMethodIxExceptionTableEntry(Thread*, jclass, jint, + jint, + local::JVM_ExceptionTableEntryType*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxExceptionTableLength(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetFieldIxModifiers(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxModifiers(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxLocalsCount(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxArgsSize(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxMaxStack(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsConstructorIx(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetMethodIxNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetMethodIxSignatureUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPFieldNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPMethodNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPMethodSignatureUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPFieldSignatureUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPClassNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPFieldClassNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPMethodClassNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetCPFieldModifiers(Thread*, jclass, int, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetCPMethodModifiers(Thread*, jclass, int, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_ReleaseUTF(const char*) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsSameClassPackage(Thread*, jclass, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetLastErrorString(char* dst, int length) +{ + strncpy(dst, strerror(errno), length); + return strlen(dst); +} + +extern "C" JNIEXPORT char* JNICALL +JVM_NativePath(char* path) +{ + return path; +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Open(const char* name, jint flags, jint mode) +{ + return OPEN(name, flags, mode); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Close(jint fd) +{ + return CLOSE(fd); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Read(jint fd, char* dst, jint length) +{ + return READ(fd, dst, length); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Write(jint fd, char* src, jint length) +{ + return WRITE(fd, src, length); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Available(jint, jlong*) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_Lseek(jint fd, jlong offset, jint start) +{ + return LSEEK(fd, offset, start); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_SetLength(jint, jlong) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Sync(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_InitializeSocketLibrary(void) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Socket(jint, jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SocketClose(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SocketShutdown(jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Recv(jint, char*, jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Send(jint, char*, jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Timeout(int, long) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Listen(jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Connect(jint, struct sockaddr*, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Bind(jint, struct sockaddr*, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Accept(jint, struct sockaddr*, jint*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_RecvFrom(jint, char*, int, + int, struct sockaddr*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SendTo(jint, char*, int, + int, struct sockaddr*, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SocketAvailable(jint, jint*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetSockName(jint, struct sockaddr*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetSockOpt(jint, int, int, char*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SetSockOpt(jint, int, int, const char*, int) { abort(); } + +extern "C" JNIEXPORT struct protoent* JNICALL +JVM_GetProtoByName(char*) { abort(); } + +extern "C" JNIEXPORT struct hostent* JNICALL +JVM_GetHostByAddr(const char*, int, int) { abort(); } + +extern "C" JNIEXPORT struct hostent* JNICALL +JVM_GetHostByName(char*) { abort(); } + +extern "C" JNIEXPORT int JNICALL +JVM_GetHostName(char*, int) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +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 +JVM_RawMonitorDestroy(void* lock) +{ + static_cast(lock)->dispose(); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_RawMonitorEnter(void* lock) +{ + static_cast(lock)->acquire + (static_cast + (local::globalMachine->localThread->get())->systemThread); + + return 0; +} + +extern "C" JNIEXPORT void JNICALL +JVM_RawMonitorExit(void* lock) +{ + static_cast(lock)->release + (static_cast + (local::globalMachine->localThread->get())->systemThread); +} + +extern "C" JNIEXPORT void* JNICALL +JVM_GetManagement(jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_InitAgentProperties(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetEnclosingMethodInfo(JNIEnv*, jclass) { abort(); } + +extern "C" JNIEXPORT jintArray JNICALL +JVM_GetThreadStateValues(JNIEnv*, jint) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetThreadStateNames(JNIEnv*, jint, jintArray) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetVersionInfo(JNIEnv*, local::jvm_version_info*, size_t) { abort(); } + +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_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_vfprintf(FILE* stream, const char* format, va_list a) +{ + return vfprintf(stream, format, a); +} + +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; +} diff --git a/src/common.h b/src/common.h index 1a672feb6d..316eeef81c 100644 --- a/src/common.h +++ b/src/common.h @@ -465,6 +465,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-x86.S b/src/compile-x86.S index 7dd9349f40..9e86527444 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -22,7 +22,7 @@ #ifdef __x86_64__ -#define THREAD_STACK 2216 +#define THREAD_STACK 2224 #if defined __MINGW32__ || defined __CYGWIN32__ diff --git a/src/compile.cpp b/src/compile.cpp index a35fa98905..5619dd0769 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -40,7 +40,7 @@ namespace { namespace local { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -259,10 +259,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; @@ -2142,7 +2142,8 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) return methodAddress(t, target); } } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2414,7 +2415,8 @@ makeBlankObjectArray(MyThread* t, object loader, object class_, int32_t length) (makeObjectArray(t, loader, class_, length)); } else { object message = makeString(t, "%d", length); - t->exception = makeNegativeArraySizeException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); unwind(t); } } @@ -2463,7 +2465,8 @@ 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); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); unwind(t); } } @@ -2497,7 +2500,8 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value) if (LIKELY(o)) { set(t, o, offset, value); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2508,7 +2512,8 @@ acquireMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { acquire(t, o); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2519,7 +2524,8 @@ releaseMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { release(t, o); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2535,7 +2541,8 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, 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); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); return 0; } } @@ -2589,7 +2596,8 @@ throwArrayIndexOutOfBounds(MyThread* t) { if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { t->tracing = true; - t->exception = makeArrayIndexOutOfBoundsException(t, 0); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType); t->tracing = false; } else { // not enough memory available for a new exception and stack trace @@ -2606,7 +2614,8 @@ throw_(MyThread* t, object o) if (LIKELY(o)) { t->exception = o; } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } // printTrace(t, t->exception); @@ -2622,7 +2631,8 @@ checkCast(MyThread* t, object class_, object o) (t, "%s as %s", &byteArrayBody(t, className(t, objectClass(t, o)), 0), &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeClassCastException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassCastExceptionType, message); unwind(t); } } @@ -6125,34 +6135,32 @@ resolveNative(MyThread* t, object method) 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)) { + if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) { + object native = resolveNativeMethod(t, method); + if (UNLIKELY(native == 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); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, 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: + // ensure other threads only see the methodCode field populated + // once the object it points do has been populated: storeStoreMemoryBarrier(); - methodCompiled(t, method) = reinterpret_cast(function); + set(t, method, MethodCode, native); } } uint64_t -invokeNativeFast(MyThread* t, object method) +invokeNativeFast(MyThread* t, object method, void* function) { - return reinterpret_cast(methodCompiled(t, method)) + return reinterpret_cast(function) (t, method, static_cast(t->stack) + t->arch->frameFooterSize() @@ -6160,7 +6168,7 @@ invokeNativeFast(MyThread* t, object method) } uint64_t -invokeNativeSlow(MyThread* t, object method) +invokeNativeSlow(MyThread* t, object method, void* function) { PROTECT(t, method); @@ -6232,7 +6240,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; @@ -6247,7 +6254,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])); } } @@ -6268,7 +6275,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])); } } @@ -6327,10 +6334,11 @@ invokeNativeSlow(MyThread* t, object method) uint64_t invokeNative2(MyThread* t, object method) { - if (methodVmFlags(t, method) & FastNative) { - return invokeNativeFast(t, method); + object native = methodCode(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)); } } @@ -6829,7 +6837,8 @@ callContinuation(MyThread* t, object continuation, object result, action = Call; } } else { - t->exception = makeIncompatibleContinuationException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IncompatibleContinuationExceptionType); action = Throw; } } else { @@ -7165,7 +7174,8 @@ class SegFaultHandler: public System::SignalHandler { if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { t->tracing = true; - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); t->tracing = false; } else { // not enough memory available for a new NPE and stack trace @@ -7269,6 +7279,7 @@ class MyProcessor: public Processor { t->init(); if (false) { + fprintf(stderr, "%d\n", difference(&(t->stack), 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)); @@ -7518,7 +7529,7 @@ class MyProcessor: public Processor { assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); - unsigned size = parameterFootprint(t, methodSpec, false); + unsigned size = parameterFootprint(t, methodSpec, this_ == 0); RUNTIME_ARRAY(uintptr_t, array, size); RUNTIME_ARRAY(bool, objectMask, size); ArgumentList list @@ -7765,6 +7776,31 @@ class MyProcessor: public Processor { abort(t); } } + + virtual void registerNative(Thread* t, object method, void* function) { + PROTECT(t, method); + + expect(t, methodFlags(t, method) & ACC_NATIVE); + + object native = makeNative(t, function, false); + + // ensure other threads only see the methodCode field populated + // once the object it points do has been populated: + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, native); + } + + virtual 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, method, MethodCode, 0); + } + } + } + } System* s; Allocator* allocator; diff --git a/src/continuations-x86.S b/src/continuations-x86.S index c55679d0ba..5dc0ba9e10 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 2224 +#define THREAD_CONTINUATION 2232 #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 2240 +#define THREAD_EXCEPTION_OFFSET 2248 +#define THREAD_EXCEPTION_HANDLER 2256 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 diff --git a/src/interpret.cpp b/src/interpret.cpp index 28754a0a3b..7d362c27d9 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -509,7 +509,9 @@ resolveNativeMethodData(Thread* t, object method) &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); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, message); } } } @@ -524,7 +526,8 @@ checkStack(Thread* t, object method) + codeMaxStack(t, methodCode(t, method)) > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); } } @@ -680,15 +683,15 @@ invokeNativeSlow(Thread* t, object method) &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"); -// } + // 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); @@ -931,13 +934,15 @@ 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); + object message = makeString + (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -953,13 +958,15 @@ 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); + object message = makeString + (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1002,7 +1009,8 @@ interpret(Thread* t) class_, count)); } else { object message = makeString(t, "%d", count); - exception = makeNegativeArraySizeException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } } goto loop; @@ -1023,7 +1031,8 @@ interpret(Thread* t) if (LIKELY(array)) { pushInt(t, cast(array, BytesPerWord)); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1051,7 +1060,8 @@ interpret(Thread* t) case athrow: { exception = popObject(t); if (UNLIKELY(exception == 0)) { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } goto throw_; @@ -1071,7 +1081,8 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, booleanArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { @@ -1083,12 +1094,15 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, byteArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1110,7 +1124,8 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, booleanArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { @@ -1121,12 +1136,14 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, byteArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1147,11 +1164,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, charArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1169,11 +1188,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, charArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1191,7 +1212,8 @@ interpret(Thread* t) &byteArrayBody (t, className(t, objectClass(t, peekObject(t, sp - 1))), 0), &byteArrayBody(t, className(t, class_), 0)); - exception = makeClassCastException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ClassCastExceptionType, message); goto throw_; } } @@ -1228,11 +1250,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, doubleArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1250,11 +1274,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, doubleArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1428,11 +1454,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, floatArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1450,11 +1478,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, floatArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1566,7 +1596,8 @@ interpret(Thread* t) } } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1658,11 +1689,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, intArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1687,11 +1720,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, intArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1958,7 +1993,8 @@ interpret(Thread* t) (t, method, objectClass(t, peekObject(t, sp - parameterFootprint))); goto invoke; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1983,7 +2019,8 @@ interpret(Thread* t) goto invoke; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2014,7 +2051,8 @@ interpret(Thread* t) code = findVirtualMethod(t, method, class_); goto invoke; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2150,11 +2188,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, longArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2179,11 +2219,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, longArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2413,7 +2455,8 @@ interpret(Thread* t) if (LIKELY(o)) { acquire(t, o); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2423,7 +2466,8 @@ interpret(Thread* t) if (LIKELY(o)) { release(t, o); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2441,7 +2485,8 @@ interpret(Thread* t) counts[i] = popInt(t); if (UNLIKELY(counts[i] < 0)) { object message = makeString(t, "%d", counts[i]); - exception = makeNegativeArraySizeException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } } @@ -2514,7 +2559,8 @@ interpret(Thread* t) pushObject(t, array); } else { object message = makeString(t, "%d", count); - exception = makeNegativeArraySizeException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } } goto loop; @@ -2576,7 +2622,8 @@ interpret(Thread* t) break; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } break; @@ -2587,7 +2634,8 @@ interpret(Thread* t) if (LIKELY(o)) { cast(o, fieldOffset(t, field)) = value; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } break; @@ -2597,7 +2645,8 @@ interpret(Thread* t) if (LIKELY(o)) { set(t, o, fieldOffset(t, field), value); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } break; @@ -2727,11 +2776,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, shortArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2749,11 +2800,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, shortArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -3195,7 +3248,8 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); return 0; } @@ -3220,7 +3274,8 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); return 0; } @@ -3244,7 +3299,8 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); return 0; } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index a7b7b0cb6f..532819b0d1 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -156,6 +156,49 @@ 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) + == arrayBody(t, t->m->types, 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)) + == arrayBody(t, t->m->types, Machine::ByteArrayType)) + { + ReleaseStringChars(t, s, chars); + } + + if ((-- t->criticalLevel) == 0) { + enter(t, Thread::IdleState); + } +} + jsize JNICALL GetStringUTFLength(Thread* t, jstring s) { @@ -186,6 +229,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) { @@ -206,9 +258,8 @@ NewString(Thread* t, const jchar* chars, jsize 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 makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size)); } jstring JNICALL @@ -218,15 +269,11 @@ NewStringUTF(Thread* t, const char* chars) ENTER(t, Thread::ActiveState); - 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); + object array = parseUtf8(t, chars, strlen(chars)); - return makeLocalReference(t, s); + return makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1)); } void @@ -240,6 +287,19 @@ replace(int a, int b, const char* in, int8_t* out) *out = 0; } +jclass JNICALL +DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, + jsize length) +{ + ENTER(t, Thread::ActiveState); + + object c = defineClass + (t, loader ? *loader : t->m->loader, + reinterpret_cast(buffer), length); + + return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); +} + jclass JNICALL FindClass(Thread* t, const char* name) { @@ -279,6 +339,20 @@ ThrowNew(Thread* t, jclass c, const char* message) return 0; } +jint JNICALL +Throw(Thread* t, jthrowable throwable) +{ + if (t->exception) { + return -1; + } + + ENTER(t, Thread::ActiveState); + + t->exception = *throwable; + + return 0; +} + void JNICALL DeleteLocalRef(Thread* t, jobject r) { @@ -329,6 +403,14 @@ IsInstanceOf(Thread* t, jobject o, jclass c) return instanceOf(t, jclassVmClass(t, *c), *o); } +jboolean JNICALL +IsAssignableFrom(Thread* t, jclass a, jclass b) +{ + ENTER(t, Thread::ActiveState); + + return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b)); +} + object findMethod(Thread* t, jclass c, const char* name, const char* spec) { @@ -362,7 +444,10 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec) ENTER(t, Thread::ActiveState); object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) { + printTrace(t, t->exception); + return 0; + } assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); @@ -1116,7 +1201,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 @@ -1222,6 +1307,12 @@ DeleteGlobalRef(Thread* t, jobject r) } } +jint JNICALL +EnsureLocalCapacity(Thread*, jint) +{ + return 0; +} + jthrowable JNICALL ExceptionOccurred(Thread* t) { @@ -1832,6 +1923,34 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint) } } +jint JNICALL +RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, + jint methodCount) +{ + ENTER(t, Thread::ActiveState); + + for (int i = 0; i < methodCount; ++i) { + if (methods[i].function) { + object method = findMethod(t, c, methods[i].name, methods[i].signature); + if (UNLIKELY(t->exception)) return -1; + + t->m->processor->registerNative(t, method, methods[i].function); + } + } + + return 0; +} + +jint JNICALL +UnregisterNatives(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + t->m->processor->unregisterNatives(t, *c); + + return 0; +} + jint JNICALL MonitorEnter(Thread* t, jobject o) { @@ -1948,14 +2067,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; #ifdef AVIAN_GNU envTable->NewDirectByteBuffer = vm::NewDirectByteBuffer; @@ -1969,6 +2094,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; @@ -2054,6 +2180,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; @@ -2103,6 +2230,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; @@ -2201,6 +2330,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) Heap* h = makeHeap(s, heapLimit); Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary); Processor* p = makeProcessor(s, h, true); + Classpath* c = makeClasspath(s, h); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); @@ -2212,11 +2342,14 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } *m = new (h->allocate(sizeof(Machine))) - Machine(s, h, f, p, properties, propertyCount); + Machine(s, h, f, p, c, properties, propertyCount); *t = p->makeThread(*m, 0, 0); enter(*t, Thread::ActiveState); + + c->boot(*t); + enter(*t, Thread::IdleState); return 0; diff --git a/src/machine.cpp b/src/machine.cpp index 0b4ddcb461..e1d2af8ec6 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -196,10 +196,12 @@ turnOffTheLights(Thread* t) System* s = m->system; Heap* h = m->heap; Processor* p = m->processor; + Classpath* c = m->classpath; Finder* f = m->finder; m->dispose(); h->disposeFixies(); + c->dispose(); p->dispose(); h->dispose(); f->dispose(); @@ -227,23 +229,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 +362,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; } @@ -793,8 +777,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); } @@ -1046,7 +1030,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 +1066,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; @@ -1392,14 +1375,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); } @@ -1549,7 +1547,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 @@ -1673,8 +1670,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); @@ -2079,8 +2075,8 @@ class HeapClient: public Heap::Client { namespace vm { Machine::Machine(System* system, Heap* heap, Finder* finder, - Processor* processor, const char** properties, - unsigned propertyCount): + Processor* processor, Classpath* classpath, + const char** properties, unsigned propertyCount): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient))) @@ -2088,6 +2084,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, heap(heap), finder(finder), processor(processor), + classpath(classpath), rootThread(0), exclusive(0), finalizeThread(0), @@ -2199,7 +2196,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): backupHeapIndex(0), useBackupHeap(false), waiting(false), - tracing(false) + tracing(false), + daemon(false) #ifdef VM_STRESS , stress(false) #endif // VM_STRESS @@ -2248,10 +2246,11 @@ Thread::init() m->jniMethodTable = makeVector(this, 0, 0); - m->nullPointerException = makeNullPointerException(this); + m->nullPointerException = m->classpath->makeThrowable + (this, Machine::NullPointerExceptionType); - m->arrayIndexOutOfBoundsException - = makeArrayIndexOutOfBoundsException(this, 0); + m->arrayIndexOutOfBoundsException = m->classpath->makeThrowable + (this, Machine::IndexOutOfBoundsExceptionType); m->localThread->set(this); } else { @@ -2262,7 +2261,7 @@ Thread::init() expect(this, m->system->success(m->system->make(&lock))); if (javaThread == 0) { - this->javaThread = makeJavaThread(this, parent); + this->javaThread = m->classpath->makeThread(this, parent); } threadPeer(this, javaThread) = reinterpret_cast(this); @@ -2365,6 +2364,7 @@ enter(Thread* t, Thread::State s) return; } + #ifdef USE_ATOMIC_OPERATIONS # define INCREMENT atomicIncrement # define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock) @@ -2408,6 +2408,24 @@ enter(Thread* t, Thread::State s) } break; case Thread::IdleState: + // The java.lang.Thread implementation may or may not notify the + // VM when the daemon field in the Java object changes, so we sync + // up the native field whenever the thread transitions to idle: + if (t->daemon != threadDaemon(t, t->javaThread)) { + ACQUIRE_LOCK; + + t->daemon = threadDaemon(t, t->javaThread); + + if (t->daemon) { + ++ t->m->daemonCount; + } else { + expect(t, t->m->daemonCount); + -- t->m->daemonCount; + } + + t->m->stateLock->notifyAll(t->systemThread); + } + if (t->state == Thread::ActiveState) { // fast path assert(t, t->m->activeCount > 0); @@ -2420,6 +2438,7 @@ enter(Thread* t, Thread::State s) t->m->stateLock->notifyAll(t->systemThread); } + break; } else { // fall through to slow path @@ -2692,91 +2711,98 @@ makeString(Thread* t, const char* format, ...) 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); + == arrayBody(t, t->m->types, 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)) { 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); + 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)) { 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 @@ -3118,7 +3144,8 @@ resolveSystemClass(Thread* t, object spec) 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); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassNotFoundExceptionType, message); } } @@ -3191,7 +3218,8 @@ resolveClass(Thread* t, object loader, object spec) byteArrayHash); } else if (t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeClassNotFoundException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassNotFoundExceptionType, message); } return class_; @@ -3216,7 +3244,8 @@ resolveMethod(Thread* t, object class_, const char* methodName, (t, "%s %s not found in %s", methodName, methodSpec, &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeNoSuchMethodError(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoSuchMethodErrorType, message); return 0; } else { return method; @@ -3246,7 +3275,8 @@ resolveField(Thread* t, object class_, const char* fieldName, (t, "%s %s not found in %s", fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeNoSuchFieldError(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoSuchFieldErrorType, message); return 0; } else { return field; @@ -3324,7 +3354,9 @@ preInitClass(Thread* t, object c) } else if (classVmFlags(t, c) & InitErrorFlag) { object message = makeString (t, "%s", &byteArrayBody(t, className(t, c), 0)); - t->exception = makeNoClassDefFoundError(t, message); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoClassDefFoundErrorType, message); } else { classVmFlags(t, c) |= InitFlag; return true; @@ -3341,7 +3373,9 @@ postInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (t->exception) { - t->exception = makeExceptionInInitializerError(t, t->exception); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception); + classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; } else { @@ -3412,7 +3446,7 @@ 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)) + Machine::Type errorType) { object originalClass = class_; @@ -3440,7 +3474,7 @@ findInHierarchy(Thread* t, object class_, object name, object spec, &byteArrayBody(t, name, 0), &byteArrayBody(t, spec, 0), &byteArrayBody(t, className(t, originalClass), 0)); - t->exception = makeError(t, message); + t->exception = t->m->classpath->makeThrowable(t, errorType, message); } return o; @@ -3596,7 +3630,7 @@ collect(Thread* t, Heap::CollectionType type) if (m->objectsToFinalize and m->finalizeThread == 0) { m->finalizeThread = m->processor->makeThread - (m, makeJavaThread(t, m->rootThread), m->rootThread); + (m, t->m->classpath->makeThread(t, m->rootThread), m->rootThread); if (not t->m->system->success (m->system->start(&(m->finalizeThread->runnable)))) @@ -3695,7 +3729,8 @@ void printTrace(Thread* t, object exception) { if (exception == 0) { - exception = makeNullPointerException(t, 0, makeTrace(t), 0); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } for (object e = exception; e; e = throwableCause(t, e)) { @@ -3738,6 +3773,10 @@ printTrace(Thread* t, object exception) fprintf(stderr, "(line %d)\n", line); } } + + if (e == throwableCause(t, e)) { + break; + } } } @@ -3792,17 +3831,6 @@ makeTrace(Thread* t, Thread* target) 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); - } -} - void runFinalizeThread(Thread* t) { @@ -3833,6 +3861,47 @@ 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 +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); + 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 c; +} + void noop() { } @@ -3857,7 +3926,7 @@ vmPrintTrace(Thread* t) int line = t->m->processor->lineNumber (t, walker->method(), walker->ip()); - fprintf(stderr, " at %s.%s ", class_, method); + fprintf(stderr, " at %s.%s (%x) ", class_, method, walker->ip()); switch (line) { case NativeLine: diff --git a/src/machine.h b/src/machine.h index b406a455ca..cc2394a757 100644 --- a/src/machine.h +++ b/src/machine.h @@ -97,7 +97,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 @@ -1151,6 +1150,8 @@ class Reference { unsigned count; }; +class Classpath; + class Machine { public: enum Type { @@ -1164,7 +1165,8 @@ class Machine { }; Machine(System* system, Heap* heap, Finder* finder, Processor* processor, - const char** properties, unsigned propertyCount); + Classpath* classpath, const char** properties, + unsigned propertyCount); ~Machine() { dispose(); @@ -1178,6 +1180,7 @@ class Machine { Heap* heap; Finder* finder; Processor* processor; + Classpath* classpath; Thread* rootThread; Thread* exclusive; Thread* finalizeThread; @@ -1371,11 +1374,45 @@ class Thread { bool useBackupHeap; bool waiting; bool tracing; -#ifdef VM_STRESS + bool daemon; bool stress; -#endif // VM_STRESS }; +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 object + makeThrowable + (Thread* t, Machine::Type type, object message = 0, object trace = 0, + object cause = 0) = 0; + + virtual void + boot(Thread* t) = 0; + + virtual void + dispose() = 0; +}; + +inline void +runJavaThread(Thread* t) +{ + t->m->classpath->runThread(t); +} + +Classpath* +makeClasspath(System* system, Allocator* allocator); + typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); inline object @@ -1731,160 +1768,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_)); @@ -1917,16 +1804,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); @@ -2159,6 +2073,9 @@ 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); @@ -2264,13 +2181,13 @@ findMethodInClass(Thread* t, object class_, object name, object spec) object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - object (*makeError)(Thread*, object)); + Machine::Type errorType); 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 @@ -2690,10 +2607,12 @@ wait(Thread* t, object o, int64_t milliseconds) bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { - t->exception = makeInterruptedException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::InterruptedExceptionType); } } else { - t->exception = makeIllegalMonitorStateException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalMonitorStateExceptionType); } if (DebugMonitors) { @@ -2722,7 +2641,8 @@ notify(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotify(t, m); } else { - t->exception = makeIllegalMonitorStateException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalMonitorStateExceptionType); } } @@ -2739,7 +2659,8 @@ notifyAll(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotifyAll(t, m); } else { - t->exception = makeIllegalMonitorStateException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalMonitorStateExceptionType); } } @@ -2756,6 +2677,7 @@ setDaemon(Thread* t, object thread, bool daemon) if ((threadDaemon(t, thread) != 0) != daemon) { threadDaemon(t, thread) = daemon; + t->daemon = daemon; if (daemon) { ++ t->m->daemonCount; @@ -2947,7 +2869,7 @@ 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)) @@ -2962,7 +2884,7 @@ resolve(Thread* t, object loader, object method, unsigned index, o = findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), - find, makeError); + find, errorType); if (UNLIKELY(t->exception)) return 0; set(t, codePool(t, methodCode(t, method)), @@ -2976,7 +2898,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 +2912,7 @@ inline object resolveMethod(Thread* t, object loader, object method, unsigned index) { return resolve(t, loader, method, index, findMethodInClass, - makeNoSuchMethodError); + Machine::NoSuchMethodErrorType); } inline object @@ -3004,6 +2926,8 @@ inline object getJClass(Thread* t, object c) { if (classAddendum(t, c) == 0) { + PROTECT(t, c); + ACQUIRE(t, t->m->classLock); object addendum = makeClassAddendum(t, 0, 0, 0, 0); @@ -3013,9 +2937,11 @@ getJClass(Thread* t, object c) object jclass = classAddendumClass(t, classAddendum(t, c)); if (jclass == 0) { + PROTECT(t, c); + ACQUIRE(t, t->m->classLock); - jclass = makeJclass(t, c); + jclass = t->m->classpath->makeJclass(t, c); set(t, classAddendum(t, c), ClassAddendumClass, jclass); } @@ -3023,6 +2949,29 @@ getJClass(Thread* t, object c) return jclass; } +inline object +primitiveClass(Thread* t, char name) +{ + switch (name) { + case 'B': return arrayBody(t, t->m->types, Machine::JbyteType); + case 'C': return arrayBody(t, t->m->types, Machine::JcharType); + case 'D': return arrayBody(t, t->m->types, Machine::JdoubleType); + case 'F': return arrayBody(t, t->m->types, Machine::JfloatType); + case 'I': return arrayBody(t, t->m->types, Machine::JintType); + case 'J': return arrayBody(t, t->m->types, Machine::JlongType); + case 'S': return arrayBody(t, t->m->types, Machine::JshortType); + case 'V': return arrayBody(t, t->m->types, Machine::JvoidType); + case 'Z': return arrayBody(t, t->m->types, Machine::JbooleanType); + default: + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalArgumentExceptionType); + return 0; + } +} + +object +defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); + void dumpHeap(Thread* t, FILE* out); diff --git a/src/posix.cpp b/src/posix.cpp index 0d34e2828a..a40d555334 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -755,7 +755,7 @@ class MySystem: public System { return 0; } else { -// fprintf(stderr, "dlerror: %s\n", dlerror()); + fprintf(stderr, "dlerror: %s\n", dlerror()); return 1; } } diff --git a/src/process.cpp b/src/process.cpp index e4897dcaf0..090d253170 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -207,18 +207,17 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, namespace vm { -void* +object resolveNativeMethod(Thread* t, object method) { void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3); if (p) { - methodVmFlags(t, method) |= FastNative; - return p; + return makeNative(t, p, true); } p = ::resolveNativeMethod(t, method, "Java_", 5, -1); if (p) { - return p; + return makeNative(t, p, false); } return 0; diff --git a/src/process.h b/src/process.h index 95da97cde8..ae1f2831fa 100644 --- a/src/process.h +++ b/src/process.h @@ -56,7 +56,7 @@ isSpecialMethod(Thread* t, object method, object class_) and isSuperclass(t, methodClass(t, method), class_); } -void* +object resolveNativeMethod(Thread* t, object method); inline void diff --git a/src/processor.h b/src/processor.h index 398b2d930b..8cff2b0782 100644 --- a/src/processor.h +++ b/src/processor.h @@ -153,6 +153,10 @@ class Processor { walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) = 0; + virtual void registerNative(Thread* t, object method, void* function) = 0; + + virtual void unregisterNatives(Thread* t, object c) = 0; + object invoke(Thread* t, object method, object this_, ...) { diff --git a/src/system.h b/src/system.h index fb3b85df80..a58d3bba73 100644 --- a/src/system.h +++ b/src/system.h @@ -87,7 +87,7 @@ 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; diff --git a/src/type-generator.cpp b/src/type-generator.cpp index fc0fb72061..0e8a6bc758 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -400,6 +400,8 @@ class Array : public Scalar { o->typeName = typeName; o->name = name; o->elementSize = elementSize; + o->noassert = false; + o->nogc = false; return o; } }; @@ -455,7 +457,7 @@ memberTypeName(Object* o) } } -const char* +const char*& memberName(Object* o) { switch (o->type) { @@ -987,8 +989,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 +1092,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 +1120,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 isNew ? member : 0; } else { return Scalar::make(t, declaration(spec, declarations), spec, string(car(cdr(p))), @@ -1120,7 +1157,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 +1350,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); } } @@ -1379,8 +1410,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); + } } } diff --git a/src/types.def b/src/types.def index 143252e352..bdf13bf0fb 100644 --- a/src/types.def +++ b/src/types.def @@ -3,7 +3,18 @@ (type class avian/VMClass (array void* vtable)) -(type jclass java/lang/Class) +(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)) @@ -22,6 +33,10 @@ (type classAddendum avian/ClassAddendum) +(type methodAddendum avian/MethodAddendum) + +(type fieldAddendum avian/FieldAddendum) + (type nativeMethodData (void* function) (uint16_t argumentTableSize) @@ -30,6 +45,10 @@ (type pointer (void* value)) +(type native + (void* function) + (uint8_t fast)) + (pod exceptionHandler (uint16_t start) (uint16_t end) @@ -142,15 +161,23 @@ (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 uint8_t interrupted) + (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) @@ -184,6 +211,8 @@ (type virtualMachineError java/lang/VirtualMachineError) +(type outOfMemoryError java/lang/OutOfMemoryError) + (type stackOverflowError java/lang/StackOverflowError) (type linkageError java/lang/LinkageError) @@ -221,9 +250,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/test/test.sh b/test/test.sh index 55b4ff54a6..786c9e24c0 100644 --- a/test/test.sh +++ b/test/test.sh @@ -4,6 +4,7 @@ log=build/log.txt vg="nice valgrind --leak-check=full --num-callers=32 \ --freelist-vol=100000000 --error-exitcode=1" +library_path=${1}; shift vm=${1}; shift mode=${1}; shift flags=${1}; shift @@ -18,10 +19,11 @@ for test in ${tests}; do case ${mode} in debug|debug-fast|fast|small ) - ${vm} ${flags} ${test} >>${log} 2>&1;; + LD_LIBRARY_PATH=${library_path} ${vm} ${flags} ${test} >>${log} 2>&1;; stress* ) - ${vg} ${vm} ${flags} ${test} >>${log} 2>&1;; + LD_LIBRARY_PATH=${library_path} ${vg} ${vm} ${flags} ${test} \ + >>${log} 2>&1;; * ) echo "unknown mode: ${mode}" >&2