diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 9fbf2087bb..868c449062 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -67,7 +67,11 @@ doOpen(JNIEnv* e, const char* path, int mask) { int fd = OPEN(path, mask | OPEN_MASK, S_IRUSR | S_IWUSR); if (fd == -1) { - throwNew(e, "java/io/IOException", strerror(errno)); + if (errno == ENOENT) { + throwNew(e, "java/io/FileNotFoundException", strerror(errno)); + } else { + throwNew(e, "java/io/IOException", strerror(errno)); + } } return fd; } diff --git a/classpath/java/lang/Enum.java b/classpath/java/lang/Enum.java index b1c57ca925..81b0403da8 100644 --- a/classpath/java/lang/Enum.java +++ b/classpath/java/lang/Enum.java @@ -22,6 +22,10 @@ public abstract class Enum> implements Comparable { } public int compareTo(E other) { + if (getDeclaringClass() != other.getDeclaringClass()) { + throw new ClassCastException(); + } + return ordinal - other.ordinal; } diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 51f15006c7..efdedff039 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -59,6 +59,8 @@ public class Runtime { return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); } + public native void addShutdownHook(Thread t); + private static native void exec(String[] command, long[] process); private static native int exitValue(long pid); diff --git a/classpath/java/lang/StringBuffer.java b/classpath/java/lang/StringBuffer.java index beef64b68e..45528396fe 100644 --- a/classpath/java/lang/StringBuffer.java +++ b/classpath/java/lang/StringBuffer.java @@ -30,6 +30,16 @@ public class StringBuffer implements CharSequence { return this; } + public synchronized StringBuffer append(CharSequence s) { + sb.append(s); + return this; + } + + public synchronized StringBuffer append(StringBuffer s) { + sb.append(s); + return this; + } + public synchronized StringBuffer append(Object o) { sb.append(o); return this; diff --git a/classpath/java/lang/StringBuilder.java b/classpath/java/lang/StringBuilder.java index 0a322a5e69..d4e98571d7 100644 --- a/classpath/java/lang/StringBuilder.java +++ b/classpath/java/lang/StringBuilder.java @@ -54,6 +54,10 @@ public class StringBuilder implements CharSequence, Appendable { } } + public StringBuilder append(StringBuffer sb) { + return append(sb.toString()); + } + public StringBuilder append(CharSequence sequence) { return append(sequence.toString()); } @@ -104,7 +108,6 @@ public class StringBuilder implements CharSequence, Appendable { return append(String.valueOf(v)); } - public char charAt(int i) { if (i < 0 || i >= length) { throw new IndexOutOfBoundsException(); diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index e284c00df3..2e494c850c 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -252,10 +252,14 @@ public class Thread implements Runnable { return daemon; } - public void setDaemon(boolean v) { - daemon = v; + public synchronized void setDaemon(boolean v) { + if (v != daemon) { + setDaemon(this, v); + } } + private static native void setDaemon(Thread t, boolean increment); + public static native void yield(); public synchronized void join() throws InterruptedException { diff --git a/classpath/java/util/regex/Matcher.java b/classpath/java/util/regex/Matcher.java index 58af1a707d..2296b4bf9d 100644 --- a/classpath/java/util/regex/Matcher.java +++ b/classpath/java/util/regex/Matcher.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,17 +11,29 @@ package java.util.regex; /** - * This implementation is a skeleton, useful only for compilation. At runtime it - * is need to be replaced by a working implementation, for example one from the - * Apache Harmony project. - * - * @author zsombor + * This is a work in progress. * + * @author zsombor and others */ public class Matcher { + private final Pattern pattern; + private CharSequence input; + private int start; + private int end; + + Matcher(Pattern pattern, CharSequence input) { + this.pattern = pattern; + this.input = input; + } public boolean matches() { - throw new UnsupportedOperationException(); + if (pattern.pattern().equals(input.toString())) { + start = 0; + end = input.length(); + return true; + } else { + return false; + } } public boolean requireEnd() { @@ -37,15 +49,18 @@ public class Matcher { } public Matcher reset() { - throw new UnsupportedOperationException(); + return reset(input); } public Matcher reset(CharSequence input) { - throw new UnsupportedOperationException(); + this.input = input; + start = 0; + end = 0; + return this; } public int start() { - throw new UnsupportedOperationException(); + return start; } public int start(int group) { @@ -69,15 +84,44 @@ public class Matcher { } public String replaceAll(String replacement) { - throw new UnsupportedOperationException(); + return replace(replacement, Integer.MAX_VALUE); } public String replaceFirst(String replacement) { - throw new UnsupportedOperationException(); + return replace(replacement, 1); + } + + private String replace(String replacement, int limit) { + reset(); + + StringBuilder sb = null; + int index = 0; + int count = 0; + while (count < limit && index < input.length()) { + if (find(index)) { + if (sb == null) { + sb = new StringBuilder(); + } + if (start > index) { + sb.append(input.subSequence(index, start)); + } + sb.append(replacement); + index = end; + ++ count; + } else if (index == 0) { + return input.toString(); + } else { + break; + } + } + if (index < input.length()) { + sb.append(input.subSequence(index, input.length())); + } + return sb.toString(); } public int end() { - throw new UnsupportedOperationException(); + return end; } public int end(int group) { @@ -85,11 +129,19 @@ public class Matcher { } public boolean find() { - throw new UnsupportedOperationException(); + return find(end); } public boolean find(int start) { - throw new UnsupportedOperationException(); + String p = pattern.pattern(); + int i = Pattern.indexOf(input, p, start); + if (i >= 0) { + this.start = i; + this.end = i + p.length(); + return true; + } else { + return false; + } } public int groupCount() { diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java index 972f93de37..a3ec90c676 100644 --- a/classpath/java/util/regex/Pattern.java +++ b/classpath/java/util/regex/Pattern.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,12 +10,14 @@ package java.util.regex; +import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; + /** - * This implementation is a skeleton, useful only for compilation. At runtime it - * is need to be replaced by a working implementation, for example one from the - * Apache Harmony project. + * This is a work in progress. * - * @author zsombor + * @author zsombor and others * */ public class Pattern { @@ -29,12 +31,41 @@ public class Pattern { public static final int UNICODE_CASE = 64; public static final int CANON_EQ = 128; - private int patternFlags; - private String pattern; + private final int patternFlags; + private final String pattern; protected Pattern(String pattern, int flags) { this.pattern = pattern; this.patternFlags = flags; + + if (! trivial(pattern)) { + throw new UnsupportedOperationException + ("only trivial regular expressions are supported so far"); + } + } + + private static boolean trivial(String pattern) { + for (int i = 0; i < pattern.length(); ++i) { + char c = pattern.charAt(i); + switch (c) { + case '\\': + case '.': + case '*': + case '+': + case '?': + case '|': + case '[': + case ']': + case '{': + case '}': + case '(': + case ')': + case '^': + case '$': + return false; + } + } + return true; } public static Pattern compile(String regex) { @@ -50,7 +81,7 @@ public class Pattern { } public Matcher matcher(CharSequence input) { - throw new UnsupportedOperationException(); + return new Matcher(this, input); } public static boolean matches(String regex, CharSequence input) { @@ -66,10 +97,72 @@ public class Pattern { } public String[] split(CharSequence input) { - throw new UnsupportedOperationException(); + return split(input, 0); } public String[] split(CharSequence input, int limit) { - throw new UnsupportedOperationException(); + boolean strip; + if (limit < 0) { + strip = false; + limit = Integer.MAX_VALUE; + } else if (limit == 0) { + strip = true; + limit = Integer.MAX_VALUE; + } else { + strip = false; + } + + List list = new LinkedList(); + int index = 0; + int trailing = 0; + while (index < input.length() && list.size() < limit) { + int i = indexOf(input, pattern, index); + if (i >= 0) { + if (i == index) { + ++ trailing; + } else { + trailing = 0; + } + + list.add(input.subSequence(index, i)); + index = i + pattern.length(); + } else { + break; + } + } + + if (strip && index == input.length()) { + ++ trailing; + } else { + trailing = 0; + } + list.add(input.subSequence(index, input.length())); + + String[] result = new String[list.size() - trailing]; + int i = 0; + for (Iterator it = list.iterator(); + it.hasNext() && i < result.length; ++ i) + { + result[i] = it.next().toString(); + } + return result; + } + + static int indexOf(CharSequence haystack, CharSequence needle, int start) { + if (needle.length() == 0) return start; + + for (int i = start; i < haystack.length() - needle.length() + 1; ++i) { + int j = 0; + for (; j < needle.length(); ++j) { + if (haystack.charAt(i + j) != needle.charAt(j)) { + break; + } + } + if (j == needle.length()) { + return i; + } + } + + return -1; } } diff --git a/src/builtin.cpp b/src/builtin.cpp index 3a126a0312..a045d8d451 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -726,6 +726,8 @@ extern "C" JNIEXPORT void JNICALL Avian_java_lang_Runtime_exit (Thread* t, object, uintptr_t* arguments) { + shutDown(t); + t->m->system->exit(*arguments); } @@ -745,6 +747,18 @@ Avian_java_lang_Runtime_totalMemory 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) @@ -840,16 +854,8 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Thread_doStart (Thread* t, object, uintptr_t* arguments) { - object this_ = reinterpret_cast(*arguments); - - Thread* p = t->m->processor->makeThread(t->m, this_, t); - - if (t->m->system->success(t->m->system->start(&(p->runnable)))) { - return reinterpret_cast(p); - } else { - p->exit(); - return 0; - } + return reinterpret_cast + (startThread(t, reinterpret_cast(*arguments))); } extern "C" JNIEXPORT void JNICALL @@ -896,6 +902,27 @@ Avian_java_lang_Thread_enumerate 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; + + ACQUIRE_RAW(t, t->m->stateLock); + + threadDaemon(t, thread) = daemon; + + if (daemon) { + ++ t->m->daemonCount; + } else { + expect(t, t->m->daemonCount); + -- t->m->daemonCount; + } + + t->m->stateLock->notifyAll(t->systemThread); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength (Thread* t, object, uintptr_t* arguments) diff --git a/src/common.h b/src/common.h index 4896bd2201..21f2dce4a8 100644 --- a/src/common.h +++ b/src/common.h @@ -31,7 +31,7 @@ #if (defined __i386__) || (defined __POWERPC__) || (defined __arm__) # define LD "ld" -# ifdef __MINGW32__ +# if (defined __MINGW32__) && __GNUC__ == 4 # define LLD "I64d" # else # define LLD "lld" diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5195057e4a..11d4e42e34 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -25,37 +25,6 @@ const uintptr_t InterfaceMethodID const uintptr_t NonVirtualMethodID = (static_cast(1) << (BitsPerWord - 2)); -jint JNICALL -DestroyJavaVM(Machine* m) -{ - System* s = m->system; - Heap* h = m->heap; - Processor* p = m->processor; - Finder* f = m->finder; - Thread* t = m->rootThread; - - // wait for other threads to exit - { ACQUIRE(t, m->stateLock); - - while (m->liveCount > 1) { - t->m->stateLock->wait(t->systemThread, 0); - } - } - - int exitCode = (t->exception ? -1 : 0); - enter(t, Thread::ActiveState); - t->exit(); - - m->dispose(); - h->disposeFixies(); - p->dispose(); - h->dispose(); - f->dispose(); - s->dispose(); - - return exitCode; -} - jint JNICALL AttachCurrentThread(Machine* m, Thread** t, void*) { @@ -84,6 +53,9 @@ DetachCurrentThread(Machine* m) ACQUIRE_RAW(t, t->m->stateLock); enter(t, Thread::ActiveState); + + threadPeer(t, t->javaThread) = 0; + enter(t, Thread::ZombieState); t->state = Thread::JoinedState; @@ -94,6 +66,30 @@ DetachCurrentThread(Machine* m) } } +jint JNICALL +DestroyJavaVM(Machine* m) +{ + Thread* t; AttachCurrentThread(m, &t, 0); + + // wait for other non-daemon threads to exit + { ACQUIRE(t, t->m->stateLock); + while (t->m->liveCount - t->m->daemonCount > 1) { + t->m->stateLock->wait(t->systemThread, 0); + } + } + + { ENTER(t, Thread::ActiveState); + + shutDown(t); + } + + int exitCode = (t->exception ? -1 : 0); + + t->exit(); + + return exitCode; +} + jint JNICALL GetEnv(Machine* m, Thread** t, jint version) { @@ -431,7 +427,7 @@ CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? false : (intValue(t, r) != 0)); + return (r ? (intValue(t, r) != 0) : false); } jboolean JNICALL @@ -454,7 +450,7 @@ CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jbyte JNICALL @@ -477,7 +473,7 @@ CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jchar JNICALL @@ -500,7 +496,7 @@ CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jshort JNICALL @@ -523,7 +519,7 @@ CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jint JNICALL @@ -546,7 +542,7 @@ CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : longValue(t, r)); + return (r ? longValue(t, r) : 0); } jlong JNICALL @@ -569,7 +565,7 @@ CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : bitsToFloat(intValue(t, r))); + return (r ? bitsToFloat(intValue(t, r)) : 0); } jfloat JNICALL @@ -592,7 +588,7 @@ CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : bitsToDouble(longValue(t, r))); + return (r ? bitsToDouble(longValue(t, r)) : 0); } jdouble JNICALL @@ -666,7 +662,7 @@ CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : (intValue(t, r) != 0)); + return (r ? (intValue(t, r) != 0) : false); } jboolean JNICALL @@ -688,7 +684,7 @@ CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jbyte JNICALL @@ -710,7 +706,7 @@ CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jchar JNICALL @@ -732,7 +728,7 @@ CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jshort JNICALL @@ -754,7 +750,7 @@ CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jint JNICALL @@ -776,7 +772,7 @@ CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : longValue(t, r)); + return (r ? longValue(t, r) : 0); } jlong JNICALL @@ -798,7 +794,7 @@ CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : bitsToFloat(intValue(t, r))); + return (r ? bitsToFloat(intValue(t, r)) : 0); } jfloat JNICALL @@ -820,7 +816,7 @@ CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : bitsToDouble(longValue(t, r))); + return (r ? bitsToDouble(longValue(t, r)) : 0); } jdouble JNICALL diff --git a/src/machine.cpp b/src/machine.cpp index 1fa9791397..1c8e985548 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -146,6 +146,50 @@ disposeAll(Thread* m, Thread* o) dispose(m, o, false); } +void +turnOffTheLights(Thread* t) +{ + expect(t, t->m->liveCount == 1); + + joinAll(t, t->m->rootThread); + + enter(t, Thread::ExitState); + + for (object* p = &(t->m->finalizers); *p;) { + object f = *p; + *p = finalizerNext(t, *p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + function(t, finalizerTarget(t, f)); + } + + for (object* p = &(t->m->tenuredFinalizers); *p;) { + object f = *p; + *p = finalizerNext(t, *p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + function(t, finalizerTarget(t, f)); + } + + Machine* m = t->m; + + disposeAll(t, t->m->rootThread); + + System* s = m->system; + Heap* h = m->heap; + Processor* p = m->processor; + Finder* f = m->finder; + + m->dispose(); + h->disposeFixies(); + p->dispose(); + h->dispose(); + f->dispose(); + s->dispose(); +} + void killZombies(Thread* t, Thread* o) { @@ -574,6 +618,7 @@ resolveSpec(Thread* t, object loader, object spec, unsigned offset) } PROTECT(t, spec); + PROTECT(t, loader); unsigned length = s - &byteArrayBody(t, spec, offset); @@ -1976,12 +2021,14 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, propertyCount(propertyCount), activeCount(0), liveCount(0), + daemonCount(0), fixedFootprint(0), localThread(0), stateLock(0), heapLock(0), classLock(0), referenceLock(0), + shutdownLock(0), libraries(0), loader(0), loadClassMethod(0), @@ -1996,6 +2043,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, finalizeQueue(0), weakReferences(0), tenuredWeakReferences(0), + shutdownHooks(0), unsafe(false), triedBuiltinOnLoad(false), heapPoolIndex(0) @@ -2009,6 +2057,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or not system->success(system->make(&referenceLock)) or + not system->success(system->make(&shutdownLock)) or not system->success (system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) { @@ -2024,6 +2073,7 @@ Machine::dispose() heapLock->dispose(); classLock->dispose(); referenceLock->dispose(); + shutdownLock->dispose(); if (libraries) { libraries->disposeAll(); @@ -2150,8 +2200,9 @@ Thread::exit() enter(this, Thread::ExclusiveState); if (m->liveCount == 1) { - vm::exit(this); + turnOffTheLights(this); } else { + threadPeer(this, javaThread) = 0; enter(this, Thread::ZombieState); } } @@ -2170,31 +2221,41 @@ Thread::dispose() } void -exit(Thread* t) +shutDown(Thread* t) { - enter(t, Thread::ExitState); + ACQUIRE(t, t->m->shutdownLock); - joinAll(t, t->m->rootThread); + object hooks = t->m->shutdownHooks; + PROTECT(t, hooks); - for (object* p = &(t->m->finalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + t->m->shutdownHooks = 0; - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - function(t, finalizerTarget(t, f)); + object h = hooks; + PROTECT(t, h); + for (; h; h = pairSecond(t, h)) { + startThread(t, pairFirst(t, h)); } - for (object* p = &(t->m->tenuredFinalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + // wait for hooks to exit + h = hooks; + for (; h; h = pairSecond(t, h)) { + while (true) { + Thread* ht = reinterpret_cast(threadPeer(t, pairFirst(t, h))); - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - function(t, finalizerTarget(t, f)); + { ACQUIRE(t, t->m->stateLock); + + if (ht == 0 + or ht->state == Thread::ZombieState + or ht->state == Thread::JoinedState) + { + break; + } else { + ENTER(t, Thread::IdleState); + t->m->stateLock->wait(t->systemThread, 0); + } + } + } } - - disposeAll(t, t->m->rootThread); } void @@ -2255,6 +2316,10 @@ enter(Thread* t, Thread::State s) if (s == Thread::ZombieState) { assert(t, t->m->liveCount > 0); -- t->m->liveCount; + + if (threadDaemon(t, t->javaThread)) { + -- t->m->daemonCount; + } } t->state = s; @@ -2308,7 +2373,7 @@ enter(Thread* t, Thread::State s) t->state = s; - while (t->m->liveCount > 1) { + while (t->m->liveCount - t->m->daemonCount > 1) { t->m->stateLock->wait(t->systemThread, 0); } } break; @@ -3436,6 +3501,7 @@ visitRoots(Machine* m, Heap::Visitor* v) v->visit(&(m->byteArrayMap)); v->visit(&(m->types)); v->visit(&(m->jniMethodTable)); + v->visit(&(m->shutdownHooks)); for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); diff --git a/src/machine.h b/src/machine.h index 1539b80af0..078355dbe9 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1178,12 +1178,14 @@ class Machine { unsigned propertyCount; unsigned activeCount; unsigned liveCount; + unsigned daemonCount; unsigned fixedFootprint; System::Local* localThread; System::Monitor* stateLock; System::Monitor* heapLock; System::Monitor* classLock; System::Monitor* referenceLock; + System::Monitor* shutdownLock; System::Library* libraries; object loader; object loadClassMethod; @@ -1198,6 +1200,7 @@ class Machine { object finalizeQueue; object weakReferences; object tenuredWeakReferences; + object shutdownHooks; bool unsafe; bool triedBuiltinOnLoad; JavaVMVTable javaVMVTable; @@ -1394,6 +1397,9 @@ dispose(Thread* t, Reference* r) void collect(Thread* t, Heap::CollectionType type); +void +shutDown(Thread* t); + #ifdef VM_STRESS inline void @@ -1599,6 +1605,19 @@ setObjectClass(Thread*, object o, object value) | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); } +inline Thread* +startThread(Thread* t, object javaThread) +{ + Thread* p = t->m->processor->makeThread(t->m, javaThread, t); + + if (t->m->system->success(t->m->system->start(&(p->runnable)))) { + return p; + } else { + p->exit(); + return 0; + } +} + inline const char* findProperty(Machine* m, const char* name) { @@ -2341,9 +2360,6 @@ interrupt(Thread*, Thread* target) object intern(Thread* t, object s); -void -exit(Thread* t); - void walk(Thread* t, Heap::Walker* w, object o, unsigned start); diff --git a/test/Strings.java b/test/Strings.java index c84f93e996..9927ba2983 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -9,9 +9,20 @@ public class Strings { 115, 46, 83, 121, 109, 98, 111, 108 }) .equals("com.ecovate.nat.bus.Symbol")); - // We don't yet have a regex implementation, so this test will fail: -// final String months = "Jan\u00aeFeb\u00aeMar\u00ae"; -// expect(months.split("\u00ae").length == 3); + final String months = "Jan\u00aeFeb\u00aeMar\u00ae"; + expect(months.split("\u00ae").length == 3); + expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar.")); + + expect("foo_foofoo__foo".replaceAll("_", "__") + .equals("foo__foofoo____foo")); + + expect("foo_foofoo__foo".replaceFirst("_", "__") + .equals("foo__foofoo__foo")); + + expect("stereomime".matches("stereomime")); + expect(! "stereomime".matches("stereomim")); + expect(! "stereomime".matches("tereomime")); + expect(! "stereomime".matches("sterEomime")); StringBuilder sb = new StringBuilder(); sb.append('$');