From c9f9b039e660d2c1b2e3e72ffedc5c814c148480 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 26 Jul 2007 20:39:53 -0600 Subject: [PATCH] classpath progress --- classpath/java/io/File.java | 10 ++ classpath/java/io/FileInputStream.java | 3 +- classpath/java/io/FileNotFoundException.java | 11 ++ classpath/java/io/FileOutputStream.java | 3 +- classpath/java/lang/Boolean.java | 2 + classpath/java/lang/Byte.java | 2 + classpath/java/lang/Character.java | 22 +++ classpath/java/lang/Class.java | 141 +++++++++++++++++- classpath/java/lang/ClassLoader.java | 10 +- classpath/java/lang/Double.java | 2 + classpath/java/lang/Float.java | 2 + classpath/java/lang/Integer.java | 2 + classpath/java/lang/Long.java | 2 + .../java/lang/NegativeArraySizeException.java | 11 ++ classpath/java/lang/Runtime.java | 2 + classpath/java/lang/Short.java | 2 + classpath/java/lang/Throwable.java | 4 + classpath/java/lang/Void.java | 2 + classpath/java/lang/reflect/Array.java | 32 +++- classpath/java/lang/reflect/Constructor.java | 16 +- classpath/java/lang/reflect/Modifier.java | 7 + classpath/java/util/LinkedList.java | 38 +++++ src/builtin.cpp | 95 ++++++++++++ 23 files changed, 411 insertions(+), 10 deletions(-) create mode 100644 classpath/java/io/FileNotFoundException.java create mode 100644 classpath/java/lang/NegativeArraySizeException.java diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 1f6bbb51b0..baaad278f2 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -29,6 +29,16 @@ public class File { return path; } + private static native String toCanonicalPath(String path); + + public String getCanonicalPath() { + return toCanonicalPath(path); + } + + public File getCanonicalFile() { + return new File(getCanonicalPath()); + } + private static native String toAbsolutePath(String path); public String getAbsolutePath() { diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java index 992d959ca7..41b383fbfb 100644 --- a/classpath/java/io/FileInputStream.java +++ b/classpath/java/io/FileInputStream.java @@ -1,7 +1,7 @@ package java.io; public class FileInputStream extends InputStream { - private final int fd; + private int fd; public FileInputStream(FileDescriptor fd) { this.fd = fd.value; @@ -42,5 +42,6 @@ public class FileInputStream extends InputStream { public void close() throws IOException { close(fd); + fd = -1; } } diff --git a/classpath/java/io/FileNotFoundException.java b/classpath/java/io/FileNotFoundException.java new file mode 100644 index 0000000000..1e9bea2afb --- /dev/null +++ b/classpath/java/io/FileNotFoundException.java @@ -0,0 +1,11 @@ +package java.io; + +public class FileNotFoundException extends IOException { + public FileNotFoundException(String message) { + super(message); + } + + public FileNotFoundException() { + this(null); + } +} diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java index e2dda678da..11e31a2f41 100644 --- a/classpath/java/io/FileOutputStream.java +++ b/classpath/java/io/FileOutputStream.java @@ -1,7 +1,7 @@ package java.io; public class FileOutputStream extends OutputStream { - private final int fd; + private int fd; public FileOutputStream(FileDescriptor fd) { this.fd = fd.value; @@ -42,5 +42,6 @@ public class FileOutputStream extends OutputStream { public void close() throws IOException { close(fd); + fd = -1; } } diff --git a/classpath/java/lang/Boolean.java b/classpath/java/lang/Boolean.java index cfecde87ad..42c5d513b6 100644 --- a/classpath/java/lang/Boolean.java +++ b/classpath/java/lang/Boolean.java @@ -1,6 +1,8 @@ package java.lang; public final class Boolean { + public static final Class TYPE = Class.forName("Z"); + private final boolean value; public Boolean(boolean value) { diff --git a/classpath/java/lang/Byte.java b/classpath/java/lang/Byte.java index 0ace19db24..61a1f1d30a 100644 --- a/classpath/java/lang/Byte.java +++ b/classpath/java/lang/Byte.java @@ -1,6 +1,8 @@ package java.lang; public final class Byte extends Number { + public static final Class TYPE = Class.forName("B"); + private final byte value; public Byte(byte value) { diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java index 85df317dde..41b693a725 100644 --- a/classpath/java/lang/Character.java +++ b/classpath/java/lang/Character.java @@ -1,6 +1,8 @@ package java.lang; public final class Character { + public static final Class TYPE = Class.forName("C"); + private final char value; public Character(char value) { @@ -26,4 +28,24 @@ public final class Character { return c; } } + + public static boolean isDigit(char c) { + return c >= '0' && c <= '9'; + } + + public static boolean isLetter(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + public static boolean isLowerCase(char c) { + return (c >= 'a' && c <= 'z'); + } + + public static boolean isUpperCase(char c) { + return (c >= 'A' && c <= 'Z'); + } + + public static boolean isWhiteSpace(char c) { + return c == ' ' || c == '\t' || c == '\n'; + } } diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index e27bf654c9..c6ea1eeb18 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -1,5 +1,6 @@ package java.lang; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Field; @@ -29,13 +30,31 @@ public final class Class { public native boolean isAssignableFrom(Class c); - public Field getDeclaredField(String name) throws NoSuchFieldException { + private Field findField(String name) { for (int i = 0; i < fieldTable.length; ++i) { if (fieldTable[i].getName().equals(name)) { return fieldTable[i]; } } + return null; + } + public Field getDeclaredField(String name) throws NoSuchFieldException { + Field f = findField(name); + if (f == null) { + throw new NoSuchFieldException(name); + } else { + return f; + } + } + + public Field getField(String name) throws NoSuchFieldException { + for (Class c = this; c != null; c = c.super_) { + Field f = c.findField(name); + if (f != null) { + return f; + } + } throw new NoSuchFieldException(name); } @@ -52,9 +71,7 @@ public final class Class { } } - public Method getDeclaredMethod(String name, Class ... parameterTypes) - throws NoSuchMethodException - { + private Method findMethod(String name, Class[] parameterTypes) { for (int i = 0; i < methodTable.length; ++i) { if (methodTable[i].getName().equals(name) && match(parameterTypes, methodTable[i].getParameterTypes())) @@ -62,7 +79,123 @@ public final class Class { return methodTable[i]; } } + return null; + } + public Method getDeclaredMethod(String name, Class ... parameterTypes) + throws NoSuchMethodException + { + Method f = findMethod(name, parameterTypes); + if (f == null) { + throw new NoSuchMethodException(name); + } else { + return f; + } + } + + public Method getMethod(String name, Class ... parameterTypes) + throws NoSuchMethodException + { + for (Class c = this; c != null; c = c.super_) { + Method f = c.findMethod(name, parameterTypes); + if (f != null) { + return f; + } + } throw new NoSuchMethodException(name); } + + public Constructor getConstructor(Class ... parameterTypes) + throws NoSuchMethodException + { + return new Constructor(getDeclaredMethod("", parameterTypes)); + } + + public Constructor[] getConstructors() { + int count = 0; + for (int i = 0; i < methodTable.length; ++i) { + if (methodTable[i].getName().equals("")) { + ++ count; + } + } + + Constructor[] array = new Constructor[count]; + int index = 0; + for (int i = 0; i < methodTable.length; ++i) { + if (methodTable[i].getName().equals("")) { + array[index++] = new Constructor(methodTable[i]); + } + } + + return array; + } + + public Constructor[] getDeclaredConstructors() { + return getConstructors(); + } + + public Field[] getDeclaredFields() { + Field[] array = new Field[fieldTable.length]; + System.arraycopy(fieldTable, 0, array, 0, fieldTable.length); + return array; + } + + public Method[] getDeclaredMethods() { + int count = 0; + for (int i = 0; i < methodTable.length; ++i) { + if (! methodTable[i].getName().equals("")) { + ++ count; + } + } + + Method[] array = new Method[count]; + int index = 0; + for (int i = 0; i < methodTable.length; ++i) { + if (! methodTable[i].getName().equals("")) { + array[index++] = methodTable[i]; + } + } + + return array; + } + + public Class[] getInterfaces() { + Class[] array = new Class[interfaceTable.length / 2]; + for (int i = 0; i < array.length; ++i) { + array[i] = (Class) interfaceTable[i * 2]; + } + return array; + } + + public ClassLoader getClassLoader() { + return ClassLoader.getSystemClassLoader(); + } + + public int getModifiers() { + return flags; + } + + public Class getSuperclass() { + return super_; + } + + public boolean isArray() { + return arrayElementSize != 0; + } + + public boolean isInstance(Object o) { + return isAssignableFrom(o.getClass()); + } + + public boolean isPrimitive() { + return equals(boolean.class) + || equals(byte.class) + || equals(char.class) + || equals(short.class) + || equals(int.class) + || equals(long.class) + || equals(float.class) + || equals(double.class) + || equals(void.class); + } } diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index b9648d565c..426cc994c2 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -1,5 +1,11 @@ package java.lang; -public abstract class ClassLoader { - +public class ClassLoader { + private static final ClassLoader instance = new ClassLoader(); + + private ClassLoader() { } + + public static ClassLoader getSystemClassLoader() { + return instance; + } } diff --git a/classpath/java/lang/Double.java b/classpath/java/lang/Double.java index 2c8f388e76..0074ac7ea9 100644 --- a/classpath/java/lang/Double.java +++ b/classpath/java/lang/Double.java @@ -1,6 +1,8 @@ package java.lang; public final class Double { + public static final Class TYPE = Class.forName("D"); + private final double value; public Double(double value) { diff --git a/classpath/java/lang/Float.java b/classpath/java/lang/Float.java index 9c4aa3ffb2..265363ae64 100644 --- a/classpath/java/lang/Float.java +++ b/classpath/java/lang/Float.java @@ -1,6 +1,8 @@ package java.lang; public final class Float extends Number { + public static final Class TYPE = Class.forName("F"); + private final float value; public Float(float value) { diff --git a/classpath/java/lang/Integer.java b/classpath/java/lang/Integer.java index 2a98535024..3ce7ef1797 100644 --- a/classpath/java/lang/Integer.java +++ b/classpath/java/lang/Integer.java @@ -1,6 +1,8 @@ package java.lang; public final class Integer extends Number { + public static final Class TYPE = Class.forName("I"); + private final int value; public Integer(int value) { diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index 1fce98ec72..3e1c6e3786 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -1,6 +1,8 @@ package java.lang; public final class Long extends Number { + public static final Class TYPE = Class.forName("J"); + private final long value; public Long(long value) { diff --git a/classpath/java/lang/NegativeArraySizeException.java b/classpath/java/lang/NegativeArraySizeException.java new file mode 100644 index 0000000000..d1beb1b526 --- /dev/null +++ b/classpath/java/lang/NegativeArraySizeException.java @@ -0,0 +1,11 @@ +package java.lang; + +public class NegativeArraySizeException extends RuntimeException { + public NegativeArraySizeException(String message) { + super(message); + } + + public NegativeArraySizeException() { + super(); + } +} diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 94c220b7b1..0becbacf05 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -14,4 +14,6 @@ public class Runtime { public native void gc(); public native void exit(int code); + + public native long freeMemory(); } diff --git a/classpath/java/lang/Short.java b/classpath/java/lang/Short.java index b860feee6a..b4cdd36b64 100644 --- a/classpath/java/lang/Short.java +++ b/classpath/java/lang/Short.java @@ -1,6 +1,8 @@ package java.lang; public final class Short extends Number { + public static final Class TYPE = Class.forName("S"); + private final short value; public Short(short value) { diff --git a/classpath/java/lang/Throwable.java b/classpath/java/lang/Throwable.java index 40db7c1d7e..53ce5eac62 100644 --- a/classpath/java/lang/Throwable.java +++ b/classpath/java/lang/Throwable.java @@ -27,6 +27,10 @@ public class Throwable { return cause; } + public String getMessage() { + return message; + } + private static native Object trace(int skipCount); private static native StackTraceElement[] resolveTrace(Object trace); diff --git a/classpath/java/lang/Void.java b/classpath/java/lang/Void.java index b1400cbd7f..777241d48b 100644 --- a/classpath/java/lang/Void.java +++ b/classpath/java/lang/Void.java @@ -1,5 +1,7 @@ package java.lang; public final class Void { + public static final Class TYPE = Class.forName("V"); + private Void() { } } diff --git a/classpath/java/lang/reflect/Array.java b/classpath/java/lang/reflect/Array.java index e0eae6a055..01dc908b04 100644 --- a/classpath/java/lang/reflect/Array.java +++ b/classpath/java/lang/reflect/Array.java @@ -3,5 +3,35 @@ package java.lang.reflect; public final class Array { private Array() { } - + public static native Object get(Object array, int index); + + public static native int getLength(Object array); + + private static native Object makeObjectArray(Class elementType, int length); + + public static Object newInstance(Class elementType, int length) { + if (length < 0) { + throw new NegativeArraySizeException(); + } + + if (elementType.equals(boolean.class)) { + return new boolean[length]; + } else if (elementType.equals(byte.class)) { + return new byte[length]; + } else if (elementType.equals(char.class)) { + return new char[length]; + } else if (elementType.equals(short.class)) { + return new short[length]; + } else if (elementType.equals(int.class)) { + return new int[length]; + } else if (elementType.equals(long.class)) { + return new long[length]; + } else if (elementType.equals(float.class)) { + return new float[length]; + } else if (elementType.equals(double.class)) { + return new double[length]; + } else { + return makeObjectArray(elementType, length); + } + } } diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index c6eaf2c307..719eeb8af4 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -3,7 +3,9 @@ package java.lang.reflect; public class Constructor extends AccessibleObject implements Member { private Method method; - private Constructor() { } + public Constructor(Method method) { + this.method = method; + } public boolean equals(Object o) { return o instanceof Constructor @@ -22,6 +24,10 @@ public class Constructor extends AccessibleObject implements Member { return method.getDeclaringClass(); } + public Class[] getParameterTypes() { + return method.getParameterTypes(); + } + public int getModifiers() { return method.getModifiers(); } @@ -29,4 +35,12 @@ public class Constructor extends AccessibleObject implements Member { public String getName() { return method.getName(); } + + private static native T make(Class c); + + public T newInstance(Object ... arguments) { + T v = make(method.getDeclaringClass()); + method.invoke(v, arguments); + return v; + } } diff --git a/classpath/java/lang/reflect/Modifier.java b/classpath/java/lang/reflect/Modifier.java index 033bf0e464..2ee03cb651 100644 --- a/classpath/java/lang/reflect/Modifier.java +++ b/classpath/java/lang/reflect/Modifier.java @@ -16,4 +16,11 @@ public final class Modifier { public static final int STRICT = 1 << 11; private Modifier() { } + + public static boolean isPublic (int v) { return (v & PUBLIC) != 0; } + public static boolean isPrivate (int v) { return (v & PRIVATE) != 0; } + public static boolean isProtected(int v) { return (v & PROTECTED) != 0; } + public static boolean isStatic (int v) { return (v & STATIC) != 0; } + public static boolean isFinal (int v) { return (v & FINAL) != 0; } + public static boolean isSuper (int v) { return (v & SUPER) != 0; } } diff --git a/classpath/java/util/LinkedList.java b/classpath/java/util/LinkedList.java index 8894453282..8af680611e 100644 --- a/classpath/java/util/LinkedList.java +++ b/classpath/java/util/LinkedList.java @@ -92,12 +92,50 @@ public class LinkedList implements List { return find(index).value; } + public T getFirst() { + if (front != null) { + return front.value; + } else { + throw new NoSuchElementException(); + } + } + + public T getLast() { + if (rear != null) { + return rear.value; + } else { + throw new NoSuchElementException(); + } + } + public T remove(int index) { Cell c = find(index); remove(c); return c.value; } + public T removeFirst() { + if (front != null) { + T v = front.value; + front = front.next; + if (front != null) front.prev = null; + return v; + } else { + throw new NoSuchElementException(); + } + } + + public T removeLast() { + if (rear != null) { + T v = rear.value; + rear = rear.prev; + if (rear != null) rear.next = null; + return v; + } else { + throw new NoSuchElementException(); + } + } + public boolean remove(T element) { Cell c = find(element); if (c == null) { diff --git a/src/builtin.cpp b/src/builtin.cpp index 12991e84a0..6c895343f9 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -162,6 +162,12 @@ Field_get(Thread* t, jobject this_, jobject instancep) } } +jobject +Constructor_make(Thread* t, jclass, jclass c) +{ + return pushReference(t, make(t, c)); +} + jobject Method_invoke(Thread* t, jobject this_, jobject instancep, jobjectArray argumentsp) @@ -201,6 +207,78 @@ Method_invoke(Thread* t, jobject this_, jobject instancep, return 0; } +jobject +Array_get(Thread* t, jobject array, int index) +{ + if (LIKELY(array)) { + object a = *array; + unsigned elementSize = classArrayElementSize(t, objectClass(t, a)); + + if (LIKELY(elementSize)) { + intptr_t length = cast(a, BytesPerWord); + + if (LIKELY(index >= 0 and index < length)) { + switch (byteArrayBody(t, className(t, objectClass(t, a)), 1)) { + case 'B': + return pushReference(t, makeByte(t, byteArrayBody(t, a, index))); + case 'C': + return pushReference(t, makeChar(t, charArrayBody(t, a, index))); + case 'D': + return pushReference(t, makeDouble(t, doubleArrayBody(t, a, index))); + case 'F': + return pushReference(t, makeFloat(t, floatArrayBody(t, a, index))); + case 'I': + return pushReference(t, makeInt(t, intArrayBody(t, a, index))); + case 'J': + return pushReference(t, makeLong(t, longArrayBody(t, a, index))); + case 'S': + return pushReference(t, makeShort(t, shortArrayBody(t, a, index))); + case 'Z': + return pushReference + (t, makeBoolean(t, booleanArrayBody(t, a, index))); + case 'L': + case '[': + return pushReference(t, objectArrayBody(t, a, index)); + + default: abort(t); + } + } else { + t->exception = makeArrayIndexOutOfBoundsException(t, 0); + } + } else { + t->exception = makeIllegalArgumentException(t); + } + } else { + t->exception = makeNullPointerException(t); + } + + return 0; +} + +jint +Array_getLength(Thread* t, jobject array) +{ + if (LIKELY(array)) { + object a = *array; + unsigned elementSize = classArrayElementSize(t, objectClass(t, a)); + + if (LIKELY(elementSize)) { + return cast(a, BytesPerWord); + } else { + t->exception = makeIllegalArgumentException(t); + } + } else { + t->exception = makeNullPointerException(t); + } + return 0; +} + +jobject +Array_makeObjectArray(Thread* t, jclass, jclass elementType, jint length) +{ + return pushReference(t, makeObjectArray(t, *elementType, length, true)); +} + void System_arraycopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, jint dstOffset, jint length) @@ -289,6 +367,13 @@ Runtime_exit(Thread* t, jobject, jint code) t->vm->system->exit(code); } +jlong +Runtime_freeMemory(Thread*, jobject) +{ + // todo + return 0; +} + jobject Throwable_trace(Thread* t, jclass, jint skipCount) { @@ -458,6 +543,16 @@ populateBuiltinMap(Thread* t, object map) { "Java_java_lang_Object_wait", reinterpret_cast(::Object_wait) }, + { "Java_java_lang_reflect_Array_get", + reinterpret_cast(::Array_get) }, + { "Java_java_lang_reflect_Array_getLength", + reinterpret_cast(::Array_getLength) }, + { "Java_java_lang_reflect_Array_makeObjectArray", + reinterpret_cast(::Array_makeObjectArray) }, + + { "Java_java_lang_reflect_Constructor_make", + reinterpret_cast(::Constructor_make) }, + { "Java_java_lang_reflect_Field_get", reinterpret_cast(::Field_get) },