diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 53ddd25a44..20a95cad01 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -1,7 +1,11 @@ package java.lang; +import java.util.Map; +import java.util.WeakHashMap; + public class Thread implements Runnable { private final Runnable task; + private Map locals; private long peer; public Thread(Runnable task) { @@ -16,6 +20,15 @@ public class Thread implements Runnable { } } + public Map locals() { + if (locals == null) { + locals = new WeakHashMap(); + } + return locals; + } + + public static native Thread currentThread(); + public static native void sleep(long milliseconds) throws InterruptedException; } diff --git a/classpath/java/lang/ThreadLocal.java b/classpath/java/lang/ThreadLocal.java new file mode 100644 index 0000000000..35003edb22 --- /dev/null +++ b/classpath/java/lang/ThreadLocal.java @@ -0,0 +1,36 @@ +package java.lang; + +import java.util.Map; + +public class ThreadLocal { + private static final Object Null = new Object(); + + protected T initialValue() { + return null; + } + + public T get() { + Map map = Thread.currentThread().locals(); + Object o = map.get(this); + if (o == null) { + o = initialValue(); + if (o == null) { + o = Null; + } + map.put(this, o); + } + if (o == Null) { + o = null; + } + return (T) o; + } + + public void set(T value) { + Map map = Thread.currentThread().locals(); + Object o = value; + if (o == null) { + o = Null; + } + map.put(this, o); + } +} diff --git a/classpath/java/lang/Throwable.java b/classpath/java/lang/Throwable.java index f81486d93c..40db7c1d7e 100644 --- a/classpath/java/lang/Throwable.java +++ b/classpath/java/lang/Throwable.java @@ -23,6 +23,10 @@ public class Throwable { this(null, null); } + public Throwable getCause() { + return cause; + } + private static native Object trace(int skipCount); private static native StackTraceElement[] resolveTrace(Object trace); diff --git a/classpath/java/lang/reflect/Array.java b/classpath/java/lang/reflect/Array.java new file mode 100644 index 0000000000..e0eae6a055 --- /dev/null +++ b/classpath/java/lang/reflect/Array.java @@ -0,0 +1,7 @@ +package java.lang.reflect; + +public final class Array { + private Array() { } + + +} diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index cba1ec9331..c6eaf2c307 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -1,6 +1,6 @@ package java.lang.reflect; -public class Constructor extends AccessibleObject { +public class Constructor extends AccessibleObject implements Member { private Method method; private Constructor() { } @@ -17,4 +17,16 @@ public class Constructor extends AccessibleObject { public void setAccessible(boolean v) { method.setAccessible(v); } + + public Class getDeclaringClass() { + return method.getDeclaringClass(); + } + + public int getModifiers() { + return method.getModifiers(); + } + + public String getName() { + return method.getName(); + } } diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 9fd11bf112..175f22f287 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -18,4 +18,16 @@ public class Field extends AccessibleObject { public void setAccessible(boolean v) { if (v) vmFlags |= Accessible; else vmFlags &= ~Accessible; } + + public Class getDeclaringClass() { + return class_; + } + + public int getModifiers() { + return flags; + } + + public String getName() { + return new String(name, 0, name.length - 1, false); + } } diff --git a/classpath/java/lang/reflect/InvocationTargetException.java b/classpath/java/lang/reflect/InvocationTargetException.java new file mode 100644 index 0000000000..a67d5c4357 --- /dev/null +++ b/classpath/java/lang/reflect/InvocationTargetException.java @@ -0,0 +1,19 @@ +package java.lang.reflect; + +public class InvocationTargetException extends Exception { + public InvocationTargetException(Throwable targetException, String message) { + super(message, targetException); + } + + public InvocationTargetException(Throwable targetException) { + this(targetException, null); + } + + public InvocationTargetException() { + this(null, null); + } + + public Throwable getTargetException() { + return getCause(); + } +} diff --git a/classpath/java/lang/reflect/Member.java b/classpath/java/lang/reflect/Member.java new file mode 100644 index 0000000000..2c0cd10384 --- /dev/null +++ b/classpath/java/lang/reflect/Member.java @@ -0,0 +1,12 @@ +package java.lang.reflect; + +public interface Member { + public static final int PUBLIC = 0; + public static final int DECLARED = 1; + + public Class getDeclaringClass(); + + public int getModifiers(); + + public String getName(); +} diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index 4d18a19a0a..236138d439 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -1,6 +1,6 @@ package java.lang.reflect; -public class Method extends AccessibleObject { +public class Method extends AccessibleObject implements Member { private byte vmFlags; private byte parameterCount; private short parameterFootprint; @@ -20,4 +20,16 @@ public class Method extends AccessibleObject { public void setAccessible(boolean v) { if (v) vmFlags |= Accessible; else vmFlags &= ~Accessible; } + + public Class getDeclaringClass() { + return class_; + } + + public int getModifiers() { + return flags; + } + + public String getName() { + return new String(name, 0, name.length - 1, false); + } } diff --git a/classpath/java/lang/reflect/Modifier.java b/classpath/java/lang/reflect/Modifier.java new file mode 100644 index 0000000000..033bf0e464 --- /dev/null +++ b/classpath/java/lang/reflect/Modifier.java @@ -0,0 +1,19 @@ +package java.lang.reflect; + +public final class Modifier { + public static final int PUBLIC = 1 << 0; + public static final int PRIVATE = 1 << 1; + public static final int PROTECTED = 1 << 2; + public static final int STATIC = 1 << 3; + public static final int FINAL = 1 << 4; + public static final int SUPER = 1 << 5; + public static final int SYNCHRONIZED = SUPER; + public static final int VOLATILE = 1 << 6; + public static final int TRANSIENT = 1 << 7; + public static final int NATIVE = 1 << 8; + public static final int INTERFACE = 1 << 9; + public static final int ABSTRACT = 1 << 10; + public static final int STRICT = 1 << 11; + + private Modifier() { } +} diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java new file mode 100644 index 0000000000..5eff151671 --- /dev/null +++ b/classpath/java/util/HashMap.java @@ -0,0 +1,220 @@ +package java.util; + +public class HashMap implements Map { + private int size; + private Cell[] array; + private Cell nullCell; + private final CellFactory factory; + + HashMap(int capacity, CellFactory factory) { + if (capacity > 0) { + array = new Cell[nextPowerOfTwo(capacity)]; + } + this.factory = factory; + } + + public HashMap(int capacity) { + this(capacity, new MyCellFactory()); + } + + public HashMap() { + this(0); + } + + private static int nextPowerOfTwo(int n) { + int r = 1; + while (r < n) r <<= 1; + return r; + } + + public int size() { + return size; + } + + private void resize() { + if (array == null || size >= array.length * 2) { + resize(array == null ? 16 : array.length * 2); + } else if (size <= array.length / 3) { + resize(array.length / 2); + } + } + + private void resize(int capacity) { + Cell[] newArray = null; + if (capacity != 0) { + capacity = nextPowerOfTwo(capacity); + if (array != null && array.length == capacity) { + return; + } + + newArray = new Cell[capacity]; + if (array != null) { + for (int i = 0; i < array.length; ++i) { + Cell next; + for (Cell c = array[i]; c != null; c = next) { + next = c.next(); + int index = c.getKey().hashCode() & (capacity - 1); + c.setNext(array[index]); + array[index] = c; + } + } + } + } + array = newArray; + } + + private Cell find(K key) { + if (key == null) { + return nullCell; + } else { + if (array != null) { + int index = key.hashCode() & (array.length - 1); + for (Cell c = array[index]; c != null; c = c.next()) { + if (key.equals(c.getKey())) { + return c; + } + } + } + + return null; + } + } + + private void insert(Cell cell) { + ++ size; + + if (cell.getKey() == null) { + nullCell = cell; + } else { + resize(); + + int index = cell.hashCode() & (array.length - 1); + cell.setNext(array[index]); + array[index] = cell; + } + } + + // primarily for use by WeakHashMap: + void remove(Cell cell) { + if (cell == nullCell) { + nullCell = null; + -- size; + } else { + int index = cell.hashCode() & (array.length - 1); + Cell p = null; + for (Cell c = array[index]; c != null; c = c.next()) { + if (c == cell) { + if (p == null) { + array[index] = c.next(); + } else { + p.setNext(c.next()); + } + -- size; + break; + } + } + + resize(); + } + } + + public V get(K key) { + Cell c = find(key); + return (c == null ? null : c.getValue()); + } + + public V put(K key, V value) { + Cell c = find(key); + if (c == null) { + insert(factory.make(key, value, null)); + return null; + } else { + V old = c.getValue(); + c.setValue(value); + return old; + } + } + + public V remove(K key) { + V old = null; + if (key == null) { + if (nullCell != null) { + old = nullCell.getValue(); + nullCell = null; + -- size; + } + } else { + if (array != null) { + int index = key.hashCode() & (array.length - 1); + Cell p = null; + for (Cell c = array[index]; c != null; c = c.next()) { + if (key.equals(c.getKey())) { + old = c.getValue(); + if (p == null) { + array[index] = c.next(); + } else { + p.setNext(c.next()); + } + -- size; + break; + } + } + + resize(); + } + } + return old; + } + + interface Cell extends Entry { + public HashMap.Cell next(); + + public void setNext(HashMap.Cell next); + } + + interface CellFactory { + public Cell make(K key, V value, Cell next); + } + + private static class MyCell implements Cell { + public final K key; + public V value; + public Cell next; + + public MyCell(K key, V value, Cell next) { + this.key = key; + this.value = value; + this.next = next; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + public HashMap.Cell next() { + return next; + } + + public void setNext(HashMap.Cell next) { + this.next = next; + } + + public int hashCode() { + return key.hashCode(); + } + } + + private static class MyCellFactory implements CellFactory { + public Cell make(K key, V value, Cell next) { + return new MyCell(key, value, next); + } + } +} diff --git a/classpath/java/util/Map.java b/classpath/java/util/Map.java new file mode 100644 index 0000000000..2be7083a45 --- /dev/null +++ b/classpath/java/util/Map.java @@ -0,0 +1,19 @@ +package java.util; + +public interface Map { + public int size(); + + public V get(K key); + + public V put(K key, V value); + + public V remove(K key); + + public interface Entry { + public K getKey(); + + public V getValue(); + + public void setValue(V value); + } +} diff --git a/classpath/java/util/WeakHashMap.java b/classpath/java/util/WeakHashMap.java new file mode 100644 index 0000000000..716ab340f8 --- /dev/null +++ b/classpath/java/util/WeakHashMap.java @@ -0,0 +1,95 @@ +package java.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +public class WeakHashMap implements Map { + private final HashMap map; + private final ReferenceQueue queue; + + public WeakHashMap(int capacity) { + map = new HashMap(capacity, new MyCellFactory()); + queue = new ReferenceQueue(); + } + + public WeakHashMap() { + this(0); + } + + private void poll() { + for (MyCell c = (MyCell) queue.poll(); + c != null; + c = (MyCell) queue.poll()) + { + map.remove(c); + } + } + + public int size() { + return map.size(); + } + + public V get(K key) { + poll(); + return map.get(key); + } + + public V put(K key, V value) { + poll(); + return map.put(key, value); + } + + public V remove(K key) { + poll(); + return map.remove(key); + } + + private static class MyCell + extends WeakReference + implements HashMap.Cell + { + public V value; + public HashMap.Cell next; + public int hashCode; + + public MyCell(K key, V value, HashMap.Cell next) { + super(key); + this.value = value; + this.next = next; + this.hashCode = key.hashCode(); + } + + public K getKey() { + return get(); + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + public HashMap.Cell next() { + return next; + } + + public void setNext(HashMap.Cell next) { + this.next = next; + } + + public int hashCode() { + return hashCode; + } + } + + private static class MyCellFactory + implements HashMap.CellFactory + { + public HashMap.Cell make(K key, V value, HashMap.Cell next) { + return new MyCell(key, value, next); + } + } +} diff --git a/src/builtin.cpp b/src/builtin.cpp index 5f8a9dd60d..89096d9ab9 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -41,6 +41,12 @@ notifyAll(Thread* t, jobject this_) vm::notifyAll(t, *this_); } +jobject +currentThread(Thread* t) +{ + return pushReference(t, t->javaThread); +} + void sleep(Thread* t, jlong milliseconds) { @@ -247,6 +253,8 @@ populate(Thread* t, object map) { "Java_java_lang_Thread_start", reinterpret_cast(start) }, + { "Java_java_lang_Thread_currentThread", + reinterpret_cast(currentThread) }, { "Java_java_lang_Thread_sleep", reinterpret_cast(sleep) }, diff --git a/src/common.h b/src/common.h index 76d6473a60..b7fd62dd16 100644 --- a/src/common.h +++ b/src/common.h @@ -1,8 +1,6 @@ #ifndef COMMON_H #define COMMON_H - - #include "stdint.h" #include "stdlib.h" #include "stdarg.h" @@ -29,8 +27,6 @@ inline void* operator new(size_t, void* p) throw() { return p; } - - namespace vm { typedef void* object; diff --git a/src/machine.cpp b/src/machine.cpp index ed08d9151b..e5268e293b 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1382,7 +1382,7 @@ Thread::Thread(Machine* m, Allocator* allocator, object javaThread, builtin::populate(t, m->builtinMap); - javaThread = makeThread(t, 0, reinterpret_cast(t)); + javaThread = makeThread(t, 0, 0, reinterpret_cast(t)); } else { threadPeer(this, javaThread) = reinterpret_cast(this); parent->child = this; @@ -1749,6 +1749,10 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), PROTECT(t, oldArray); unsigned newLength = nextPowerOfTwo(size); + if (oldArray and arrayLength(t, oldArray) == newLength) { + return; + } + newArray = makeArray(t, newLength, true); if (oldArray) { @@ -1832,6 +1836,7 @@ hashMapRemove(Thread* t, object map, object key, o = tripleSecond(t, *n); set(t, *n, tripleThird(t, *n)); -- hashMapSize(t, map); + break; } else { n = &tripleThird(t, *n); } diff --git a/src/types.def b/src/types.def index 8025a86036..cb2d124737 100644 --- a/src/types.def +++ b/src/types.def @@ -127,6 +127,7 @@ (type thread java/lang/Thread (extends jobject) (object task) + (object locals) (int64_t peer)) (type stackTraceElement java/lang/StackTraceElement