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