diff --git a/classpath/java/lang/ArrayIndexOutOfBoundsException.java b/classpath/java/lang/ArrayIndexOutOfBoundsException.java index a2e8e4c634..7545661bb7 100644 --- a/classpath/java/lang/ArrayIndexOutOfBoundsException.java +++ b/classpath/java/lang/ArrayIndexOutOfBoundsException.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,7 +10,7 @@ package java.lang; -public class ArrayIndexOutOfBoundsException extends RuntimeException { +public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException { public ArrayIndexOutOfBoundsException(String message, Throwable cause) { super(message, cause); } diff --git a/classpath/java/lang/ClassNotFoundException.java b/classpath/java/lang/ClassNotFoundException.java index e2752a538a..1dfc694b06 100644 --- a/classpath/java/lang/ClassNotFoundException.java +++ b/classpath/java/lang/ClassNotFoundException.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -11,8 +11,11 @@ package java.lang; public class ClassNotFoundException extends Exception { + private final Throwable cause2; + public ClassNotFoundException(String message, Throwable cause) { super(message, cause); + cause2 = cause; } public ClassNotFoundException(String message) { diff --git a/classpath/java/lang/ExceptionInInitializerError.java b/classpath/java/lang/ExceptionInInitializerError.java index 912e43ba8d..9deea39355 100644 --- a/classpath/java/lang/ExceptionInInitializerError.java +++ b/classpath/java/lang/ExceptionInInitializerError.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -11,11 +11,14 @@ package java.lang; public class ExceptionInInitializerError extends Error { + private final Throwable cause2; + public ExceptionInInitializerError(String message) { super(message); + cause2 = null; } public ExceptionInInitializerError() { - super(); + this(null); } } diff --git a/classpath/java/lang/StackOverflowError.java b/classpath/java/lang/StackOverflowError.java index c5acc3fb6a..d8144b6666 100644 --- a/classpath/java/lang/StackOverflowError.java +++ b/classpath/java/lang/StackOverflowError.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,9 +10,9 @@ package java.lang; -public class StackOverflowError extends Error { +public class StackOverflowError extends VirtualMachineError { public StackOverflowError(String message) { - super(message, null); + super(message); } public StackOverflowError() { diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 731331051d..85a44023e2 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -15,14 +15,30 @@ import java.util.WeakHashMap; public class Thread implements Runnable { private long peer; + private boolean interrupted; + private boolean daemon; + private byte state; + private byte priority; private final Runnable task; private Map locals; - private boolean interrupted; private Object sleepLock; private ClassLoader classLoader; - private String name; + private UncaughtExceptionHandler exceptionHandler; - public Thread(Runnable task, String name) { + // package private for GNU Classpath, which inexpicably bypasses the + // accessor methods: + String name; + ThreadGroup group; + + private static UncaughtExceptionHandler defaultExceptionHandler; + + public static final int MIN_PRIORITY = 1; + public static final int NORM_PRIORITY = 5; + public static final int MAX_PRIORITY = 10; + + public Thread(ThreadGroup group, Runnable task, String name, long stackSize) + { + this.group = group; this.task = task; this.name = name; @@ -41,8 +57,28 @@ public class Thread implements Runnable { classLoader = current.classLoader; } + public Thread(ThreadGroup group, Runnable task, String name) { + this(group, task, name, 0); + } + + public Thread(ThreadGroup group, String name) { + this(null, null, name); + } + + public Thread(Runnable task, String name) { + this(null, task, name); + } + public Thread(Runnable task) { - this(task, "Thread["+task+"]"); + this(null, task, "Thread["+task+"]"); + } + + public Thread(String name) { + this(null, null, name); + } + + public Thread() { + this((Runnable) null); } public synchronized void start() { @@ -58,6 +94,28 @@ public class Thread implements Runnable { private native long doStart(); + private static void run(Thread t) throws Throwable { + t.state = (byte) State.RUNNABLE.ordinal(); + try { + t.run(); + } catch (Throwable e) { + UncaughtExceptionHandler eh = t.exceptionHandler; + UncaughtExceptionHandler deh = defaultExceptionHandler; + if (eh != null) { + eh.uncaughtException(t, e); + } else if (deh != null) { + deh.uncaughtException(t, e); + } else { + throw e; + } + } finally { + synchronized (t) { + t.state = (byte) State.TERMINATED.ordinal(); + t.notifyAll(); + } + } + } + public void run() { if (task != null) { task.run(); @@ -101,6 +159,10 @@ public class Thread implements Runnable { } } + public static boolean isInterrupted() { + return currentThread().interrupted; + } + public static void sleep(long milliseconds) throws InterruptedException { Thread t = currentThread(); if (t.sleepLock == null) { @@ -111,6 +173,16 @@ public class Thread implements Runnable { } } + public static void sleep(long milliseconds, int nanoseconds) + throws InterruptedException + { + if (nanoseconds > 0) { + ++ milliseconds; + } + + sleep(milliseconds); + } + public StackTraceElement[] getStackTrace() { return Throwable.resolveTrace(getStackTrace(peer)); } @@ -124,5 +196,126 @@ public class Thread implements Runnable { public String getName() { return name; } + + public void setName(String name) { + this.name = name; + } + + public UncaughtExceptionHandler getUncaughtExceptionHandler() { + UncaughtExceptionHandler eh = exceptionHandler; + return (eh == null ? group : eh); + } + + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() { + return defaultExceptionHandler; + } + + public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) { + exceptionHandler = h; + } + + public static void setDefaultUncaughtExceptionHandler + (UncaughtExceptionHandler h) + { + defaultExceptionHandler = h; + } + + public State getState() { + return State.values()[state]; + } + + public boolean isAlive() { + switch (getState()) { + case NEW: + case TERMINATED: + return false; + + default: + return true; + } + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) { + throw new IllegalArgumentException(); + } + this.priority = (byte) priority; + } + + public boolean isDaemon() { + return daemon; + } + + public void setDaemon(boolean v) { + daemon = v; + } + + public static native void yield(); + + public synchronized void join() throws InterruptedException { + while (getState() != State.TERMINATED) { + wait(); + } + } + + public synchronized void join(long milliseconds) throws InterruptedException + { + long then = System.currentTimeMillis(); + while (getState() != State.TERMINATED) { + wait(); + + if (System.currentTimeMillis() - then >= milliseconds) { + break; + } + } + } + + public void join(long milliseconds, int nanoseconds) + throws InterruptedException + { + if (nanoseconds > 0) { + ++ milliseconds; + } + + join(milliseconds); + } + + public ThreadGroup getThreadGroup() { + return group; + } + + public static native boolean holdsLock(Object o); + + public long getId() { + return peer; + } + + public void stop() { + throw new UnsupportedOperationException(); + } + + public void stop(Throwable t) { + throw new UnsupportedOperationException(); + } + + public void suspend() { + throw new UnsupportedOperationException(); + } + + public void resume() { + throw new UnsupportedOperationException(); + } + + public interface UncaughtExceptionHandler { + public void uncaughtException(Thread t, Throwable e); + } + + public enum State { + NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED + } } diff --git a/classpath/java/lang/ThreadDeath.java b/classpath/java/lang/ThreadDeath.java new file mode 100644 index 0000000000..167f6633dc --- /dev/null +++ b/classpath/java/lang/ThreadDeath.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class ThreadDeath extends Error { + public ThreadDeath() { } +} diff --git a/classpath/java/lang/ThreadGroup.java b/classpath/java/lang/ThreadGroup.java new file mode 100644 index 0000000000..9636b6a53a --- /dev/null +++ b/classpath/java/lang/ThreadGroup.java @@ -0,0 +1,35 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class ThreadGroup implements Thread.UncaughtExceptionHandler { + private final ThreadGroup parent; + private final String name; + + public ThreadGroup(ThreadGroup parent, String name) { + this.parent = parent; + this.name = name; + } + + public void uncaughtException(Thread t, Throwable e) { + if (parent != null) { + parent.uncaughtException(t, e); + } else { + Thread.UncaughtExceptionHandler deh + = Thread.getDefaultUncaughtExceptionHandler(); + if (deh != null) { + deh.uncaughtException(t, e); + } else if (! (e instanceof ThreadDeath)) { + e.printStackTrace(); + } + } + } +} diff --git a/classpath/java/lang/VirtualMachineError.java b/classpath/java/lang/VirtualMachineError.java new file mode 100644 index 0000000000..b59ebd41be --- /dev/null +++ b/classpath/java/lang/VirtualMachineError.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class VirtualMachineError extends Error { + public VirtualMachineError(String message) { + super(message); + } + + public VirtualMachineError() { + this(null); + } +} diff --git a/classpath/java/util/zip/ZipFile.java b/classpath/java/util/zip/ZipFile.java index a11a3c5dd1..d59885496f 100644 --- a/classpath/java/util/zip/ZipFile.java +++ b/classpath/java/util/zip/ZipFile.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -63,7 +63,7 @@ public class ZipFile { return index.size(); } - public Enumeration entries() { + public Enumeration entries() { return new MyEnumeration(window, index.values().iterator()); } diff --git a/makefile b/makefile index f9762c6938..2d00f61417 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -MAKEFLAGS = -s +#MAKEFLAGS = -s name = avian version = 0.2 @@ -328,11 +328,14 @@ gnu-blacklist = \ gnu-overrides = \ 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/StringBuffer.class \ java/lang/StringBuilder.class \ + java/lang/Thread.class \ + java/lang/ThreadLocal.class \ java/lang/Throwable.class \ java/lang/ref/PhantomReference.class \ java/lang/ref/Reference.class \ @@ -425,6 +428,16 @@ $(classpath-dep): $(classpath-sources) @mkdir -p $(classpath-build) $(javac) -d $(classpath-build) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) +ifdef gnu + (wd=$$(pwd); \ + cd $(classpath-build); \ + $(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \ + $(gnu-overrides) $$(find avian -name '*.class'); \ + rm -r *; \ + $(jar) xf $(gnu)/share/classpath/glibj.zip; \ + rm $(gnu-blacklist); \ + jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")") +endif @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -483,21 +496,9 @@ $(boot-object): $(boot-source) $(compile-object) $(build)/classpath.jar: $(classpath-dep) -ifdef gnu - mkdir $(build)/gnu - (wd=$$(pwd); \ - cd $(build)/gnu; \ - $(jar) xf $(gnu)/share/classpath/glibj.zip; \ - rm $(gnu-blacklist); \ - $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) - (wd=$$(pwd); \ - cd $(classpath-build); \ - $(jar) u0f "$$($(native-path) "$${wd}/$(@)")" $(gnu-overrides)) -else (wd=$$(pwd); \ cd $(classpath-build); \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) -endif $(binaryToMacho): $(src)/binaryToMacho.cpp $(cxx) $(^) -o $(@) diff --git a/src/gnu.cpp b/src/gnu.cpp index 7620fe18bf..3e443a275f 100644 --- a/src/gnu.cpp +++ b/src/gnu.cpp @@ -80,3 +80,59 @@ Avian_gnu_classpath_VMSystemProperties_preInit setProperty(t, method, properties, "user.home", getenv("HOME")); #endif } + +extern "C" JNIEXPORT int64_t JNICALL +Avian_gnu_classpath_VMStackWalker_getClassContext +(Thread* t, object, uintptr_t*) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t): + t(t), skipCount(1), trace(0), index(0), protector(t, &trace) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (skipCount == 0) { + if (trace == 0) { + trace = makeObjectArray + (t, arrayBody(t, t->m->types, Machine::ClassType), + walker->count()); + } + + assert(t, index < objectArrayLength(t, trace)); + + set(t, trace, ArrayBody + (index * BytesPerWord), + methodClass(t, walker->method())); + + ++ index; + return true; + } else { + -- skipCount; + return true; + } + } + + Thread* t; + unsigned skipCount; + object trace; + unsigned index; + Thread::SingleProtector protector; + } v(t); + + t->m->processor->walkStack(t, &v); + + if (v.trace == 0) { + v.trace = makeObjectArray + (t, arrayBody(t, t->m->types, Machine::ClassType), 0); + } + + return reinterpret_cast(v.trace); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_gnu_classpath_VMStackWalker_getClassLoader +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (classLoader(t, reinterpret_cast(arguments[0]))); +} diff --git a/src/machine.cpp b/src/machine.cpp index 9c8e167380..853cd29519 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1840,8 +1840,12 @@ Thread::init() if (javaThread) { threadPeer(this, javaThread) = reinterpret_cast(this); } else { + const unsigned NewState = 0; + const unsigned NormalPriority = 5; + this->javaThread = makeThread - (this, reinterpret_cast(this), 0, 0, 0, 0, m->loader, 0); + (this, reinterpret_cast(this), 0, 0, NewState, NormalPriority, + 0, 0, 0, m->loader, 0, 0, 0); } } @@ -2969,11 +2973,11 @@ makeTrace(Thread* t, Thread* target) void runJavaThread(Thread* t) { - object method = resolveMethod(t, "java/lang/Thread", "run", "()V"); + object method = resolveMethod + (t, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); + if (t->exception == 0) { - t->m->processor->invoke - (t, findMethod(t, method, objectClass(t, t->javaThread)), - t->javaThread); + t->m->processor->invoke (t, method, t->javaThread); } } diff --git a/src/machine.h b/src/machine.h index 9029811b05..a458557318 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1703,7 +1703,7 @@ makeClassNotFoundException(Thread* t, object message) { PROTECT(t, message); object trace = makeTrace(t); - return makeClassNotFoundException(t, message, trace, 0); + return makeClassNotFoundException(t, message, trace, 0, 0); } inline object @@ -1767,7 +1767,7 @@ makeExceptionInInitializerError(Thread* t, object cause) { PROTECT(t, cause); object trace = makeTrace(t); - return makeExceptionInInitializerError(t, 0, trace, cause); + return makeExceptionInInitializerError(t, 0, trace, cause, cause); } inline object diff --git a/src/types.def b/src/types.def index 98ad156f23..82ef783316 100644 --- a/src/types.def +++ b/src/types.def @@ -144,8 +144,9 @@ (type illegalMonitorStateException java/lang/IllegalMonitorStateException) -(type arrayIndexOutOfBoundsException - java/lang/ArrayIndexOutOfBoundsException) +(type indexOutOfBoundsException java/lang/IndexOutOfBoundsException) + +(type arrayIndexOutOfBoundsException java/lang/ArrayIndexOutOfBoundsException) (type arrayStoreException java/lang/ArrayStoreException) @@ -161,6 +162,8 @@ (type error java/lang/Error) +(type virtualMachineError java/lang/VirtualMachineError) + (type stackOverflowError java/lang/StackOverflowError) (type linkageError java/lang/LinkageError) diff --git a/test/Zip.java b/test/Zip.java index b18d5f1a0b..2aea1760f1 100644 --- a/test/Zip.java +++ b/test/Zip.java @@ -9,7 +9,9 @@ public class Zip { ZipFile file = new ZipFile("build/classpath.jar"); byte[] buffer = new byte[4096]; - for (Enumeration e = file.entries(); e.hasMoreElements();) { + for (Enumeration e = file.entries(); + e.hasMoreElements();) + { ZipEntry entry = e.nextElement(); InputStream in = file.getInputStream(entry); try {